cargo-0.86.0/.cargo/config.toml000064400000000000000000000006541046102023000143320ustar 00000000000000[alias] build-man = "run --package xtask-build-man --" stale-label = "run --package xtask-stale-label --" bump-check = "run --package xtask-bump-check --" lint-docs = "run --package xtask-lint-docs --" [env] # HACK: Until this is stabilized, `snapbox`s polyfill could get confused # inside of the rust-lang/rust repo because it looks for the furthest-away `Cargo.toml` CARGO_RUSTC_CURRENT_DIR = { value = "", relative = true } cargo-0.86.0/.cargo_vcs_info.json0000644000000001360000000000100122220ustar { "git": { "sha1": "d73d2caf9e41a39daf2a8d6ce60ec80bf354d2a7" }, "path_in_vcs": "" }cargo-0.86.0/.github/ISSUE_TEMPLATE/bug_report.yml000064400000000000000000000022641046102023000174340ustar 00000000000000name: Bug Report description: Create a report to help us improve labels: ["C-bug", "S-triage"] body: - type: markdown attributes: value: Thanks for filing a πŸ› bug report πŸ˜„! - type: textarea id: problem attributes: label: Problem description: > Please provide a clear and concise description of what the bug is, including what currently happens and what you expected to happen. validations: required: true - type: textarea id: steps attributes: label: Steps description: Please list the steps to reproduce the bug. placeholder: | 1. 2. 3. - type: textarea id: possible-solutions attributes: label: Possible Solution(s) description: > Not obligatory, but suggest a fix/reason for the bug, or ideas how to implement the addition or change. - type: textarea id: notes attributes: label: Notes description: Provide any additional notes that might be helpful. - type: textarea id: version attributes: label: Version description: Please paste the output of running `cargo version --verbose`. render: text cargo-0.86.0/.github/ISSUE_TEMPLATE/config.yml000064400000000000000000000005671046102023000165350ustar 00000000000000contact_links: - name: Question url: https://users.rust-lang.org about: > Got a question about Cargo? Ask the community on the user forum. - name: Inspiring Idea url: https://internals.rust-lang.org/c/tools-and-infrastructure/cargo about: > Need more discussions with your next big idea? Reach out the coummunity on the internals forum. cargo-0.86.0/.github/ISSUE_TEMPLATE/feature_request.yml000064400000000000000000000025261046102023000204700ustar 00000000000000name: Feature Request description: Suggest an idea for enhancing Cargo labels: ["C-feature-request", "S-triage"] body: - type: markdown attributes: value: | Thanks for filing a πŸ™‹ feature request πŸ˜„! If the feature request is relatively small and already with a possible solution, this might be the place for you. If you are brewing a big feature that needs feedback from the community, [the internal forum] is the best fit, especially for pre-RFC. You can also talk the idea over with other developers in [#t-cargo Zulip stream]. [the internal forum]: https://internals.rust-lang.org/c/tools-and-infrastructure/cargo/15 [#t-cargo Zulip stream]: https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo - type: textarea id: problem attributes: label: Problem description: > Please provide a clear description of your use case and the problem this feature request is trying to solve. validations: required: true - type: textarea id: solution attributes: label: Proposed Solution description: > Please provide a clear and concise description of what you want to happen. - type: textarea id: notes attributes: label: Notes description: Provide any additional context or information that might be helpful. cargo-0.86.0/.github/ISSUE_TEMPLATE/tracking_issue.yml000064400000000000000000000042041046102023000202720ustar 00000000000000name: Tracking Issue description: A tracking issue for an accepted feature or RFC in Cargo. title: "Tracking Issue for _FEATURE_NAME_" labels: ["C-tracking-issue"] body: - type: markdown attributes: value: > Thank you for creating a tracking issue! Tracking issues are for tracking an accepted feature or RFC from implementation to stabilization. Please do not file a tracking issue until the feature or RFC has been approved. - type: textarea id: summary attributes: label: Summary description: Please provide a very brief summary of the feature. value: | RFC: [#NNNN](https://github.com/rust-lang/rfcs/pull/NNNN) Original issue: #NNNN Implementation: #NNNN Documentation: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#my-feature Please enter a short, one-sentence description here. validations: required: true - type: textarea id: unresolved attributes: label: Unresolved Issues description: List issues that have not yet been resolved. placeholder: | * [ ] Make a list of any known implementation or design issues. - type: textarea id: future attributes: label: Future Extensions description: > An optional section where you can mention where the feature may be extended in the future, but is explicitly not intended to address. - type: textarea id: about attributes: label: About tracking issues description: Please include this notice in the issue. value: | Tracking issues are used to record the overall progress of implementation. They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions. A tracking issue is however *not* meant for large scale discussion, questions, or bug reports about a feature. Instead, open a dedicated issue for the specific matter and add the relevant feature gate label. cargo-0.86.0/.github/PULL_REQUEST_TEMPLATE.md000064400000000000000000000030521046102023000161530ustar 00000000000000 cargo-0.86.0/.github/renovate.json5000064400000000000000000000047061046102023000151640ustar 00000000000000{ schedule: [ 'before 5am on the first day of the month', ], semanticCommits: 'enabled', configMigration: true, dependencyDashboard: true, ignorePaths: [ '**/tests/**', ], // See rust-lang/cargo#13546 and openssl/openssl#23376 for the exclusion ignoreDeps: ['openssl', 'openssl-src', 'openssl-sys'], customManagers: [ { customType: 'regex', fileMatch: [ 'Cargo.toml$', ], matchStrings: [ '\\bMSRV:1\\b.*?(?\\d+\\.\\d+(\\.\\d+)?)', '(?\\d+\\.\\d+(\\.\\d+)?).*?\\bMSRV:1\\b', ], depNameTemplate: 'MSRV:1', // Support 1 version of rustc packageNameTemplate: 'rust-lang/rust', datasourceTemplate: 'github-releases', }, { customType: 'regex', fileMatch: [ 'Cargo.toml$', ], matchStrings: [ '\\bMSRV:3\\b.*?(?\\d+\\.\\d+(\\.\\d+)?)', '(?\\d+\\.\\d+(\\.\\d+)?).*?\\bMSRV:3\\b', ], depNameTemplate: 'MSRV:3', // Support 3 versions of rustc packageNameTemplate: 'rust-lang/rust', datasourceTemplate: 'github-releases', }, ], packageRules: [ { commitMessageTopic: 'MSRV (1 version)', matchManagers: [ 'custom.regex', ], matchDepNames: [ 'MSRV:1', ], extractVersion: '^(?\\d+\\.\\d+)', // Drop the patch version schedule: [ '* * * * *', ], groupName: 'msrv', }, { commitMessageTopic: 'MSRV (3 versions)', matchManagers: [ 'custom.regex', ], matchDepNames: [ 'MSRV:3', ], extractVersion: '^(?\\d+\\.\\d+)', // Drop the patch version schedule: [ '* * * * *', ], minimumReleaseAge: '85 days', // 2 releases back * 6 weeks per release * 7 days per week + 1 internalChecksFilter: 'strict', groupName: 'msrv', }, // Goals: // - Rollup safe upgrades to reduce CI runner load // - Have lockfile and manifest in-sync (implicit rules) { matchManagers: [ 'cargo', ], matchCurrentVersion: '>=0.1.0', matchUpdateTypes: [ 'patch', ], automerge: false, groupName: 'compatible', }, { matchManagers: [ 'cargo', ], matchCurrentVersion: '>=1.0.0', matchUpdateTypes: [ 'minor', ], automerge: false, groupName: 'compatible', }, ], } cargo-0.86.0/.github/workflows/audit.yml000064400000000000000000000011601046102023000162360ustar 00000000000000name: Security audit permissions: contents: read on: pull_request: paths: - '**/Cargo.toml' - '**/Cargo.lock' push: branches: - master jobs: cargo_deny: runs-on: ubuntu-latest strategy: matrix: checks: - advisories - bans licenses sources steps: - uses: actions/checkout@v4 - uses: EmbarkStudios/cargo-deny-action@v2 # Prevent sudden announcement of a new advisory from failing ci: continue-on-error: ${{ matrix.checks == 'advisories' }} with: command: check ${{ matrix.checks }} rust-version: stable cargo-0.86.0/.github/workflows/contrib.yml000064400000000000000000000030161046102023000165720ustar 00000000000000name: Contrib Deploy on: push: branches: - master concurrency: cancel-in-progress: false group: "gh-pages" permissions: contents: read jobs: deploy: permissions: contents: write # for Git to git push runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install mdbook run: | mkdir mdbook curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.40/mdbook-v0.4.40-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook echo `pwd`/mdbook >> $GITHUB_PATH - name: Deploy docs run: | GENERATE_PY="$(pwd)/ci/generate.py" cd src/doc/contrib mdbook build # Override previous ref to avoid keeping history. git worktree add --orphan -B gh-pages gh-pages git config user.name "Deploy from CI" git config user.email "" cd gh-pages mv ../book contrib git add contrib # Generate HTML for link redirections. python3 "$GENERATE_PY" git add *.html # WARN: The CNAME file is for GitHub to redirect requests to the custom domain. # Missing this may entail security hazard and domain takeover. # See git add CNAME git commit -m "Deploy $GITHUB_SHA to gh-pages" git push origin +gh-pages cargo-0.86.0/.github/workflows/main.yml000064400000000000000000000221571046102023000160650ustar 00000000000000name: CI on: merge_group: pull_request: branches: - "**" defaults: run: shell: bash permissions: contents: read concurrency: group: "${{ github.workflow }}-${{ github.ref }}" cancel-in-progress: true jobs: conclusion: needs: - build_std - clippy - msrv - docs - lint-docs - lockfile - resolver - rustfmt - test - test_gitoxide permissions: contents: none # We need to ensure this job does *not* get skipped if its dependencies fail, # because a skipped job is considered a success by GitHub. So we have to # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run # when the workflow is canceled manually. # # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! if: ${{ !cancelled() }} runs-on: ubuntu-latest steps: # Manually check the status of all dependencies. `if: failure()` does not work. - name: Conclusion run: | # Print the dependent jobs to see them in the CI log jq -C <<< '${{ toJson(needs) }}' # Check if all jobs that we depend on (in the needs array) were successful. jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' # Check Code style quickly by running `rustfmt` over all code rustfmt: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: rustup update stable && rustup default stable - run: rustup component add rustfmt - run: cargo fmt --all --check # Ensure there are no clippy warnings clippy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: rustup update stable && rustup default stable - run: rustup component add clippy - run: cargo clippy --workspace --all-targets --no-deps -- -D warnings stale-label: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: rustup update stable && rustup default stable - run: cargo stale-label lint-docs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: rustup update stable && rustup default stable - run: cargo lint-docs --check # Ensure Cargo.lock is up-to-date lockfile: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: rustup update stable && rustup default stable - run: cargo update -p cargo --locked check-version-bump: runs-on: ubuntu-latest env: BASE_SHA: ${{ github.event.pull_request.base.sha }} HEAD_SHA: ${{ github.event.pull_request.head.sha != '' && github.event.pull_request.head.sha || github.sha }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - run: rustup update stable && rustup default stable - name: Install cargo-semver-checks run: | mkdir installed-bins curl -Lf https://github.com/obi1kenobi/cargo-semver-checks/releases/download/v0.36.0/cargo-semver-checks-x86_64-unknown-linux-gnu.tar.gz \ | tar -xz --directory=./installed-bins echo `pwd`/installed-bins >> $GITHUB_PATH - run: ci/validate-version-bump.sh test: runs-on: ${{ matrix.os }} env: CARGO_PROFILE_DEV_DEBUG: 1 CARGO_PROFILE_TEST_DEBUG: 1 CARGO_INCREMENTAL: 0 CARGO_PUBLIC_NETWORK_TESTS: 1 # Workaround for https://github.com/rust-lang/rustup/issues/3036 RUSTUP_WINDOWS_PATH_ADD_BIN: 0 strategy: matrix: include: - name: Linux x86_64 stable os: ubuntu-latest rust: stable other: i686-unknown-linux-gnu - name: Linux x86_64 beta os: ubuntu-latest rust: beta other: i686-unknown-linux-gnu - name: Linux x86_64 nightly os: ubuntu-latest rust: nightly other: i686-unknown-linux-gnu - name: macOS aarch64 stable os: macos-14 rust: stable other: x86_64-apple-darwin - name: macOS x86_64 nightly os: macos-13 rust: nightly other: x86_64-apple-ios - name: macOS aarch64 nightly os: macos-14 rust: nightly other: x86_64-apple-darwin - name: Windows x86_64 MSVC stable os: windows-latest rust: stable-msvc other: i686-pc-windows-msvc - name: Windows x86_64 gnu nightly # runs out of space while trying to link the test suite os: windows-latest rust: nightly-gnu other: i686-pc-windows-gnu name: Tests ${{ matrix.name }} steps: - uses: actions/checkout@v4 - name: Dump Environment run: ci/dump-environment.sh # Some tests require stable. Make sure it is set to the most recent stable # so that we can predictably handle updates if necessary (and not randomly # when GitHub updates its image). - run: rustup update --no-self-update stable - run: rustup update --no-self-update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} - run: rustup target add ${{ matrix.other }} - run: rustup target add aarch64-unknown-none # need this for build-std mock tests if: startsWith(matrix.rust, 'nightly') - run: rustup component add rustc-dev llvm-tools-preview rust-docs if: startsWith(matrix.rust, 'nightly') - run: sudo apt update -y && sudo apt install lldb gcc-multilib libsecret-1-0 libsecret-1-dev -y if: matrix.os == 'ubuntu-latest' - run: rustup component add rustfmt || echo "rustfmt not available" - name: Configure extra test environment run: echo CARGO_CONTAINER_TESTS=1 >> $GITHUB_ENV if: matrix.os == 'ubuntu-latest' - run: cargo test -p cargo - name: Clear intermediate test output run: ci/clean-test-output.sh - name: gitoxide tests (all git-related tests) run: cargo test -p cargo git env: __CARGO_USE_GITOXIDE_INSTEAD_OF_GIT2: 1 # The testsuite generates a huge amount of data, and fetch-smoke-test was # running out of disk space. - name: Clear test output run: ci/clean-test-output.sh # This only tests `cargo fix` because fix-proxy-mode is one of the most # complicated subprocess management in Cargo. - name: Check operability of rustc invocation with argfile run: 'cargo test -p cargo --test testsuite -- fix::' env: __CARGO_TEST_FORCE_ARGFILE: 1 - run: cargo test --workspace --exclude cargo --exclude benchsuite --exclude resolver-tests - name: Check benchmarks run: | # This only tests one benchmark since it can take over 10 minutes to # download all workspaces. cargo test -p benchsuite --all-targets -- cargo cargo check -p capture # The testsuite generates a huge amount of data, and fetch-smoke-test was # running out of disk space. - name: Clear benchmark output run: ci/clean-test-output.sh - name: Fetch smoke test run: ci/fetch-smoke-test.sh resolver: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: rustup update stable && rustup default stable - run: cargo test -p resolver-tests test_gitoxide: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: rustup update --no-self-update stable && rustup default stable - run: rustup target add i686-unknown-linux-gnu - run: sudo apt update -y && sudo apt install gcc-multilib libsecret-1-0 libsecret-1-dev -y - run: rustup component add rustfmt || echo "rustfmt not available" - run: cargo test -p cargo env: __CARGO_USE_GITOXIDE_INSTEAD_OF_GIT2: 1 build_std: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: rustup update nightly && rustup default nightly - run: rustup component add rust-src - run: cargo build - run: cargo test -p cargo --test build-std env: CARGO_RUN_BUILD_STD_TESTS: 1 docs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: rustup update nightly && rustup default nightly - run: rustup update stable - run: rustup component add rust-docs - run: ci/validate-man.sh # This requires rustfmt, use stable. - name: Run semver-check run: cargo +stable run -p semver-check - name: Ensure intradoc links are valid run: cargo doc --workspace --document-private-items --no-deps env: RUSTDOCFLAGS: -D warnings - name: Install mdbook run: | mkdir mdbook curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.40/mdbook-v0.4.40-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook echo `pwd`/mdbook >> $GITHUB_PATH - run: cd src/doc && mdbook build --dest-dir ../../target/doc - name: Run linkchecker.sh run: | cd target curl -sSLO https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/linkcheck.sh sh linkcheck.sh --all --path ../src/doc cargo msrv: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: taiki-e/install-action@cargo-hack - run: cargo hack check --all-targets --rust-version --workspace --ignore-private --locked cargo-0.86.0/.github/workflows/release.yml000064400000000000000000000014111046102023000165470ustar 00000000000000# Publish Cargo to crates.io whenever a new tag is pushed. Tags are pushed by # the Rust release process (https://github.com/rust-lang/promote-release), # which will cause this workflow to run. name: Release on: push: tags: - "0.*" # Prevent multiple releases from starting at the same time. concurrency: group: release jobs: crates-io: name: Publish on crates.io runs-on: ubuntu-latest permissions: contents: read # Gain access to the crates.io publishing token. environment: name: release steps: - name: Checkout the source code uses: actions/checkout@v4 - name: Publish Cargo to crates.io run: ./publish.py env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} cargo-0.86.0/.gitignore000064400000000000000000000002301046102023000127750ustar 00000000000000/target /Cargo.lock /config.stamp /Makefile /config.mk /src/doc/build /src/etc/*.pyc /src/registry/target rustc __pycache__ .idea/ .vscode/ *.iml *.swp cargo-0.86.0/.ignore000064400000000000000000000007721046102023000123040ustar 00000000000000# Output generated from src/doc/man # # The goal is to help people find the right file to edit src/doc/man/generated_txt src/doc/src/commands/* src/etc/man !src/doc/src/commands/build-commands.md !src/doc/src/commands/cargo-clippy.md !src/doc/src/commands/cargo-fmt.md !src/doc/src/commands/cargo-miri.md !src/doc/src/commands/general-commands.md !src/doc/src/commands/index.md !src/doc/src/commands/manifest-commands.md !src/doc/src/commands/package-commands.md !src/doc/src/commands/publishg-commands.md cargo-0.86.0/CHANGELOG.md000064400000000000000000011715231046102023000126350ustar 00000000000000# Changelog ## Cargo 1.85 (2025-02-20) [66221abd...rust-1.84.0](https://github.com/rust-lang/cargo/compare/66221abd...rust-1.84.0) ### Added - πŸŽ‰ Cargo now supports the 2024 edition. More information is available in the [edition guide](https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html). [#14828](https://github.com/rust-lang/cargo/pull/14828) ### Changed - Added a future-incompatibility warning for keywords in `cfg`s in Cargo.toml and Cargo configuration. `cfg`s with keywords like `cfg(true)` and `cfg(false)` were incorrectly accepted. For backward compatibility, support for raw identifiers has been introduced; for example, use `cfg(r#true)` instead. [#14671](https://github.com/rust-lang/cargo/pull/14671) ### Fixed - Set `GIT_DIR` to ensure compatibility with bare repositories for `net.git-fetch-with-cli=true`. [#14860](https://github.com/rust-lang/cargo/pull/14860) ### Nightly only - `-Zbuild-std`: Check if build target supports `std`. [#14183](https://github.com/rust-lang/cargo/pull/14183) - `-Zbuild-std`: always link to std when testing proc-macros. [#14850](https://github.com/rust-lang/cargo/pull/14850) [#14861](https://github.com/rust-lang/cargo/pull/14861) - `-Zpackage-workspace`: Allow dry-run of a non-bumped workspace. [#14847](https://github.com/rust-lang/cargo/pull/14847) - `-Zscript`: Allow adding/removing dependencies from cargo scripts [#14857](https://github.com/rust-lang/cargo/pull/14857) - `-Zscript`: Migrate cargo script manifests across editions [#14864](https://github.com/rust-lang/cargo/pull/14864) ### Documentation - Clarify how `cargo::metadata` env var is selected. [#14842](https://github.com/rust-lang/cargo/pull/14842) - cargo-info: Remove references to the default registry in `cargo-info` docs [#14880](https://github.com/rust-lang/cargo/pull/14880) ### Internal - cargo-test-support: `requires` attribute accepts string literals for cmds [#14875](https://github.com/rust-lang/cargo/pull/14875) - cargo-test-support: Switch from 'exec_with_output' to 'run' [#14848](https://github.com/rust-lang/cargo/pull/14848) - test: Verify `-Cmetadata` directly, not through `-Cextra-filename` [#14846](https://github.com/rust-lang/cargo/pull/14846) - test: ensure PGO works [#14859](https://github.com/rust-lang/cargo/pull/14859) [#14874](https://github.com/rust-lang/cargo/pull/14874) - Update dependencies. [#14867](https://github.com/rust-lang/cargo/pull/14867) [#14871](https://github.com/rust-lang/cargo/pull/14871) [#14878](https://github.com/rust-lang/cargo/pull/14878) [#14879](https://github.com/rust-lang/cargo/pull/14879) ## Cargo 1.84 (2025-01-09) [15fbd2f6...rust-1.84.0](https://github.com/rust-lang/cargo/compare/15fbd2f6...rust-1.84.0) ### Added - πŸŽ‰ Stabilize resolver v3, a.k.a the MSRV-aware dependency resolver. The stabilization includes `package.resolver = "3"` in Cargo.toml, and the `[resolver]` table in Cargo configuration. ([RFC 3537](https://github.com/rust-lang/rfcs/blob/master/text/3537-msrv-resolver.md)) ([manifest docs](https://doc.rust-lang.org/nightly/cargo/reference/resolver.html#resolver-versions)) ([config docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#resolver)) [#14639](https://github.com/rust-lang/cargo/pull/14639) [#14662](https://github.com/rust-lang/cargo/pull/14662) [#14711](https://github.com/rust-lang/cargo/pull/14711) [#14725](https://github.com/rust-lang/cargo/pull/14725) [#14748](https://github.com/rust-lang/cargo/pull/14748) [#14753](https://github.com/rust-lang/cargo/pull/14753) [#14754](https://github.com/rust-lang/cargo/pull/14754) - Added a new build script invocation `cargo::error=MESSAGE` to report error messages. ([docs](https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#cargo-error)) [#14743](https://github.com/rust-lang/cargo/pull/14743) ### Changed - ❗️ cargo-publish: Always include Cargo.lock in published crates. Originally it was only included for packages that have executables or examples for use with `cargo install`. [#14815](https://github.com/rust-lang/cargo/pull/14815) - Dependency resolver performance improvements, including shared caching, reduced iteration overhead, and removing redundant fetches and clones. [#14663](https://github.com/rust-lang/cargo/pull/14663) [#14690](https://github.com/rust-lang/cargo/pull/14690) [#14692](https://github.com/rust-lang/cargo/pull/14692) [#14694](https://github.com/rust-lang/cargo/pull/14694) - Deprecate `cargo verify-project`. [#14736](https://github.com/rust-lang/cargo/pull/14736) - Add source replacement info when no matching package found during dependency resolving. [#14715](https://github.com/rust-lang/cargo/pull/14715) - Hint for using `crates-io` when `[patch.crates.io]` found. [#14700](https://github.com/rust-lang/cargo/pull/14700) - Normalize source paths of Cargo targets for better diagnostics. [#14497](https://github.com/rust-lang/cargo/pull/14497) [#14750](https://github.com/rust-lang/cargo/pull/14750) - Allow registries to omit empty/default fields in index metadata JSON. Due to backward compatibility, crates.io continues to emit them. [#14838](https://github.com/rust-lang/cargo/pull/14838) [#14839](https://github.com/rust-lang/cargo/pull/14839) - cargo-doc: display env vars in extra verbose mode. [#14812](https://github.com/rust-lang/cargo/pull/14812) - cargo-fix: replace special-case handling of duplicate insert-only replacement. [#14765](https://github.com/rust-lang/cargo/pull/14765) [#14782](https://github.com/rust-lang/cargo/pull/14782) - cargo-remove: when a dependency is not found, try suggesting other dependencies with similar names. [#14818](https://github.com/rust-lang/cargo/pull/14818) - git: skip unnecessary submodule validations for fresh checkouts on Git dependencies. [#14605](https://github.com/rust-lang/cargo/pull/14605) - git: Enhanced the error message for fetching Git dependencies when refspec not found. [#14806](https://github.com/rust-lang/cargo/pull/14806) - git: Pass `--no-tags` by default to git CLI when `net.git-fetch-with-cli = true`. [#14688](https://github.com/rust-lang/cargo/pull/14688) ### Fixed - Fixed old Cargos failing to read the newer format of dep-info in build caches. [#14751](https://github.com/rust-lang/cargo/pull/14751) [#14745](https://github.com/rust-lang/cargo/pull/14745) - Fixed rebuild detection not respecting changes in the `[env]` table. [#14701](https://github.com/rust-lang/cargo/pull/14701) [#14730](https://github.com/rust-lang/cargo/pull/14730) - cargo-fix: Added transactional semantics to `rustfix` to keep code fix in a valid state when multiple suggestions contain overlapping spans. [#14747](https://github.com/rust-lang/cargo/pull/14747) ### Nightly only - The unstable environment variable `CARGO_RUSTC_CURRENT_DIR` has been removed. [#14799](https://github.com/rust-lang/cargo/pull/14799) - πŸ”₯ Cargo now includes an experimental JSON Schema file for `Cargo.toml` in the source code. It helps external tools validate or auto-complete the schema of the manifest. ([manifest.schema.json](https://github.com/rust-lang/cargo/blob/master/crates/cargo-util-schemas/manifest.schema.json)) [#14683](https://github.com/rust-lang/cargo/pull/14683) - πŸ”₯ `Zroot-dir`: A new unstable `-Zroot-dir` flag to configure the path from which rustc should be invoked. ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#root-dir)) [#14752](https://github.com/rust-lang/cargo/pull/14752) - πŸ”₯ `-Zwarnings`: A new unstable feature to control how Cargo handles warnings via the `build.warnings` configuration field. ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#warnings)) [#14388](https://github.com/rust-lang/cargo/pull/14388) [#14827](https://github.com/rust-lang/cargo/pull/14827) [#14836](https://github.com/rust-lang/cargo/pull/14836) - `edition2024`: Verify 2024 edition / resolver=3 doesn't affect resolution [#14724](https://github.com/rust-lang/cargo/pull/14724) - `native-completions`: Include descriptions in zsh [#14726](https://github.com/rust-lang/cargo/pull/14726) - `-Zbindeps`: Fix panic when running cargo tree on a package with a cross compiled bindep [#14593](https://github.com/rust-lang/cargo/pull/14593) - `-Zbindeps`: download targeted transitive deps of with artifact deps' target platform [#14723](https://github.com/rust-lang/cargo/pull/14723) - `-Zbuild-std`: Remove the requirement for `--target`. [#14317](https://github.com/rust-lang/cargo/pull/14317) - `-Zpackage-workspace`: Support package selection options, such as `--exclude`, in `cargo publish` [#14659](https://github.com/rust-lang/cargo/pull/14659) - `-Zscript`: Remove support for accepting `Cargo.toml`. [#14670](https://github.com/rust-lang/cargo/pull/14670) - `-Zscript`: Change config paths to only check `CARGO_HOME` [#14749](https://github.com/rust-lang/cargo/pull/14749) - `-Zscript`: Update the frontmatter parser for RFC 3503. [#14792](https://github.com/rust-lang/cargo/pull/14792) ### Documentation - Clarify the meaning of `--tests` and `--benches` flags. [#14675](https://github.com/rust-lang/cargo/pull/14675) - Clarify tools should only interpret messages with a line starting with `{` as JSON. [#14677](https://github.com/rust-lang/cargo/pull/14677) - Clarify what is and isn't included by `cargo package` [#14684](https://github.com/rust-lang/cargo/pull/14684) - Document official external commands: `cargo-clippy`, `cargo-fmt`, and `cargo-miri`. [#14669](https://github.com/rust-lang/cargo/pull/14669) [#14805](https://github.com/rust-lang/cargo/pull/14805) - Enhance documentation on environment variables [#14676](https://github.com/rust-lang/cargo/pull/14676) - Simplify English used in documentations. [#14825](https://github.com/rust-lang/cargo/pull/14825) [#14829](https://github.com/rust-lang/cargo/pull/14829) - A new doc page for deprecated and removed commands. [#14739](https://github.com/rust-lang/cargo/pull/14739) - cargo-test-support: Document `Execs` assertions based on port effort [#14793](https://github.com/rust-lang/cargo/pull/14793) ### Internal - πŸŽ‰ Migrate `build-rs` crate to the `rust-lang/cargo` repository as an intentional artifact of the Cargo team. [#14786](https://github.com/rust-lang/cargo/pull/14786) [#14817](https://github.com/rust-lang/cargo/pull/14817) - Enable transfer feature in triagebot [#14777](https://github.com/rust-lang/cargo/pull/14777) - clone-on-write when needed for InternedString [#14808](https://github.com/rust-lang/cargo/pull/14808) - ci: Switch CI from bors to merge queue [#14718](https://github.com/rust-lang/cargo/pull/14718) - ci: make the `lint-docs` job required [#14797](https://github.com/rust-lang/cargo/pull/14797) - ci: Check for clippy `correctness` [#14796](https://github.com/rust-lang/cargo/pull/14796) - ci: Switch matchPackageNames to matchDepNames for renovate [#14704](https://github.com/rust-lang/cargo/pull/14704) - fingerprint: Track the intent for each use of `UnitHash` [#14826](https://github.com/rust-lang/cargo/pull/14826) - fingerprint: Add more metadata to `rustc_fingerprint`. [#14761](https://github.com/rust-lang/cargo/pull/14761) - test: Migrate remaining snapshotting to snapbox [#14642](https://github.com/rust-lang/cargo/pull/14642) [#14760](https://github.com/rust-lang/cargo/pull/14760) [#14781](https://github.com/rust-lang/cargo/pull/14781) [#14785](https://github.com/rust-lang/cargo/pull/14785) [#14790](https://github.com/rust-lang/cargo/pull/14790) - Update dependencies. [#14668](https://github.com/rust-lang/cargo/pull/14668) [#14705](https://github.com/rust-lang/cargo/pull/14705) [#14762](https://github.com/rust-lang/cargo/pull/14762) [#14766](https://github.com/rust-lang/cargo/pull/14766) [#14772](https://github.com/rust-lang/cargo/pull/14772) ## Cargo 1.83 (2024-11-28) [8f40fc59...rust-1.83.0](https://github.com/rust-lang/cargo/compare/8f40fc59...rust-1.83.0) ### Added - `--timings` HTML output can now auto-switch between light and dark color schemes based on browser preference. [#14588](https://github.com/rust-lang/cargo/pull/14588) - Introduced a new `CARGO_MANIFEST_PATH` environment variable, similar to `CARGO_MANIFEST_DIR` but pointing directly to the manifest file. [#14404](https://github.com/rust-lang/cargo/pull/14404) - manifest: Added `package.autolib`, allowing `[lib]` auto-discovery to be disabled. [#14591](https://github.com/rust-lang/cargo/pull/14591) ### Changed - ❗️ Lockfile format v4 is now the default for creating/updating a lockfile. Rust toolchains 1.78+ support lockfile v4. For compatibility with earlier MSRV, consdier setting the `package.rust-version` to 1.82 or earlier. [#14595](https://github.com/rust-lang/cargo/pull/14595) - ❗️ cargo-package: When using the `--package` flag, only the specified packages are packaged. Previously, the package in the current working directory was automatically selected for packaging. [#14488](https://github.com/rust-lang/cargo/pull/14488) - cargo-publish: Now fails fast if the package version is already published. [#14448](https://github.com/rust-lang/cargo/pull/14448) - Improved error messages for missing features. [#14436](https://github.com/rust-lang/cargo/pull/14436) - Log details of `rustc` invocation failure if no errors are seen [#14453](https://github.com/rust-lang/cargo/pull/14453) - Uplifted `windows-gnullvm` import libraries, aligning them with `windows-gnu`. [#14451](https://github.com/rust-lang/cargo/pull/14451) - Suggest `cargo info` command in the `cargo search` result [#14537](https://github.com/rust-lang/cargo/pull/14537) - Enhanced dependency update status messages, now displaying updates (compatible, incompatible, direct-dep) in different colors, along with messages and MSRVs. [#14440](https://github.com/rust-lang/cargo/pull/14440) [#14457](https://github.com/rust-lang/cargo/pull/14457) [#14459](https://github.com/rust-lang/cargo/pull/14459) [#14461](https://github.com/rust-lang/cargo/pull/14461) [#14471](https://github.com/rust-lang/cargo/pull/14471) [#14568](https://github.com/rust-lang/cargo/pull/14568) - The `Locking` status message no longer displays workspace members. [#14445](https://github.com/rust-lang/cargo/pull/14445) ### Fixed - Prevented duplicate library search environment variables when calling `cargo` recursively. [#14464](https://github.com/rust-lang/cargo/pull/14464) - Don't double-warn about `$CARGO_HOME/config` not having `.toml` extension. [#14579](https://github.com/rust-lang/cargo/pull/14579) - Correct diagnostic count message when using `--message-format json`. [#14598](https://github.com/rust-lang/cargo/pull/14598) - cargo-add: Perform fuzzy searches when translating package names [#13765](https://github.com/rust-lang/cargo/pull/13765) - cargo-new: only auto-add new packages to the workspace relative to the manifest, rather than the current directory. [#14505](https://github.com/rust-lang/cargo/pull/14505) - cargo-rustc: Fixed parsing of comma-separated values in the `--crate-type` flag. [#14499](https://github.com/rust-lang/cargo/pull/14499) - cargo-vendor: trusts the crate version only when it originates from registries. This causes git dependencies to be re-vendored even if they haven't changed. [#14530](https://github.com/rust-lang/cargo/pull/14530) - cargo-publish: Downgrade version-exists error to warning on dry-run [#14742](https://github.com/rust-lang/cargo/pull/14742) [#14744](https://github.com/rust-lang/cargo/pull/14744) ### Nightly only - ❗️ cargo-rustc: give trailing flags higher precedence on nightly. The nightly gate will be removed after a few releases. Please give feedback if it breaks any workflow. A temporary environment variable `__CARGO_RUSTC_ORIG_ARGS_PRIO=1` is provided to opt-out of the behavior. [#14587](https://github.com/rust-lang/cargo/pull/14587) - πŸ”₯ cargo-install: a new `--dry-run` flag without actually installing binaries. [#14280](https://github.com/rust-lang/cargo/pull/14280) - πŸ”₯ `native-completions`: moves the handwritten shell completion scripts to Rust native, making it easier for us to add, extend, and test new completions. ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#native-completions)) [#14493](https://github.com/rust-lang/cargo/pull/14493) [#14531](https://github.com/rust-lang/cargo/pull/14531) [#14532](https://github.com/rust-lang/cargo/pull/14532) [#14533](https://github.com/rust-lang/cargo/pull/14533) [#14534](https://github.com/rust-lang/cargo/pull/14534) [#14535](https://github.com/rust-lang/cargo/pull/14535) [#14536](https://github.com/rust-lang/cargo/pull/14536) [#14546](https://github.com/rust-lang/cargo/pull/14546) [#14547](https://github.com/rust-lang/cargo/pull/14547) [#14548](https://github.com/rust-lang/cargo/pull/14548) [#14552](https://github.com/rust-lang/cargo/pull/14552) [#14557](https://github.com/rust-lang/cargo/pull/14557) [#14558](https://github.com/rust-lang/cargo/pull/14558) [#14563](https://github.com/rust-lang/cargo/pull/14563) [#14564](https://github.com/rust-lang/cargo/pull/14564) [#14573](https://github.com/rust-lang/cargo/pull/14573) [#14590](https://github.com/rust-lang/cargo/pull/14590) [#14592](https://github.com/rust-lang/cargo/pull/14592) [#14653](https://github.com/rust-lang/cargo/pull/14653) [#14656](https://github.com/rust-lang/cargo/pull/14656) - πŸ”₯ `-Zchecksum-freshness`: replace the use of file mtimes in cargo’s rebuild detection with a file checksum algorithm. This is most useful on systems with a poor mtime implementation, or in CI/CD. ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#checksum-freshness)) [#14137](https://github.com/rust-lang/cargo/pull/14137) - cargo-update: Add `matches_prerelease` semantic [#14305](https://github.com/rust-lang/cargo/pull/14305) - `build-plan`: document it as being deprecated. [#14657](https://github.com/rust-lang/cargo/pull/14657) - `edition2024`: Remove implicit feature removal from 2024 edition. [#14630](https://github.com/rust-lang/cargo/pull/14630) - `lockfile-path`: implies `--locked` on `cargo install`. [#14556](https://github.com/rust-lang/cargo/pull/14556) - `open-namespaces`: Allow open namespaces in `PackageIdSpec`s [#14467](https://github.com/rust-lang/cargo/pull/14467) - `path-bases`: `cargo [add|remove|update]` support [#14427](https://github.com/rust-lang/cargo/pull/14427) - `-Zmsrv-policy`: determine the workspace's MSRV by the most number of MSRVs within it. [#14569](https://github.com/rust-lang/cargo/pull/14569) - `-Zpackage-workspace`: allows to publish multiple crates in a workspace, even if they have inter-dependencies. ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#package-workspace)) [#14433](https://github.com/rust-lang/cargo/pull/14433) [#14496](https://github.com/rust-lang/cargo/pull/14496) - `-Zpublic-dependency`: Include public/private dependency status in `cargo metadata` [#14504](https://github.com/rust-lang/cargo/pull/14504) - `-Zpublic-dependency`: Don't require MSRV bump [#14507](https://github.com/rust-lang/cargo/pull/14507) ### Documentation - πŸŽ‰ New chapter about the uses, support expectations, and management of `package.rust-version` a.k.a MSRV. ([docs](https://doc.rust-lang.org/nightly/cargo/reference/rust-version.html)) [#14619](https://github.com/rust-lang/cargo/pull/14619) [#14636](https://github.com/rust-lang/cargo/pull/14636) - Clarify `target.'cfg(...)'` doesn't respect cfg from build script [#14312](https://github.com/rust-lang/cargo/pull/14312) - Clarify `[[bin]]` target auto-discovery can be `src/main.rs` and/or in `src/bin/` [#14515](https://github.com/rust-lang/cargo/pull/14515) - Disambiguate the use of 'target' in the feature resolver v2 doc. [#14540](https://github.com/rust-lang/cargo/pull/14540) - Make `--config ` more prominent [#14631](https://github.com/rust-lang/cargo/pull/14631) - Minor re-grouping of pages. [#14620](https://github.com/rust-lang/cargo/pull/14620) - contrib: Update docs for how cargo is published [#14539](https://github.com/rust-lang/cargo/pull/14539) - contrib: Declare support level for each crate in Cargo's Charter / crate docs [#14600](https://github.com/rust-lang/cargo/pull/14600) - contrib: Declare new Intentional Artifacts as 'small' changes [#14599](https://github.com/rust-lang/cargo/pull/14599) ### Internal - Cleanup duplicated check-cfg lint logic [#14567](https://github.com/rust-lang/cargo/pull/14567) - Fix elided lifetime due to nightly rustc changes [#14487](https://github.com/rust-lang/cargo/pull/14487) - Improved error reporting when a feature is not found in `activated_features`. [#14647](https://github.com/rust-lang/cargo/pull/14647) - cargo-info: Use the `shell.note` to print the note [#14554](https://github.com/rust-lang/cargo/pull/14554) - ci: bump CI tools [#14503](https://github.com/rust-lang/cargo/pull/14503) [#14628](https://github.com/rust-lang/cargo/pull/14628) - perf: zero-copy deserialization for compiler messages when possible [#14608](https://github.com/rust-lang/cargo/pull/14608) - resolver: Add more SAT resolver tests [#14583](https://github.com/rust-lang/cargo/pull/14583) [#14614](https://github.com/rust-lang/cargo/pull/14614) - test: Migrated more tests to snapbox [#14576](https://github.com/rust-lang/cargo/pull/14576) [#14577](https://github.com/rust-lang/cargo/pull/14577) - Update dependencies. [#14475](https://github.com/rust-lang/cargo/pull/14475) [#14478](https://github.com/rust-lang/cargo/pull/14478) [#14489](https://github.com/rust-lang/cargo/pull/14489) [#14607](https://github.com/rust-lang/cargo/pull/14607) [#14624](https://github.com/rust-lang/cargo/pull/14624) [#14632](https://github.com/rust-lang/cargo/pull/14632) ## Cargo 1.82 (2024-10-17) [a2b58c3d...rust-1.82.0](https://github.com/rust-lang/cargo/compare/a2b58c3d...rust-1.82.0) ### Added - πŸŽ‰ Added `cargo info` command for displaying information about a package. [docs](https://doc.rust-lang.org/nightly/cargo/commands/cargo-info.html) [#14141](https://github.com/rust-lang/cargo/pull/14141) [#14418](https://github.com/rust-lang/cargo/pull/14418) [#14430](https://github.com/rust-lang/cargo/pull/14430) ### Changed - ❗️ Doctest respects Cargo's color options by passing `--color` to rustdoc invocations. [#14425](https://github.com/rust-lang/cargo/pull/14425) - Improved error message for missing both `[package]` and `[workspace]` in Cargo.toml. [#14261](https://github.com/rust-lang/cargo/pull/14261) - Enumerate all possible values of `profile.*.debug` for the error message. [#14413](https://github.com/rust-lang/cargo/pull/14413) ### Fixed - Use longhand gitoxide path-spec patterns. Previously the implementation used shorthand pathspecs, which could produce invalid syntax, for example, if the path to the manifest file contained a leading `_` underscore [#14380](https://github.com/rust-lang/cargo/pull/14380) - cargo-package: fix failures on bare commit git repo. [#14359](https://github.com/rust-lang/cargo/pull/14359) - cargo-publish: Don't strip non-dev features for renamed dependencies from the HTTP JSON body sent to the registry. The bug only affected third-party registries. [#14325](https://github.com/rust-lang/cargo/pull/14325) [#14327](https://github.com/rust-lang/cargo/pull/14327) - cargo-vendor: don't copy source files of excluded Cargo targets when vendoring. [#14367](https://github.com/rust-lang/cargo/pull/14367) ### Nightly only - πŸ”₯ `lockfile-path`: Added `--lockfile-path` flag that allows specifying a path to the lockfile other than the default path `/Cargo.lock`. ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#lockfile-path)) [#14326](https://github.com/rust-lang/cargo/pull/14326) [#14417](https://github.com/rust-lang/cargo/pull/14417) [#14423](https://github.com/rust-lang/cargo/pull/14423) [#14424](https://github.com/rust-lang/cargo/pull/14424) - πŸ”₯ `path-bases`: Introduced a table of path "bases" in Cargo configuration files that can be used to prefix the paths of path dependencies and patch entries. ([RFC 3529](https://github.com/rust-lang/rfcs/blob/master/text/3529-cargo-path-bases.md)) ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#path-bases)) [#14360](https://github.com/rust-lang/cargo/pull/14360) - πŸ”₯ `-Zpackage-workspace`: Enhanced the experience of `cargo package --workspace` when there are dependencies between crates in the workspace. Crates in a workspace are no longer required to publish to actual registries. This is a step toward supporting `cargo publish --workspace`. [#13947](https://github.com/rust-lang/cargo/pull/13947) [#14408](https://github.com/rust-lang/cargo/pull/14408) [#14340](https://github.com/rust-lang/cargo/pull/14340) - cargo-update: Limit pre-release match semantics to use only on `OptVersionReq::Req` [#14412](https://github.com/rust-lang/cargo/pull/14412) - `edition2024`: Revert "fix: Ensure dep/feature activates the dependency on 2024". [#14295](https://github.com/rust-lang/cargo/pull/14295) - `update-breaking`: Improved error message when `update --breaking` has an invalid spec [#14279](https://github.com/rust-lang/cargo/pull/14279) - `update-breaking`: Don’t downgrade on prerelease `VersionReq` when updating with `--breaking` [#14250](https://github.com/rust-lang/cargo/pull/14250) - `-Zbuild-std`: remove hack on creating virtual std workspace [#14358](https://github.com/rust-lang/cargo/pull/14358) [#14370](https://github.com/rust-lang/cargo/pull/14370) - `-Zmsrv-policy`: Adjust MSRV resolve config field name / values. The previous placeholder `resolver.something-like-precedence` is now renamed to `resolver.incompatible-rust-versions`. [#14296](https://github.com/rust-lang/cargo/pull/14296) - `-Zmsrv-policy`: : Report when incompatible-rust-version packages are selected [#14401](https://github.com/rust-lang/cargo/pull/14401) - `-Ztarget-applies-to-host`: Fixed passing of links-overrides with target-applies-to-host and an implicit target [#14205](https://github.com/rust-lang/cargo/pull/14205) - `-Ztarget-applies-to-host`: `-Cmetadata` includes whether extra rustflags is same as host [#14432](https://github.com/rust-lang/cargo/pull/14432) - `-Ztrim-paths`: rustdoc supports trim-paths for diagnostics [#14389](https://github.com/rust-lang/cargo/pull/14389) ### Documentation - Convert comments to doc comments for `Workspace`. [#14397](https://github.com/rust-lang/cargo/pull/14397) - Fix MSRV indicator for `workspace.package` and `workspace.dependencies`. [#14400](https://github.com/rust-lang/cargo/pull/14400) - FAQ: remove outdated Cargo offline usage section. [#14336](https://github.com/rust-lang/cargo/pull/14336) ### Internal - Enhanced `cargo-test-support` usability and documentation. [#14266](https://github.com/rust-lang/cargo/pull/14266) [#14268](https://github.com/rust-lang/cargo/pull/14268) [#14269](https://github.com/rust-lang/cargo/pull/14269) [#14270](https://github.com/rust-lang/cargo/pull/14270) [#14272](https://github.com/rust-lang/cargo/pull/14272) - Made summary sync by using Arc instead of Rc [#14260](https://github.com/rust-lang/cargo/pull/14260) - Used `Rc` instead of `Arc` for storing rustflags [#14273](https://github.com/rust-lang/cargo/pull/14273) - Removed rustc probe for `--check-cfg` support [#14302](https://github.com/rust-lang/cargo/pull/14302) - Renamed 'resolved' to 'normalized' for all manifest normalization related items. [#14342](https://github.com/rust-lang/cargo/pull/14342) - cargo-util-schemas: Added `TomlPackage::new`, `Default` for `TomlWorkspace` [#14271](https://github.com/rust-lang/cargo/pull/14271) - ci: Switch macos aarch64 to nightly [#14382](https://github.com/rust-lang/cargo/pull/14382) - mdman: Normalize newlines when rendering options [#14428](https://github.com/rust-lang/cargo/pull/14428) - perf: dont call wrap in a no-op `source_id::with*` [#14318](https://github.com/rust-lang/cargo/pull/14318) - test: Migrated more tests to snapbox [#14242](https://github.com/rust-lang/cargo/pull/14242) [#14244](https://github.com/rust-lang/cargo/pull/14244) [#14293](https://github.com/rust-lang/cargo/pull/14293) [#14297](https://github.com/rust-lang/cargo/pull/14297) [#14319](https://github.com/rust-lang/cargo/pull/14319) [#14402](https://github.com/rust-lang/cargo/pull/14402) [#14410](https://github.com/rust-lang/cargo/pull/14410) - test: don't rely on absence of `RUST_BACKTRACE` [#14441](https://github.com/rust-lang/cargo/pull/14441) - test: Use gmake on AIX [#14323](https://github.com/rust-lang/cargo/pull/14323) - Updated to `gix` 0.64.0 [#14332](https://github.com/rust-lang/cargo/pull/14332) - Updated to `rusqlite` 0.32.0 [#14334](https://github.com/rust-lang/cargo/pull/14334) - Updated to `windows-sys` 0.59 [#14335](https://github.com/rust-lang/cargo/pull/14335) - Update dependencies. [#14299](https://github.com/rust-lang/cargo/pull/14299) [#14303](https://github.com/rust-lang/cargo/pull/14303) [#14324](https://github.com/rust-lang/cargo/pull/14324) [#14329](https://github.com/rust-lang/cargo/pull/14329) [#14331](https://github.com/rust-lang/cargo/pull/14331) [#14391](https://github.com/rust-lang/cargo/pull/14391) ## Cargo 1.81 (2024-09-05) [34a6a87d...rust-1.81.0](https://github.com/rust-lang/cargo/compare/34a6a87d...rust-1.81.0) ### Added ### Changed - ❗️ cargo-package: Disallow `package.license-file` and `package.readme` pointing to non-existent files during packaging. [#13921](https://github.com/rust-lang/cargo/pull/13921) - ❗️ cargo-package: generated `.cargo_vcs_info.json` is always included, even when `--allow-dirty` is passed. [#13960](https://github.com/rust-lang/cargo/pull/13960) - ❗️ Disallow passing `--release`/`--debug` flag along with the `--profile` flag. [#13971](https://github.com/rust-lang/cargo/pull/13971) - ❗️ Remove `lib.plugin` key support in Cargo.toml. Rust plugin support has been deprecated for four years and was removed in 1.75.0. [#13902](https://github.com/rust-lang/cargo/pull/13902) [#14038](https://github.com/rust-lang/cargo/pull/14038) - Make the calculation of `-Cmetadata` for rustc consistent across platforms. [#14107](https://github.com/rust-lang/cargo/pull/14107) - Emit a warning when `edition` is unset, even when MSRV is unset. [#14110](https://github.com/rust-lang/cargo/pull/14110) ### Fixed - Fix a proc-macro example from a dependency affecting feature resolution. [#13892](https://github.com/rust-lang/cargo/pull/13892) - Don't warn on duplicate packages from using '..'. [#14234](https://github.com/rust-lang/cargo/pull/14234) - Don't `du` on every git source load. [#14252](https://github.com/rust-lang/cargo/pull/14252) - Don't warn about unreferenced duplicate packages [#14239](https://github.com/rust-lang/cargo/pull/14239) - cargo-publish: Don't strip non-dev features for renamed dependencies from the HTTP JSON body sent to the registry. The bug only affected third-party registries. [#14328](https://github.com/rust-lang/cargo/pull/14328) - cargo-vendor: don't copy source files of excluded Cargo targets when vendoring. [#14368](https://github.com/rust-lang/cargo/pull/14368) ### Nightly only - πŸ”₯ `update-breaking`: Add `--breaking` to `cargo update`, allowing upgrading dependencies to breaking versions. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#update-breaking) [#13979](https://github.com/rust-lang/cargo/pull/13979) [#14047](https://github.com/rust-lang/cargo/pull/14047) [#14049](https://github.com/rust-lang/cargo/pull/14049) - `--artifact-dir`: Rename `--out-dir` to `--artifact-dir`. The `--out-dir` flag is kept for compatibility and may be removed when the feature gets stabilized. [#13809](https://github.com/rust-lang/cargo/pull/13809) - `edition2024`: Ensure unused optional dependencies fire for shadowed dependencies. [#14028](https://github.com/rust-lang/cargo/pull/14028) - `edition2024`: Address problems with implicit -> explicit feature migration [#14018](https://github.com/rust-lang/cargo/pull/14018) - `-Zcargo-lints`: Add `unknown_lints` to lints list. [#14024](https://github.com/rust-lang/cargo/pull/14024) - `-Zcargo-lints`: Add tooling to document lints. [#14025](https://github.com/rust-lang/cargo/pull/14025) - `-Zcargo-lints`: Keep lints updated and sorted. [#14030](https://github.com/rust-lang/cargo/pull/14030) - `-Zconfig-include`: Allow enabling `config-include` feature in config. [#14196](https://github.com/rust-lang/cargo/pull/14196) - `-Zpublic-dependency`: remove some legacy public dependency code from the resolver [#14090](https://github.com/rust-lang/cargo/pull/14090) - `-Ztarget-applies-to-host`: Pass rustflags to artifacts built with implicit targets when using target-applies-to-host [#13900](https://github.com/rust-lang/cargo/pull/13900) [#14201](https://github.com/rust-lang/cargo/pull/14201) - cargo-update: Track the behavior of `--precise `. [#14013](https://github.com/rust-lang/cargo/pull/14013) ### Documentation - Clarify `CARGO_CFG_TARGET_FAMILY` is multi-valued. [#14165](https://github.com/rust-lang/cargo/pull/14165) - Document `CARGO_CFG_TARGET_ABI` [#14164](https://github.com/rust-lang/cargo/pull/14164) - Document MSRV for each manifest field and build script invocations. [#14224](https://github.com/rust-lang/cargo/pull/14224) - Remove duplicate `strip` section. [#14146](https://github.com/rust-lang/cargo/pull/14146) - Update summary of Cargo configuration to include missing keys. [#14145](https://github.com/rust-lang/cargo/pull/14145) - Update index of Cargo documentation. [#14228](https://github.com/rust-lang/cargo/pull/14228) - Don't mention non-existent `workspace.badges` field. [#14042](https://github.com/rust-lang/cargo/pull/14042) - contrib: Suggest atomic commits with separate test commits. [#14014](https://github.com/rust-lang/cargo/pull/14014) - contrib: Document how to write an RFC for Cargo. [#14222](https://github.com/rust-lang/cargo/pull/14222) - contrib: Improve triage instructions [#14052](https://github.com/rust-lang/cargo/pull/14052) ### Internal - cargo-package: Change verification order during packaging. [#14074](https://github.com/rust-lang/cargo/pull/14074) - ci: Add workflow to publish Cargo automatically [#14202](https://github.com/rust-lang/cargo/pull/14202) - ci: bump CI tools [#14062](https://github.com/rust-lang/cargo/pull/14062) [#14257](https://github.com/rust-lang/cargo/pull/14257) - registry: Add local registry overlays. [#13926](https://github.com/rust-lang/cargo/pull/13926) - registry: move `get_source_id` out of registry [#14218](https://github.com/rust-lang/cargo/pull/14218) - resolver: Simplify checking for dependency cycles [#14089](https://github.com/rust-lang/cargo/pull/14089) - rustfix: Add `CodeFix::apply_solution` and impl `Clone` [#14092](https://github.com/rust-lang/cargo/pull/14092) - source: Clean up after `PathSource`/`RecursivePathSource` split [#14169](https://github.com/rust-lang/cargo/pull/14169) [#14231](https://github.com/rust-lang/cargo/pull/14231) - Remove the temporary `__CARGO_GITOXIDE_DISABLE_LIST_FILES` environment variable. [#14036](https://github.com/rust-lang/cargo/pull/14036) - Simplify checking feature syntax [#14106](https://github.com/rust-lang/cargo/pull/14106) - Dont make new constant `InternedString` in hot path [#14211](https://github.com/rust-lang/cargo/pull/14211) - Use `std::fs::absolute` instead of reimplementing it [#14075](https://github.com/rust-lang/cargo/pull/14075) - Remove unecessary feature activations from cargo. [#14122](https://github.com/rust-lang/cargo/pull/14122) [#14160](https://github.com/rust-lang/cargo/pull/14160) - Revert #13630 as rustc ignores `-C strip` on MSVC. [#14061](https://github.com/rust-lang/cargo/pull/14061) - test: Allow `unexpected_builtin_cfgs` lint in `user_specific_cfgs` test [#14153](https://github.com/rust-lang/cargo/pull/14153) - test: Add cargo_test to test-support prelude [#14243](https://github.com/rust-lang/cargo/pull/14243) - test: migrate Cargo testsuite to `snapbox`. For the complete list of migration pull requests, see [#14039](https://github.com/rust-lang/cargo/issues/14039#issuecomment-2158974033) - Updated to `gix` 0.64.0 [#14431](https://github.com/rust-lang/cargo/pull/14431) - Update dependencies. [#13995](https://github.com/rust-lang/cargo/pull/13995) [#13998](https://github.com/rust-lang/cargo/pull/13998) [#14037](https://github.com/rust-lang/cargo/pull/14037) [#14063](https://github.com/rust-lang/cargo/pull/14063) [#14067](https://github.com/rust-lang/cargo/pull/14067) [#14174](https://github.com/rust-lang/cargo/pull/14174) [#14186](https://github.com/rust-lang/cargo/pull/14186) [#14254](https://github.com/rust-lang/cargo/pull/14254) ## Cargo 1.80 (2024-07-25) [b60a1555...rust-1.80.0](https://github.com/rust-lang/cargo/compare/b60a1555...rust-1.80.0) ### Added - πŸŽ‰ Stabilize `-Zcheck-cfg`! This by default enables rustc's checking of conditional compilation at compile time, which verifies that the crate is correctly handling conditional compilation for different target platforms or features. Internally, cargo will be passing a new command line option `--check-cfg` to all rustc and rustdoc invocations. A new build script invocation [`cargo::rustc-check-cfg=CHECK_CFG`](https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg) is added along with this stabilization, as a way to add custom cfgs to the list of expected cfg names and values. If a build script is not an option for your package, Cargo provides a config [`[lints.rust.unexpected_cfgs.check-cfg]`](https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html#check-cfg-in-lintsrust-table) to add known custom cfgs statically. ([RFC 3013](https://github.com/rust-lang/rfcs/blob/master/text/3013-conditional-compilation-checking.md)) ([docs](https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html)) [#13571](https://github.com/rust-lang/cargo/pull/13571) [#13865](https://github.com/rust-lang/cargo/pull/13865) [#13869](https://github.com/rust-lang/cargo/pull/13869) [#13884](https://github.com/rust-lang/cargo/pull/13884) [#13913](https://github.com/rust-lang/cargo/pull/13913) [#13937](https://github.com/rust-lang/cargo/pull/13937) [#13958](https://github.com/rust-lang/cargo/pull/13958) - πŸŽ‰ cargo-update: Allows `--precise` to specify a yanked version of a package, and will update the lockfile accordingly. [#13974](https://github.com/rust-lang/cargo/pull/13974) ### Changed - ❗️ manifest: Disallow `[badges]` to inherit from `[workspace.package.badges]`. This was considered a bug. Keep in mind that `[badges]` is effectively deprecated. [#13788](https://github.com/rust-lang/cargo/pull/13788) - build-script: Suggest old syntax based on MSRV. [#13874](https://github.com/rust-lang/cargo/pull/13874) - cargo-add: Avoid escaping double quotes by using string literals. [#14006](https://github.com/rust-lang/cargo/pull/14006) - cargo-clean: Performance improvements for cleaning specific packages via `-p` flag. [#13818](https://github.com/rust-lang/cargo/pull/13818) - cargo-new: Use `i32` rather than `usize` as the "default integer" in library template. [#13939](https://github.com/rust-lang/cargo/pull/13939) - cargo-package: Warn, rather than fail, if a Cargo target is excluded during packaging. [#13713](https://github.com/rust-lang/cargo/pull/13713) - manifest: Warn, not error, on unsupported lint tool in the `[lints]` table. [#13833](https://github.com/rust-lang/cargo/pull/13833) - perf: Avoid inferring when Cargo targets are known. [#13849](https://github.com/rust-lang/cargo/pull/13849) - Populate git information when building Cargo from Rust's source tarball. [#13832](https://github.com/rust-lang/cargo/pull/13832) - Improve the error message when deserializing Cargo configuration from partial environment variables. [#13956](https://github.com/rust-lang/cargo/pull/13956) ### Fixed - resolver: Make path dependencies with the same name stay locked. [#13572](https://github.com/rust-lang/cargo/pull/13572) - cargo-add: Preserve file permissions on Unix during `write_atomic`. [#13898](https://github.com/rust-lang/cargo/pull/13898) - cargo-clean: Remove symlink directory on Windows. [#13910](https://github.com/rust-lang/cargo/pull/13910) - cargo-fix: Don't fix into the standard library. [#13792](https://github.com/rust-lang/cargo/pull/13792) - cargo-fix: Support IPv6-only networks. [#13907](https://github.com/rust-lang/cargo/pull/13907) - cargo-new: Don't say we're adding to a workspace when a regular package is in the root. [#13987](https://github.com/rust-lang/cargo/pull/13987) - cargo-vendor: Silence the warning about forgetting the vendoring. [#13886](https://github.com/rust-lang/cargo/pull/13886) - cargo-publish/cargo-vendor: Ensure targets in generated Cargo.toml are in a deterministic order. [#13989](https://github.com/rust-lang/cargo/pull/13989) [#14004](https://github.com/rust-lang/cargo/pull/14004) - cargo-credential-libsecret: Load `libsecret` by its `SONAME`, `libsecret-1.so.0`. [#13927](https://github.com/rust-lang/cargo/pull/13927) - Don't panic when an alias doesn't include a subcommand. [#13819](https://github.com/rust-lang/cargo/pull/13819) - Workaround copying file returning EAGAIN on ZFS on macOS. [#13845](https://github.com/rust-lang/cargo/pull/13845) - Fetch specific commits even if the GitHub fast path fails. [#13946](https://github.com/rust-lang/cargo/pull/13946) [#13969](https://github.com/rust-lang/cargo/pull/13969) - Distinguish Cargo config from different environment variables that share the same prefix. [#14000](https://github.com/rust-lang/cargo/pull/14000) ### Nightly only - `-Zcargo-lints`: Don't always inherit workspace lints. [#13812](https://github.com/rust-lang/cargo/pull/13812) - `-Zcargo-lints`: Add a test to ensure cap-lints works. [#13829](https://github.com/rust-lang/cargo/pull/13829) - `-Zcargo-lints`: Error when unstable lints are specified but not enabled. [#13805](https://github.com/rust-lang/cargo/pull/13805) - `-Zcargo-lints`: Add cargo-lints to unstable docs. [#13881](https://github.com/rust-lang/cargo/pull/13881) - `-Zcargo-lints`: Refactor cargo lint tests. [#13880](https://github.com/rust-lang/cargo/pull/13880) - `-Zcargo-lints`: Remove ability to specify `-` in lint name. [#13837](https://github.com/rust-lang/cargo/pull/13837) - `-Zscript`: Remove unstable rejected frontmatter syntax for cargo script. The only allowed frontmatter syntax now is `---`. [#13861](https://github.com/rust-lang/cargo/pull/13861) [#13893](https://github.com/rust-lang/cargo/pull/13893) - `-Zbindeps`: Build only the specified artifact library when multiple types are available. [#13842](https://github.com/rust-lang/cargo/pull/13842) - `-Zmsrv-policy`: Treat unset MSRV as compatible. [#13791](https://github.com/rust-lang/cargo/pull/13791) - `-Zgit`/`-Zgitoxide`: Default configuration to be obtained from both environment variables and Cargo configuration. [#13687](https://github.com/rust-lang/cargo/pull/13687) - `-Zpublic-dependency`: Don't lose 'public' when inheriting a dependency. [#13836](https://github.com/rust-lang/cargo/pull/13836) - `edition2024`: Disallow ignored `default-features` when inheriting. [#13839](https://github.com/rust-lang/cargo/pull/13839) - `edition2024`: Validate crate-types/proc-macro for bin like other Cargo targets. [#13841](https://github.com/rust-lang/cargo/pull/13841) ### Documentation - cargo-package: Clarify no guarantee of VCS provenance. [#13984](https://github.com/rust-lang/cargo/pull/13984) - cargo-metadata: Clarify dash replacement rule in Cargo target names. [#13887](https://github.com/rust-lang/cargo/pull/13887) - config: Fix wrong type of `rustc-flags` in build script overrides. [#13957](https://github.com/rust-lang/cargo/pull/13957) - resolver: Add README for `resolver-tests`. [#13977](https://github.com/rust-lang/cargo/pull/13977) - contrib: Update UI example code in contributor guide. [#13864](https://github.com/rust-lang/cargo/pull/13864) - Fix libcurl proxy documentation link. [#13990](https://github.com/rust-lang/cargo/pull/13990) - Add missing `CARGO_MAKEFLAGS` env for plugins. [#13872](https://github.com/rust-lang/cargo/pull/13872) - Include CircleCI reference in the Continuous Integration chapter. [#13850](https://github.com/rust-lang/cargo/pull/13850) ### Internal - ci: Don't check `cargo` against beta channel. [#13827](https://github.com/rust-lang/cargo/pull/13827) - test: Set safe.directory for git repo in apache container. [#13920](https://github.com/rust-lang/cargo/pull/13920) - test: Silence warnings running embedded unittests. [#13929](https://github.com/rust-lang/cargo/pull/13929) - test: Update test formatting due to nightly rustc changes. [#13890](https://github.com/rust-lang/cargo/pull/13890) [#13901](https://github.com/rust-lang/cargo/pull/13901) [#13964](https://github.com/rust-lang/cargo/pull/13964) - test: Make `git::use_the_cli` test truly locale independent. [#13935](https://github.com/rust-lang/cargo/pull/13935) - cargo-test-support: Transition direct assertions from cargo-test-support to snapbox. [#13980](https://github.com/rust-lang/cargo/pull/13980) - cargo-test-support: Auto-redact elapsed time. [#13973](https://github.com/rust-lang/cargo/pull/13973) - cargo-test-support: Clean up unnecessary uses of `match_exact`. [#13879](https://github.com/rust-lang/cargo/pull/13879) - Split `RecursivePathSource` out of `PathSource`. [#13993](https://github.com/rust-lang/cargo/pull/13993) - Adjust custom errors from cert-check due to libgit2 1.8 change. [#13970](https://github.com/rust-lang/cargo/pull/13970) - Move diagnostic printing to Shell. [#13813](https://github.com/rust-lang/cargo/pull/13813) - Update dependencies. [#13834](https://github.com/rust-lang/cargo/pull/13834) [#13840](https://github.com/rust-lang/cargo/pull/13840) [#13948](https://github.com/rust-lang/cargo/pull/13948) [#13963](https://github.com/rust-lang/cargo/pull/13963) [#13976](https://github.com/rust-lang/cargo/pull/13976) ## Cargo 1.79 (2024-06-13) [2fe739fc...rust-1.79.0](https://github.com/rust-lang/cargo/compare/2fe739fc...rust-1.79.0) ### Added - πŸŽ‰ `cargo add` respects `package.rust-version` a.k.a. MSRV when adding new dependencies. The behavior can be overridden by specifying a version requirement, or passing the `--ignore-rust-version` flag. ([RFC 3537](https://github.com/rust-lang/rfcs/blob/master/text/3537-msrv-resolver.md)) [#13608](https://github.com/rust-lang/cargo/pull/13608) - A new `Locking` status message shows dependency changes on any command. For `cargo update`, it also tells you if any dependency version is outdated. [#13561](https://github.com/rust-lang/cargo/pull/13561) [#13647](https://github.com/rust-lang/cargo/pull/13647) [#13651](https://github.com/rust-lang/cargo/pull/13651) [#13657](https://github.com/rust-lang/cargo/pull/13657) [#13759](https://github.com/rust-lang/cargo/pull/13759) [#13764](https://github.com/rust-lang/cargo/pull/13764) ### Changed - ❗️ `RUSTC_WRAPPER`, `RUSTC_WORKSPACE_WRAPPER`, and variables from the `[env]` table now also apply to the initial `rustc -vV` invocation Cargo uses for probing rustc information. [#13659](https://github.com/rust-lang/cargo/pull/13659) - ❗️ Turns dependencies like `foo = { optional = true }` from `version="*"` dependencies with a warning into errors. This behavior has been considered a bug from the beginning. [#13775](https://github.com/rust-lang/cargo/pull/13775) - ❗️ Replace dashes with underscores also if `lib.name` is inferred from `package.name`. This change aligns to the documented behavior. One caveat is that JSON messages emitted by Cargo, like via `cargo metadata` or `--message-format=json`, will start reporting underscore lib names. [#12783](https://github.com/rust-lang/cargo/pull/12783) - Switch to `gitoxide` for listing files. This improves the performance of build script and `cargo doc` for computing cache freshness, as well as fixes some subtle bugs for `cargo publish`. [#13592](https://github.com/rust-lang/cargo/pull/13592) [#13696](https://github.com/rust-lang/cargo/pull/13696) [#13704](https://github.com/rust-lang/cargo/pull/13704) [#13777](https://github.com/rust-lang/cargo/pull/13777) - Warn on `-Zlints` being passed and no longer necessary. [#13632](https://github.com/rust-lang/cargo/pull/13632) - Warn on unused `workspace.dependencies` keys on virtual workspaces. [#13664](https://github.com/rust-lang/cargo/pull/13664) - Emit 1.77 build script syntax error only when msrv is incompatible. [#13808](https://github.com/rust-lang/cargo/pull/13808) - Don't warn on `lints.rust.unexpected_cfgs.check-cfg`. [#13925](https://github.com/rust-lang/cargo/pull/13925) - cargo-init: don't assign `target.name` in Cargo.toml if the value can be inferred. [#13606](https://github.com/rust-lang/cargo/pull/13606) - cargo-package: normalize paths in `Cargo.toml`, including replacing `\` with `/`. [#13729](https://github.com/rust-lang/cargo/pull/13729) - cargo-test: recategorize cargo test's `--doc` flag under β€œTarget Selection”. [#13756](https://github.com/rust-lang/cargo/pull/13756) ### Fixed - Ensure `--config net.git-fetch-with-cli=true` is respected. [#13992](https://github.com/rust-lang/cargo/pull/13992) [#13997](https://github.com/rust-lang/cargo/pull/13997) - Dont panic when resolving an empty alias. [#13613](https://github.com/rust-lang/cargo/pull/13613) - When using `--target`, the default debuginfo strip rule also applies. Note that on Windows MSVC Cargo no longer strips by default. [#13618](https://github.com/rust-lang/cargo/pull/13618) - Don't crash on Cargo.toml parse errors that point to multi-byte character [#13780](https://github.com/rust-lang/cargo/pull/13780) - Don't emit deprecation warning if one of `.cargo/{config,config.toml}` is a symlink to the other. [#13793](https://github.com/rust-lang/cargo/pull/13793) - Follow HTTP redirections when checking if a repo on GitHub is up-to-date. [#13718](https://github.com/rust-lang/cargo/pull/13718) - Bash completion fallback in `nounset` mode. [#13686](https://github.com/rust-lang/cargo/pull/13686) - Rerun build script when rustflags changed and `--target` was passed. [#13560](https://github.com/rust-lang/cargo/pull/13560) - Fix doc collision for lib/bin with a dash in the inferred name. [#13640](https://github.com/rust-lang/cargo/pull/13640) - cargo-add: Maintain sorting of dependency features. [#13682](https://github.com/rust-lang/cargo/pull/13682) - cargo-add: Preserve comments when updating simple deps [#13655](https://github.com/rust-lang/cargo/pull/13655) - cargo-fix: dont apply same suggestion twice. [#13728](https://github.com/rust-lang/cargo/pull/13728) - cargo-package: error when the package specified via `--package` cannot be found [#13735](https://github.com/rust-lang/cargo/pull/13735) - credential-provider: trim newlines in tokens from stdin. [#13770](https://github.com/rust-lang/cargo/pull/13770) ### Nightly only - πŸ”₯ cargo-update: allows `--precise` to specify a pre-release version of a package ([RFC 3493](https://github.com/rust-lang/rfcs/blob/master/text/3493-precise-pre-release-cargo-update.md)) ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#precise-pre-release)) [#13626](https://github.com/rust-lang/cargo/pull/13626) - RFC 3491: Unused dependencies cleanup [#13778](https://github.com/rust-lang/cargo/pull/13778) - `-Zcargo-lints`: Add a basic linting system for Cargo. This is still under development and not available for general use. [#13621](https://github.com/rust-lang/cargo/pull/13621) [#13635](https://github.com/rust-lang/cargo/pull/13635) [#13797](https://github.com/rust-lang/cargo/pull/13797) [#13740](https://github.com/rust-lang/cargo/pull/13740) [#13801](https://github.com/rust-lang/cargo/pull/13801) [#13852](https://github.com/rust-lang/cargo/pull/13852) [#13853](https://github.com/rust-lang/cargo/pull/13853) - πŸ”₯ `edition2024`: Add default Edition2024 to resolver v3 (MSRV-aware resolver). [#13785](https://github.com/rust-lang/cargo/pull/13785) - `edition2024`: Remove underscore field support in 2024. [#13783](https://github.com/rust-lang/cargo/pull/13783) [#13798](https://github.com/rust-lang/cargo/pull/13798) [#13800](https://github.com/rust-lang/cargo/pull/13800) [#13804](https://github.com/rust-lang/cargo/pull/13804) - `edition2024`: Error on `[project]` in Edition 2024 [#13747](https://github.com/rust-lang/cargo/pull/13747) - `-Zmsrv-policy`: Respect '--ignore-rust-version' [#13738](https://github.com/rust-lang/cargo/pull/13738) - `-Zmsrv-policy`: Add `--ignore-rust-version` to update/generate-lockfile [#13741](https://github.com/rust-lang/cargo/pull/13741) [#13742](https://github.com/rust-lang/cargo/pull/13742) - `-Zmsrv-policy`: Put MSRV-aware resolver behind a config [#13769](https://github.com/rust-lang/cargo/pull/13769) - `-Zmsrv-policy`: Error, rather than panic, on rust-version 'x' [#13771](https://github.com/rust-lang/cargo/pull/13771) - `-Zmsrv-policy`: Fallback to 'rustc -V' for MSRV resolving. [#13743](https://github.com/rust-lang/cargo/pull/13743) - `-Zmsrv-policy`: Add v3 resolver for MSRV-aware resolving [#13776](https://github.com/rust-lang/cargo/pull/13776) - `-Zmsrv-policy`: Don't respect MSRV for non-local installs [#13790](https://github.com/rust-lang/cargo/pull/13790) - `-Zmsrv-policy`: Track when MSRV is explicitly set, either way [#13732](https://github.com/rust-lang/cargo/pull/13732) - test: don't compress test registry crates. [#13744](https://github.com/rust-lang/cargo/pull/13744) ### Documentation - Clarify `--locked` ensuring that Cargo uses dependency versions in lockfile [#13665](https://github.com/rust-lang/cargo/pull/13665) - Clarify the precedence of `RUSTC_WORKSPACE_WRAPPER` and `RUSTC_WRAPPER`. [#13648](https://github.com/rust-lang/cargo/pull/13648) - Clarify only in the root Cargo.toml the `[workspace]` section is allowed. [#13753](https://github.com/rust-lang/cargo/pull/13753) - Clarify the differences between virtual and real manifests. [#13794](https://github.com/rust-lang/cargo/pull/13794) ### Internal - πŸŽ‰ New member crates [`cargo-test-support`](https://crates.io/crates/cargo-test-support) and [`cargo-test-macro`](https://crates.io/crates/cargo-test-macro)! They are designed for testing Cargo itself, so no guarantee on any stability across versions. The crates.io publish of this crate is the same as other members crates. They follow Rust's [6-week release process](https://doc.crates.io/contrib/process/release.html#cratesio-publishing). [#13418](https://github.com/rust-lang/cargo/pull/13418) - Fix publish script due to crates.io CDN change [#13614](https://github.com/rust-lang/cargo/pull/13614) - Push diagnostic complexity on annotate-snippets [#13619](https://github.com/rust-lang/cargo/pull/13619) - cargo-package: Simplify getting of published Manifest [#13666](https://github.com/rust-lang/cargo/pull/13666) - ci: update macos images to macos-13 [#13685](https://github.com/rust-lang/cargo/pull/13685) - manifest: Split out an explicit step to resolve `Cargo.toml` [#13693](https://github.com/rust-lang/cargo/pull/13693) - manifest: Decouple target discovery from Target creation [#13701](https://github.com/rust-lang/cargo/pull/13701) - manifest: Expose surce/spans for VirtualManifests [#13603](https://github.com/rust-lang/cargo/pull/13603) - Update dependencies [#13609](https://github.com/rust-lang/cargo/pull/13609) [#13674](https://github.com/rust-lang/cargo/pull/13674) [#13675](https://github.com/rust-lang/cargo/pull/13675) [#13679](https://github.com/rust-lang/cargo/pull/13679) [#13680](https://github.com/rust-lang/cargo/pull/13680) [#13692](https://github.com/rust-lang/cargo/pull/13692) [#13731](https://github.com/rust-lang/cargo/pull/13731) [#13760](https://github.com/rust-lang/cargo/pull/13760) [#13950](https://github.com/rust-lang/cargo/pull/13950) ## Cargo 1.78 (2024-05-02) [7bb7b539...rust-1.78.0](https://github.com/rust-lang/cargo/compare/7bb7b539...rust-1.78.0) ### Added - Stabilize global cache data tracking. The `-Zgc` flag is still unstable. This is only for Cargo to start data collection, so that when automatic gc is stabilized, it's less likely to see cache misses. [#13492](https://github.com/rust-lang/cargo/pull/13492) [#13467](https://github.com/rust-lang/cargo/pull/13467) - Stabilize lockfile format v4. Lockfile v3 is still the default version. [#12852](https://github.com/rust-lang/cargo/pull/12852) - Auto-detecting whether output can be rendered using non-ASCII Unicode characters. A configuration value `term.unicode` is added to control the behavior manually. [docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#termunicode) [#13337](https://github.com/rust-lang/cargo/pull/13337) - Support `target..rustdocflags` in Cargo configuration. [docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#targettriplerustdocflags) [#13197](https://github.com/rust-lang/cargo/pull/13197) ### Changed - cargo-add: Print a status when a dep feature is being created [#13434](https://github.com/rust-lang/cargo/pull/13434) - cargo-add: improve the error message when adding a package from a replaced source. [#13281](https://github.com/rust-lang/cargo/pull/13281) - cargo-doc: Collapse down `Generated` statuses without `--verbose`. [#13557](https://github.com/rust-lang/cargo/pull/13557) - cargo-new: Print a 'Creating', rather than 'Created' status [#13367](https://github.com/rust-lang/cargo/pull/13367) - cargo-new: Print a note, rather than a comment, for more information [#13371](https://github.com/rust-lang/cargo/pull/13371) - cargo-new: Print a hint when adding members to workspace [#13411](https://github.com/rust-lang/cargo/pull/13411) - cargo-test: Suggest `--` for libtest arguments [#13448](https://github.com/rust-lang/cargo/pull/13448) - cargo-update: Tell users when some dependencies are still behind latest. [#13372](https://github.com/rust-lang/cargo/pull/13372) - Deprecate non-extension `.cargo/config` files. [#13349](https://github.com/rust-lang/cargo/pull/13349) - Don't print rustdoc command lines on failure by default [#13387](https://github.com/rust-lang/cargo/pull/13387) - Respect `package.rust-version` when generating new lockfiles. [#12861](https://github.com/rust-lang/cargo/pull/12861) - Send `User-Agent: cargo/1.2.3` header when communicating with remote registries. Previously it was `cargo 1.2.3`, which didn't follow the HTTP specifications. [#13548](https://github.com/rust-lang/cargo/pull/13548) - Emit a warning when `package.edition` field is missing in Cargo.toml. [#13499](https://github.com/rust-lang/cargo/pull/13499) [#13504](https://github.com/rust-lang/cargo/pull/13504) [#13505](https://github.com/rust-lang/cargo/pull/13505) [#13533](https://github.com/rust-lang/cargo/pull/13533) - Emit warnings from parsing virtual manifests. [#13589](https://github.com/rust-lang/cargo/pull/13589) - Mention the workspace root location in the error message when collecting workspace members. [#13480](https://github.com/rust-lang/cargo/pull/13480) - Clarify the profile in use in `Finished` status message. [#13422](https://github.com/rust-lang/cargo/pull/13422) - Switched more notes/warnings to lowercase. [#13410](https://github.com/rust-lang/cargo/pull/13410) - Report all packages incompatible with `package.rust-version.`, not just a random one. [#13514](https://github.com/rust-lang/cargo/pull/13514) ### Fixed - cargo-add: don't add the new package to `workspace.members` if there is no existing workspace in Cargo.toml. [#13391](https://github.com/rust-lang/cargo/pull/13391) - cargo-add: Fix markdown line break in cargo-add [#13400](https://github.com/rust-lang/cargo/pull/13400) - cargo-run: use Package ID Spec match packages [#13335](https://github.com/rust-lang/cargo/pull/13335) - cargo-doc: doctest searches native libs in build script outputs. [#13490](https://github.com/rust-lang/cargo/pull/13490) - cargo-publish: strip also features from dev-dependencies from Cargo.toml to publish. [#13518](https://github.com/rust-lang/cargo/pull/13518) - Don't duplicate comments when editing TOML via `cargo add/rm/init/new`. [#13402](https://github.com/rust-lang/cargo/pull/13402) - Fix confusing error messages for sparse index replaced source. [#13433](https://github.com/rust-lang/cargo/pull/13433) - Respect `CARGO_TERM_COLOR` in '--list' and '-Zhelp'. [#13479](https://github.com/rust-lang/cargo/pull/13479) - Control colors of errors and help texts from clap through `CARGO_TERM_COLOR`. [#13463](https://github.com/rust-lang/cargo/pull/13463) - Don't panic on empty spans in Cargo.toml. [#13375](https://github.com/rust-lang/cargo/pull/13375) [#13376](https://github.com/rust-lang/cargo/pull/13376) ### Nightly only - πŸ”₯ cargo-update: allows `--precise` to specify a yanked version of a package [#13333](https://github.com/rust-lang/cargo/pull/13333) - `-Zcheck-cfg`: Add `docsrs` cfg as a well known `--check-cfg` [#13383](https://github.com/rust-lang/cargo/pull/13383) - `-Zcheck-cfg`: Silently ignore `cargo::rustc-check-cfg` to avoid MSRV annoyance when stabilizing `-Zcheck-cfg`. [#13438](https://github.com/rust-lang/cargo/pull/13438) - `-Zmsrv-policy`: Fallback to `rustc -v` when no MSRV is set [#13516](https://github.com/rust-lang/cargo/pull/13516) - `-Zscript`: Improve errors related to cargo script [#13346](https://github.com/rust-lang/cargo/pull/13346) - `-Zpanic-abort-tests`: applies to doctests too [#13388](https://github.com/rust-lang/cargo/pull/13388) - `-Zpublic-dependency`: supports enabling via the `-Zpublic-dependency` flag. [#13340](https://github.com/rust-lang/cargo/pull/13340) [#13556](https://github.com/rust-lang/cargo/pull/13556) [#13547](https://github.com/rust-lang/cargo/pull/13547) - `-Zpublic-dependency`: test for packaging a public dependency [#13536](https://github.com/rust-lang/cargo/pull/13536) - `-Zrustdoc-map`: Add all unit's children recursively for `doc.extern-map` option [#13481](https://github.com/rust-lang/cargo/pull/13481) [#13544](https://github.com/rust-lang/cargo/pull/13544) - `edition2024`: Enable edition migration for 2024. [#13429](https://github.com/rust-lang/cargo/pull/13429) - `open-namespaces`: basic support for open namespaces ([RFC 3243](https://github.com/rust-lang/rfcs/blob/master/text/3243-packages-as-optional-namespaces.md)) ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#open-namespaces)) [#13591](https://github.com/rust-lang/cargo/pull/13591) ### Documentation - cargo-fetch: hide `cargo-fetch` recursive link in `--offline` man page. [#13364](https://github.com/rust-lang/cargo/pull/13364) - cargo-install: `--list` option description starting with uppercase [#13344](https://github.com/rust-lang/cargo/pull/13344) - cargo-vendor: clarify vendored sources as read-only and ways to modify them [#13512](https://github.com/rust-lang/cargo/pull/13512) - build-script: clarification of build script metadata set via `cargo::metadata=KEY=VALUE`. [#13436](https://github.com/rust-lang/cargo/pull/13436) - Clarify the `version` field in `[package]` is optional in Cargo.toml [#13390](https://github.com/rust-lang/cargo/pull/13390) - Improve "Registry Authentication" docs [#13351](https://github.com/rust-lang/cargo/pull/13351) - Improve "Specifying Dependencies" docs [#13341](https://github.com/rust-lang/cargo/pull/13341) - Remove `package.documentation` from the β€œbefore publishing” list. [#13398](https://github.com/rust-lang/cargo/pull/13398) ### Internal - πŸŽ‰ Integrated tracing-chrome as a basic profiler for Cargo itself. [docs](https://doc.crates.io/contrib/tests/profiling.html) [#13399](https://github.com/rust-lang/cargo/pull/13399) [#13551](https://github.com/rust-lang/cargo/pull/13551) - Updated to `gix` 0.58.0 [#13380](https://github.com/rust-lang/cargo/pull/13380) - Updated to `git2` 0.18.2 [#13412](https://github.com/rust-lang/cargo/pull/13412) - Updated to `jobserver` 0.1.28 [#13419](https://github.com/rust-lang/cargo/pull/13419) - Updated to `supports-hyperlinks` 3.0.0 [#13511](https://github.com/rust-lang/cargo/pull/13511) - Updated to `rusqlite` 0.31.0 [#13510](https://github.com/rust-lang/cargo/pull/13510) - bump-check: use symmetric difference when comparing source code [#13581](https://github.com/rust-lang/cargo/pull/13581) - bump-check: include rustfix and cargo-util-schemas [#13421](https://github.com/rust-lang/cargo/pull/13421) - ci: enable m1 runner [#13377](https://github.com/rust-lang/cargo/pull/13377) - ci: Ensure lockfile is respected during MSRV testing via `cargo-hack`. [#13523](https://github.com/rust-lang/cargo/pull/13523) - cargo-util-schemas: Consistently compare MSRVs via `RustVersion::is_compatible_with`. [#13537](https://github.com/rust-lang/cargo/pull/13537) - console: Use new fancy `anstyle` API [#13368](https://github.com/rust-lang/cargo/pull/13368) [#13562](https://github.com/rust-lang/cargo/pull/13562) - fingerprint: remove unnecessary Option in `Freshness::Dirty` [#13361](https://github.com/rust-lang/cargo/pull/13361) - fingerprint: abstract `std::fs` away from on-disk index cache [#13515](https://github.com/rust-lang/cargo/pull/13515) - mdman: Updated to `pulldown-cmark` 0.10.0 [#13517](https://github.com/rust-lang/cargo/pull/13517) - refactor: Renamed `Config` to `GlobalContext` [#13409](https://github.com/rust-lang/cargo/pull/13409) [#13486](https://github.com/rust-lang/cargo/pull/13486) [#13506](https://github.com/rust-lang/cargo/pull/13506) - refactor: Removed unused `sysroot_host_libdir`. [#13468](https://github.com/rust-lang/cargo/pull/13468) - refactor: Expose source/spans to Manifest for emitting lints [#13593](https://github.com/rust-lang/cargo/pull/13593) - refactor: Flatten manifest parsing [#13589](https://github.com/rust-lang/cargo/pull/13589) - refactor: Make lockfile diffing/printing more reusable [#13564](https://github.com/rust-lang/cargo/pull/13564) - test: Updated to `snapbox` 0.5.0 [#13441](https://github.com/rust-lang/cargo/pull/13441) - test: Verify terminal styling via snapbox's `term-svg` feature. [#13461](https://github.com/rust-lang/cargo/pull/13461) [#13465](https://github.com/rust-lang/cargo/pull/13465) [#13520](https://github.com/rust-lang/cargo/pull/13520) - test: Ensure `nonzero_exit_code` test isn't affected by developers `RUST_BACKTRACE` setting [#13385](https://github.com/rust-lang/cargo/pull/13385) - test: Add tests for using worktrees. [#13567](https://github.com/rust-lang/cargo/pull/13567) - test: Fix old_cargos tests [#13435](https://github.com/rust-lang/cargo/pull/13435) - test: Fixed tests due to changes in rust-lang/rust. [#13362](https://github.com/rust-lang/cargo/pull/13362) [#13382](https://github.com/rust-lang/cargo/pull/13382) [#13415](https://github.com/rust-lang/cargo/pull/13415) [#13424](https://github.com/rust-lang/cargo/pull/13424) [#13444](https://github.com/rust-lang/cargo/pull/13444) [#13455](https://github.com/rust-lang/cargo/pull/13455) [#13464](https://github.com/rust-lang/cargo/pull/13464) [#13466](https://github.com/rust-lang/cargo/pull/13466) [#13469](https://github.com/rust-lang/cargo/pull/13469) - test: disable lldb test as it requires privileges to run on macOS [#13416](https://github.com/rust-lang/cargo/pull/13416) ## Cargo 1.77.1 (2024-03-28) ### Fixed - Debuginfo is no longer stripped by default for Windows MSVC targets. This caused an unexpected regression in 1.77.0 that broke backtraces. [#13654](https://github.com/rust-lang/cargo/pull/13654) ## Cargo 1.77 (2024-03-21) [1a2666dd...rust-1.77.0](https://github.com/rust-lang/cargo/compare/1a2666dd...rust-1.77.0) ### Added - πŸŽ‰ Stabilize the package identifier format as [Package ID Spec](https://doc.rust-lang.org/nightly/cargo/reference/pkgid-spec.html). This format can be used across most of the commands in Cargo, including the `--package`/`-p` flag, `cargo pkgid`, `cargo metadata`, and JSON messages from `--message-format=json`. [#12914](https://github.com/rust-lang/cargo/pull/12914) [#13202](https://github.com/rust-lang/cargo/pull/13202) [#13311](https://github.com/rust-lang/cargo/pull/13311) [#13298](https://github.com/rust-lang/cargo/pull/13298) [#13322](https://github.com/rust-lang/cargo/pull/13322) - Add colors to `-Zhelp` console output [#13269](https://github.com/rust-lang/cargo/pull/13269) - build script: Extend the build directive syntax with `cargo::`. [#12201](https://github.com/rust-lang/cargo/pull/12201) [#13212](https://github.com/rust-lang/cargo/pull/13212) ### Changed - πŸŽ‰ Disabling debuginfo now implies `strip = "debuginfo"` (when `strip` is not set) to strip pre-existing debuginfo coming from the standard library, reducing the default size of release binaries considerably (from ~4.5 MiB down to ~450 KiB for helloworld on Linux x64). [#13257](https://github.com/rust-lang/cargo/pull/13257) - Add `rustc` style errors for manifest parsing. [#13172](https://github.com/rust-lang/cargo/pull/13172) - Deprecate rustc plugin support in cargo [#13248](https://github.com/rust-lang/cargo/pull/13248) - cargo-vendor: Hold the mutate exclusive lock when vendoring. [#12509](https://github.com/rust-lang/cargo/pull/12509) - crates-io: Set `Content-Type: application/json` only for requests with a body payload [#13264](https://github.com/rust-lang/cargo/pull/13264) ### Fixed - jobserver: inherit jobserver from env for all kinds of runner [#12776](https://github.com/rust-lang/cargo/pull/12776) - build script: Set `OUT_DIR` for all units with build scripts [#13204](https://github.com/rust-lang/cargo/pull/13204) - cargo-add: find the correct package with given features from Git repositories with multiple packages. [#13213](https://github.com/rust-lang/cargo/pull/13213) - cargo-fix: always inherit the jobserver [#13225](https://github.com/rust-lang/cargo/pull/13225) - cargo-fix: Call rustc fewer times to improve the performance. [#13243](https://github.com/rust-lang/cargo/pull/13243) - cargo-new: only inherit workspace package table if the new package is a member [#13261](https://github.com/rust-lang/cargo/pull/13261) - cargo-update: `--precise` accepts arbitrary git revisions [#13250](https://github.com/rust-lang/cargo/pull/13250) - manifest: Provide unused key warnings for lints table [#13262](https://github.com/rust-lang/cargo/pull/13262) - rustfix: Support inserting new lines. [#13226](https://github.com/rust-lang/cargo/pull/13226) ### Nightly only - πŸ”₯ `-Zgit`: Implementation of shallow libgit2 fetches behind an unstable flag [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#git) [#13252](https://github.com/rust-lang/cargo/pull/13252) - πŸ”₯ Add unstable `--output-format` option to `cargo rustdoc`, providing tools with a way to lean on rustdoc’s experimental JSON format. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#output-format-for-rustdoc) [#12252](https://github.com/rust-lang/cargo/pull/12252) [#13284](https://github.com/rust-lang/cargo/pull/13284) [#13325](https://github.com/rust-lang/cargo/pull/13325) - `-Zcheck-cfg`: Rework `--check-cfg` generation comment [#13195](https://github.com/rust-lang/cargo/pull/13195) - `-Zcheck-cfg`: Go back to passing an empty `values()` when no features are declared [#13316](https://github.com/rust-lang/cargo/pull/13316) - `-Zprecise-pre-release`: the flag is added but not implemented yet. [#13296](https://github.com/rust-lang/cargo/pull/13296) [#13320](https://github.com/rust-lang/cargo/pull/13320) - `-Zpublic-dependency`: support publish package with a `public` field. [#13245](https://github.com/rust-lang/cargo/pull/13245) - `-Zpublic-dependency`: help text of `--public`/`--no-public` flags for `cargo add` [#13272](https://github.com/rust-lang/cargo/pull/13272) - `-Zscript`: Add prefix-char frontmatter syntax support [#13247](https://github.com/rust-lang/cargo/pull/13247) - `-Zscript`: Add multiple experimental manifest syntaxes [#13241](https://github.com/rust-lang/cargo/pull/13241) - `-Ztrim-paths`: remap common prefix only [#13210](https://github.com/rust-lang/cargo/pull/13210) ### Documentation - Added guidance on setting homepage in manifest [#13293](https://github.com/rust-lang/cargo/pull/13293) - Clarified how custom subcommands are looked up. [#13203](https://github.com/rust-lang/cargo/pull/13203) - Clarified why `du` function uses mutex [#13273](https://github.com/rust-lang/cargo/pull/13273) - Highlighted "How to find features enabled on dependencies" [#13305](https://github.com/rust-lang/cargo/pull/13305) - Delete sentence about parentheses being unsupported in license [#13292](https://github.com/rust-lang/cargo/pull/13292) - resolver: clarify how pre-release version is handled in dependency resolution. [#13286](https://github.com/rust-lang/cargo/pull/13286) - cargo-test: clarify the target selection of the test options. [#13236](https://github.com/rust-lang/cargo/pull/13236) - cargo-install: clarify `--path` is the installation source not destination [#13205](https://github.com/rust-lang/cargo/pull/13205) - contrib: Fix team HackMD links [#13237](https://github.com/rust-lang/cargo/pull/13237) - contrib: Highlight the non-blocking feature gating technique [#13307](https://github.com/rust-lang/cargo/pull/13307) ### Internal - πŸŽ‰ New member crate [`cargo-util-schemas`](https://crates.io/crates/cargo-util-schemas)! This contains low-level Cargo schema types, focusing on `serde` and `FromStr` for use in reading files and parsing command-lines. Any logic for getting final semantics from these will likely need other tools to process, like `cargo metadata`. The crates.io publish of this crate is the same as other members crates. It follows Rust's [6-week release process](https://doc.crates.io/contrib/process/release.html#cratesio-publishing). [#13178](https://github.com/rust-lang/cargo/pull/13178) [#13185](https://github.com/rust-lang/cargo/pull/13185) [#13186](https://github.com/rust-lang/cargo/pull/13186) [#13209](https://github.com/rust-lang/cargo/pull/13209) [#13267](https://github.com/rust-lang/cargo/pull/13267) - Updated to `gix` 0.57.1. [#13230](https://github.com/rust-lang/cargo/pull/13230) - cargo-fix: Remove error-format special-case in `cargo fix` [#13224](https://github.com/rust-lang/cargo/pull/13224) - cargo-credential: bump to 0.4.3 [#13221](https://github.com/rust-lang/cargo/pull/13221) - mdman: updated to `handlebars` 5.0.0. [#13168](https://github.com/rust-lang/cargo/pull/13168) [#13249](https://github.com/rust-lang/cargo/pull/13249) - rustfix: remove useless clippy rules and fix a typo [#13182](https://github.com/rust-lang/cargo/pull/13182) - ci: fix Dependabot's MSRV auto-update [#13265](https://github.com/rust-lang/cargo/pull/13265) [#13324](https://github.com/rust-lang/cargo/pull/13324) [#13268](https://github.com/rust-lang/cargo/pull/13268) - ci: Add [dependency dashboard](https://github.com/rust-lang/cargo/issues/13256). [#13255](https://github.com/rust-lang/cargo/pull/13255) - ci: update alpine docker tag to v3.19 [#13228](https://github.com/rust-lang/cargo/pull/13228) - ci: Improve GitHub Actions CI config [#13317](https://github.com/rust-lang/cargo/pull/13317) - resolver: do not panic when sorting empty summaries [#13287](https://github.com/rust-lang/cargo/pull/13287) ## Cargo 1.76 (2024-02-08) [6790a512...rust-1.76.0](https://github.com/rust-lang/cargo/compare/6790a512...rust-1.76.0) ### Added - Added a Windows application manifest file to the built `cargo.exe` for windows msvc. [#13131](https://github.com/rust-lang/cargo/pull/13131) Notable changes: - States the compatibility with Windows versions 7, 8, 8.1, 10 and 11. - Sets the code page to UTF-8. - Enables long path awareness. - Added color output for `cargo --list`. [#12992](https://github.com/rust-lang/cargo/pull/12992) - cargo-add: `--optional ` would create a ` = "dep:"` feature. [#13071](https://github.com/rust-lang/cargo/pull/13071) - Extends Package ID spec for unambiguous specs. [docs](https://doc.rust-lang.org/nightly/cargo/reference/pkgid-spec.html) [#12933](https://github.com/rust-lang/cargo/pull/12933) Specifically, - Supports `git+` and `path+` schemes. - Supports Git ref query strings, such as `?branch=dev` or `?tag=1.69.0`. ### Changed - ❗️ Disallow `[lints]` in virtual workspaces as they are ignored and users likely meant `[workspace.lints]`. This was an oversight in the initial implementation (e.g. a `[dependencies]` produces the same error). [#13155](https://github.com/rust-lang/cargo/pull/13155) - Disallow empty name in several places like package ID spec and `cargo new`. [#13152](https://github.com/rust-lang/cargo/pull/13152) - Respect `rust-lang/rust`'s `omit-git-hash` option. [#12968](https://github.com/rust-lang/cargo/pull/12968) - Displays error count with a number, even when there is only one error. [#12484](https://github.com/rust-lang/cargo/pull/12484) - `all-static` feature now includes `vendored-libgit2`. [#13134](https://github.com/rust-lang/cargo/pull/13134) - crates-io: Add support for other 2xx HTTP status codes when interacting with registries. [#13158](https://github.com/rust-lang/cargo/pull/13158) [#13160](https://github.com/rust-lang/cargo/pull/13160) - home: Replace SHGetFolderPathW with SHGetKnownFolderPath. [#13173](https://github.com/rust-lang/cargo/pull/13173) ### Fixed - Print rustc messages colored on wincon. [#13140](https://github.com/rust-lang/cargo/pull/13140) - Fixed bash completion in directory with spaces. [#13126](https://github.com/rust-lang/cargo/pull/13126) - Fixed uninstall a running binary failed on Windows. [#13053](https://github.com/rust-lang/cargo/pull/13053) [#13099](https://github.com/rust-lang/cargo/pull/13099) - Fixed the error message for duplicate links. [#12973](https://github.com/rust-lang/cargo/pull/12973) - Fixed `--quiet` being used with nested subcommands. [#12959](https://github.com/rust-lang/cargo/pull/12959) - Fixed panic when there is a cycle in dev-dependencies. [#12977](https://github.com/rust-lang/cargo/pull/12977) - Don't panic when failed to parse rustc commit-hash. [#12963](https://github.com/rust-lang/cargo/pull/12963) [#12965](https://github.com/rust-lang/cargo/pull/12965) - Don't do git fetches when updating workspace members. [#12975](https://github.com/rust-lang/cargo/pull/12975) - Avoid writing CACHEDIR.TAG if it already exists. [#13132](https://github.com/rust-lang/cargo/pull/13132) - Accept `?` in the `--package` flag if it's a valid pkgid spec. [#13315](https://github.com/rust-lang/cargo/pull/13315) [#13318](https://github.com/rust-lang/cargo/pull/13318) - cargo-package: Only filter out `target` directory if it's in the package root. [#12944](https://github.com/rust-lang/cargo/pull/12944) - cargo-package: errors out when a build script doesn't exist or is outside the package root. [#12995](https://github.com/rust-lang/cargo/pull/12995) - cargo-credential-1password: Add missing `--account` argument to `op signin` command. [#12985](https://github.com/rust-lang/cargo/pull/12985) [#12986](https://github.com/rust-lang/cargo/pull/12986) ### Nightly only - πŸ”₯ The `-Zgc` flag enables garbage collection for deleting old, unused files in cargo's cache. That is, downloaded source files and registry index under the `CARGO_HOME` directory. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#gc) [#12634](https://github.com/rust-lang/cargo/pull/12634) [#12958](https://github.com/rust-lang/cargo/pull/12958) [#12981](https://github.com/rust-lang/cargo/pull/12981) [#13055](https://github.com/rust-lang/cargo/pull/13055) - πŸ”₯ Added a new environment variable `CARGO_RUSTC_CURRENT_DIR`. This is a path that rustc is invoked from. [docs](https://doc.rust-lang.org/nightly/cargo/reference/environment-variables.html?highlight=CARGO_RUSTC_CURRENT_DIR#environment-variables-cargo-sets-for-crates) [#12996](https://github.com/rust-lang/cargo/pull/12996) - `-Zcheck-cfg`: Include declared list of features in fingerprint for `-Zcheck-cfg`. [#13012](https://github.com/rust-lang/cargo/pull/13012) - `-Zcheck-cfg`: Fix `--check-cfg` invocations with zero features. [#13011](https://github.com/rust-lang/cargo/pull/13011) - `-Ztrim-paths`: reorder `--remap-path-prefix` flags for `-Zbuild-std`. [#13065](https://github.com/rust-lang/cargo/pull/13065) - `-Ztrim-paths`: explicitly remap current dir by using `.`. [#13114](https://github.com/rust-lang/cargo/pull/13114) - `-Ztrim-paths`: exercise with real world debugger. [#13091](https://github.com/rust-lang/cargo/pull/13091) [#13118](https://github.com/rust-lang/cargo/pull/13118) - `-Zpublic-dependency`: Limit `exported-private-dependencies` lints to libraries. [#13135](https://github.com/rust-lang/cargo/pull/13135) - `-Zpublic-dependency`: Disallow workspace-inheriting of dependency public status. [#13125](https://github.com/rust-lang/cargo/pull/13125) - `-Zpublic-dependency`: Add `--public` for `cargo add`. [#13046](https://github.com/rust-lang/cargo/pull/13046) - `-Zpublic-dependency`: Remove unused public-deps error handling [#13036](https://github.com/rust-lang/cargo/pull/13036) - `-Zmsrv-policy`: Prefer MSRV, rather than ignore incompatible. [#12950](https://github.com/rust-lang/cargo/pull/12950) - `-Zmsrv-policy`: De-prioritize no-rust-version in MSRV resolver. [#13066](https://github.com/rust-lang/cargo/pull/13066) - `-Zrustdoc-scrape-examples`: Don't filter on workspace members when scraping doc examples. [#13077](https://github.com/rust-lang/cargo/pull/13077) ### Documentation - Recommends a wider selection of libsecret-compatible password managers. [#12993](https://github.com/rust-lang/cargo/pull/12993) - Clarified different targets has different sets of `CARGO_CFG_*` values. [#13069](https://github.com/rust-lang/cargo/pull/13069) - Clarified `[lints]` table only affects local development of the current package. [#12976](https://github.com/rust-lang/cargo/pull/12976) - Clarified `cargo search` can search in alternative registries. [#12962](https://github.com/rust-lang/cargo/pull/12962) - Added common CI practices for verifying `rust-version` (MSRV) field. [#13056](https://github.com/rust-lang/cargo/pull/13056) - Added a link to rustc lint levels doc. [#12990](https://github.com/rust-lang/cargo/pull/12990) - Added a link to the packages lint table from the related workspace table [#13057](https://github.com/rust-lang/cargo/pull/13057) - contrib: Add more resources to the contrib docs. [#13008](https://github.com/rust-lang/cargo/pull/13008) - contrib: Update how that credential crates are published. [#13006](https://github.com/rust-lang/cargo/pull/13006) - contrib: remove review capacity notice. [#13070](https://github.com/rust-lang/cargo/pull/13070) ### Internal - πŸŽ‰ Migrate `rustfix` crate to the `rust-lang/cargo` repository. [#13005](https://github.com/rust-lang/cargo/pull/13005) [#13042](https://github.com/rust-lang/cargo/pull/13042) [#13047](https://github.com/rust-lang/cargo/pull/13047) [#13048](https://github.com/rust-lang/cargo/pull/13048) [#13050](https://github.com/rust-lang/cargo/pull/13050) - Updated to `curl-sys` 0.4.70, which corresponds to curl 8.4.0. [#13147](https://github.com/rust-lang/cargo/pull/13147) - Updated to `gix-index` 0.27.1. [#13148](https://github.com/rust-lang/cargo/pull/13148) - Updated to `itertools` 0.12.0. [#13086](https://github.com/rust-lang/cargo/pull/13086) - Updated to `rusqlite` 0.30.0. [#13087](https://github.com/rust-lang/cargo/pull/13087) - Updated to `toml_edit` 0.21.0. [#13088](https://github.com/rust-lang/cargo/pull/13088) - Updated to `windows-sys` 0.52.0. [#13089](https://github.com/rust-lang/cargo/pull/13089) - Updated to `tracing` 0.1.37 for being be compatible with rustc_log. [#13239](https://github.com/rust-lang/cargo/pull/13239) [#13242](https://github.com/rust-lang/cargo/pull/13242) - Re-enable flaky gitoxide auth tests thanks to update to `gix-config`. [#13117](https://github.com/rust-lang/cargo/pull/13117) [#13129](https://github.com/rust-lang/cargo/pull/13129) [#13130](https://github.com/rust-lang/cargo/pull/13130) - Dogfood Cargo `-Zlints` table feature. [#12178](https://github.com/rust-lang/cargo/pull/12178) - Refactored `Cargo.toml` parsing code in preparation of extracting an official schema API. [#12954](https://github.com/rust-lang/cargo/pull/12954) [#12960](https://github.com/rust-lang/cargo/pull/12960) [#12961](https://github.com/rust-lang/cargo/pull/12961) [#12971](https://github.com/rust-lang/cargo/pull/12971) [#13000](https://github.com/rust-lang/cargo/pull/13000) [#13021](https://github.com/rust-lang/cargo/pull/13021) [#13080](https://github.com/rust-lang/cargo/pull/13080) [#13097](https://github.com/rust-lang/cargo/pull/13097) [#13123](https://github.com/rust-lang/cargo/pull/13123) [#13128](https://github.com/rust-lang/cargo/pull/13128) [#13154](https://github.com/rust-lang/cargo/pull/13154) [#13166](https://github.com/rust-lang/cargo/pull/13166) - Use `IndexSummary` in `query{_vec}` functions. [#12970](https://github.com/rust-lang/cargo/pull/12970) - ci: migrate renovate config [#13106](https://github.com/rust-lang/cargo/pull/13106) - ci: Always update gix packages together [#13093](https://github.com/rust-lang/cargo/pull/13093) - ci: Catch naive use of AtomicU64 early [#12988](https://github.com/rust-lang/cargo/pull/12988) - xtask-bump-check: dont check `home` against beta/stable branches [#13167](https://github.com/rust-lang/cargo/pull/13167) - cargo-test-support: Handle $message_type in JSON diagnostics [#13016](https://github.com/rust-lang/cargo/pull/13016) - cargo-test-support: Add more options to registry test support. [#13085](https://github.com/rust-lang/cargo/pull/13085) - cargo-test-support: Add features to the default Cargo.toml file [#12997](https://github.com/rust-lang/cargo/pull/12997) - cargo-test-support: Fix clippy-wrapper test race condition. [#12999](https://github.com/rust-lang/cargo/pull/12999) - test: Don't rely on mtime to test changes [#13143](https://github.com/rust-lang/cargo/pull/13143) - test: remove unnecessary packages and versions for `optionals` tests [#13108](https://github.com/rust-lang/cargo/pull/13108) - test: Remove the deleted feature `test_2018_feature` from the test. [#13156](https://github.com/rust-lang/cargo/pull/13156) - test: remove jobserver env var in some tests. [#13072](https://github.com/rust-lang/cargo/pull/13072) - test: Fix a rustflags test using a wrong buildfile name [#12987](https://github.com/rust-lang/cargo/pull/12987) - test: Fix some test output validation. [#12982](https://github.com/rust-lang/cargo/pull/12982) - test: Ignore changing_spec_relearns_crate_types on windows-gnu [#12972](https://github.com/rust-lang/cargo/pull/12972) ## Cargo 1.75 (2023-12-28) [59596f0f...rust-1.75.0](https://github.com/rust-lang/cargo/compare/59596f0f...rust-1.75.0) ### Added - `package.version` field in `Cargo.toml` is now optional and defaults to `0.0.0`. Packages without the `package.version` field cannot be published. [#12786](https://github.com/rust-lang/cargo/pull/12786) - Links in `--timings` and `cargo doc` outputs are clickable on supported terminals, controllable through `term.hyperlinks` config value. [#12889](https://github.com/rust-lang/cargo/pull/12889) - Print environment variables for build script executions with `-vv`. [#12829](https://github.com/rust-lang/cargo/pull/12829) - cargo-new: add new packages to [workspace.members] automatically. [#12779](https://github.com/rust-lang/cargo/pull/12779) - cargo-doc: print a new `Generated` status displaying the full path. [#12859](https://github.com/rust-lang/cargo/pull/12859) ### Changed - cargo-new: warn if crate name doesn't follow snake_case or kebab-case. [#12766](https://github.com/rust-lang/cargo/pull/12766) - cargo-install: clarify the arg `` to install is positional. [#12841](https://github.com/rust-lang/cargo/pull/12841) - cargo-install: Suggest an alternative version on MSRV failure. [#12798](https://github.com/rust-lang/cargo/pull/12798) - cargo-install: reports more detailed SemVer errors. [#12924](https://github.com/rust-lang/cargo/pull/12924) - cargo-install: install only once if there are crates duplicated. [#12868](https://github.com/rust-lang/cargo/pull/12868) - cargo-remove: Clarify flag behavior of different dependency kinds. [#12823](https://github.com/rust-lang/cargo/pull/12823) - cargo-remove: suggest the dependency to remove exists only in the other section. [#12865](https://github.com/rust-lang/cargo/pull/12865) - cargo-update: Do not call it "Downgrading" when difference is only build metadata. [#12796](https://github.com/rust-lang/cargo/pull/12796) - Enhanced help text to clarify `--test` flag is for Cargo targets, not test functions. [#12915](https://github.com/rust-lang/cargo/pull/12915) - Included package name/version in build script warnings. [#12799](https://github.com/rust-lang/cargo/pull/12799) - Provide next steps for bad -Z flag. [#12857](https://github.com/rust-lang/cargo/pull/12857) - Suggest `cargo search` when `cargo-` cannot be found. [#12840](https://github.com/rust-lang/cargo/pull/12840) - Do not allow empty feature name. [#12928](https://github.com/rust-lang/cargo/pull/12928) - Added unsupported short flag suggestion for `--target` and `--exclude` flags. [#12805](https://github.com/rust-lang/cargo/pull/12805) - Added unsupported short flag suggestion for `--out-dir` flag. [#12755](https://github.com/rust-lang/cargo/pull/12755) - Added unsupported lowercase `-z` flag suggestion for `-Z` flag. [#12788](https://github.com/rust-lang/cargo/pull/12788) - Added better suggestion for unsupported `--path` flag. [#12811](https://github.com/rust-lang/cargo/pull/12811) - Added detailed message when target directory path is invalid. [#12820](https://github.com/rust-lang/cargo/pull/12820) ### Fixed - Fixed corruption when cargo was killed while writing to files. [#12744](https://github.com/rust-lang/cargo/pull/12744) - cargo-add: Preserve more comments [#12838](https://github.com/rust-lang/cargo/pull/12838) - cargo-fix: preserve jobserver file descriptors on rustc invocation. [#12951](https://github.com/rust-lang/cargo/pull/12951) - cargo-remove: Preserve feature comments [#12837](https://github.com/rust-lang/cargo/pull/12837) - Removed unnecessary backslash in timings HTML report when error happens. [#12934](https://github.com/rust-lang/cargo/pull/12934) - Fixed error message that invalid a feature name can contain `-`. [#12939](https://github.com/rust-lang/cargo/pull/12939) - When there's a version of a dependency in the lockfile, Cargo would use that "exact" version, including the build metadata. [#12772](https://github.com/rust-lang/cargo/pull/12772) ### Nightly only - Added `Edition2024` unstable feature. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#edition-2024) [#12771](https://github.com/rust-lang/cargo/pull/12771) - πŸ”₯ The `-Ztrim-paths` feature adds a new profile setting to control how paths are sanitized in the resulting binary. ([RFC 3127](https://github.com/rust-lang/rfcs/blob/master/text/3127-trim-paths.md)) ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#profile-trim-paths-option)) [#12625](https://github.com/rust-lang/cargo/pull/12625) [#12900](https://github.com/rust-lang/cargo/pull/12900) [#12908](https://github.com/rust-lang/cargo/pull/12908) - `-Zcheck-cfg`: Adjusted for new rustc syntax and behavior. [#12845](https://github.com/rust-lang/cargo/pull/12845) - `-Zcheck-cfg`: Remove outdated option to `-Zcheck-cfg` warnings. [#12884](https://github.com/rust-lang/cargo/pull/12884) - `public-dependency`: Support `public` dependency configuration with workspace deps. [#12817](https://github.com/rust-lang/cargo/pull/12817) ### Documentation - profile: add missing `strip` info. [#12754](https://github.com/rust-lang/cargo/pull/12754) - features: a note about the new limit on number of features. [#12913](https://github.com/rust-lang/cargo/pull/12913) - crates-io: Add doc comment for `NewCrate` struct. [#12782](https://github.com/rust-lang/cargo/pull/12782) - resolver: Highlight commands to answer dep resolution questions. [#12903](https://github.com/rust-lang/cargo/pull/12903) - cargo-bench: `--bench` is passed in unconditionally to bench harnesses. [#12850](https://github.com/rust-lang/cargo/pull/12850) - cargo-login: mention args after `--` in manpage. [#12832](https://github.com/rust-lang/cargo/pull/12832) - cargo-vendor: clarify config to use vendored source is printed to stdout [#12893](https://github.com/rust-lang/cargo/pull/12893) - manifest: update to SPDX 2.3 license expression and 3.20 license list. [#12827](https://github.com/rust-lang/cargo/pull/12827) - contrib: Policy on manifest editing [#12836](https://github.com/rust-lang/cargo/pull/12836) - contrib: use `AND` search terms in mdbook search and fixed broken links. [#12812](https://github.com/rust-lang/cargo/pull/12812) [#12813](https://github.com/rust-lang/cargo/pull/12813) [#12814](https://github.com/rust-lang/cargo/pull/12814) - contrib: Describe how to add a new package [#12878](https://github.com/rust-lang/cargo/pull/12878) - contrib: Removed review capacity notice. [#12842](https://github.com/rust-lang/cargo/pull/12842) ### Internal - Updated to `itertools` 0.11.0. [#12759](https://github.com/rust-lang/cargo/pull/12759) - Updated to `cargo_metadata` 0.18.0. [#12758](https://github.com/rust-lang/cargo/pull/12758) - Updated to `curl-sys` 0.4.68, which corresponds to curl 8.4.0. [#12808](https://github.com/rust-lang/cargo/pull/12808) - Updated to `toml` 0.8.2. [#12760](https://github.com/rust-lang/cargo/pull/12760) - Updated to `toml_edit` 0.20.2. [#12761](https://github.com/rust-lang/cargo/pull/12761) - Updated to `gix` to 0.55.2 [#12906](https://github.com/rust-lang/cargo/pull/12906) - Disabled the `custom_target::custom_bin_target` test on windows-gnu. [#12763](https://github.com/rust-lang/cargo/pull/12763) - Refactored `Cargo.toml` parsing code in preparation of extracting an official schema API. [#12768](https://github.com/rust-lang/cargo/pull/12768) [#12881](https://github.com/rust-lang/cargo/pull/12881) [#12902](https://github.com/rust-lang/cargo/pull/12902) [#12911](https://github.com/rust-lang/cargo/pull/12911) [#12948](https://github.com/rust-lang/cargo/pull/12948) - Split out SemVer logic to its own module. [#12926](https://github.com/rust-lang/cargo/pull/12926) [#12940](https://github.com/rust-lang/cargo/pull/12940) - source: Prepare for new `PackageIDSpec` syntax [#12938](https://github.com/rust-lang/cargo/pull/12938) - resolver: Consolidate logic in `VersionPreferences` [#12930](https://github.com/rust-lang/cargo/pull/12930) - Make the `SourceId::precise` field an Enum. [#12849](https://github.com/rust-lang/cargo/pull/12849) - shell: Write at once rather than in fragments. [#12880](https://github.com/rust-lang/cargo/pull/12880) - Move up looking at index summary enum [#12749](https://github.com/rust-lang/cargo/pull/12749) [#12923](https://github.com/rust-lang/cargo/pull/12923) - Generate redirection HTML pages in CI for Cargo Contributor Guide. [#12846](https://github.com/rust-lang/cargo/pull/12846) - Add new package cache lock modes. [#12706](https://github.com/rust-lang/cargo/pull/12706) - Add regression test for issue 6915: features and transitive dev deps. [#12907](https://github.com/rust-lang/cargo/pull/12907) - Auto-labeling when PR review state changes. [#12856](https://github.com/rust-lang/cargo/pull/12856) - credential: include license files in all published crates. [#12953](https://github.com/rust-lang/cargo/pull/12953) - credential: Filter `cargo-credential-*` dependencies by OS. [#12949](https://github.com/rust-lang/cargo/pull/12949) - ci: bump cargo-semver-checks to 0.24.0 [#12795](https://github.com/rust-lang/cargo/pull/12795) - ci: set and verify all MSRVs for Cargo's crates automatically. [#12767](https://github.com/rust-lang/cargo/pull/12767) [#12654](https://github.com/rust-lang/cargo/pull/12654) - ci: use separate concurrency group for publishing Cargo Contributor Book. [#12834](https://github.com/rust-lang/cargo/pull/12834) [#12835](https://github.com/rust-lang/cargo/pull/12835) - ci: update `actions/checkout` action to v4 [#12762](https://github.com/rust-lang/cargo/pull/12762) - cargo-search: improved the margin calculation for the output. [#12890](https://github.com/rust-lang/cargo/pull/12890) ## Cargo 1.74 (2023-11-16) [80eca0e5...rust-1.74.0](https://github.com/rust-lang/cargo/compare/80eca0e5...rust-1.74.0) ### Added - πŸŽ‰ The `[lints]` table has been stabilized, allowing you to configure reporting levels for rustc and other tool lints in `Cargo.toml`. ([RFC 3389](https://github.com/rust-lang/rfcs/blob/master/text/3389-manifest-lint.md)) ([docs](https://doc.rust-lang.org/nightly/cargo/reference/manifest.html#the-lints-section)) [#12584](https://github.com/rust-lang/cargo/pull/12584) [#12648](https://github.com/rust-lang/cargo/pull/12648) - πŸŽ‰ The unstable features `credential-process` and `registry-auth` have been stabilized. These features consolidate the way to authenticate with private registries. ([RFC 2730](https://github.com/rust-lang/rfcs/blob/master/text/2730-cargo-token-from-process.md)) ([RFC 3139](https://github.com/rust-lang/rfcs/blob/master/text/3139-cargo-alternative-registry-auth.md)) ([docs](https://doc.rust-lang.org/nightly/cargo/reference/registry-authentication.html)) [#12590](https://github.com/rust-lang/cargo/pull/12590) [#12622](https://github.com/rust-lang/cargo/pull/12622) [#12623](https://github.com/rust-lang/cargo/pull/12623) [#12626](https://github.com/rust-lang/cargo/pull/12626) [#12641](https://github.com/rust-lang/cargo/pull/12641) [#12644](https://github.com/rust-lang/cargo/pull/12644) [#12649](https://github.com/rust-lang/cargo/pull/12649) [#12671](https://github.com/rust-lang/cargo/pull/12671) [#12709](https://github.com/rust-lang/cargo/pull/12709) Notable changes: - Introducing a new protocol for both external and built-in providers to store and retrieve credentials for registry authentication. - Adding the `auth-required` field in the registry index's `config.json`, enabling authenticated sparse index, crate downloads, and search API. - For using alternative registries with authentication, a credential provider must be configured to avoid unknowingly storing unencrypted credentials on disk. - These settings can be configured in `[registry]` and `[registries]` tables. - πŸŽ‰ `--keep-going` flag has been stabilized and is now available in each build command (except `bench` and `test`, which have `--no-fail-fast` instead). ([docs](https://doc.rust-lang.org/cargo/commands/cargo-build.html#option-cargo-build---keep-going)) [#12568](https://github.com/rust-lang/cargo/pull/12568) - Added `--dry-run` flag and summary line at the end for `cargo clean`. [#12638](https://github.com/rust-lang/cargo/pull/12638) - Added a short alias `-n` for cli option `--dry-run`. [#12660](https://github.com/rust-lang/cargo/pull/12660) - Added support for `target.'cfg(..)'.linker`. [#12535](https://github.com/rust-lang/cargo/pull/12535) - Allowed incomplete versions when they are unambiguous for flags like `--package`. [#12591](https://github.com/rust-lang/cargo/pull/12591) [#12614](https://github.com/rust-lang/cargo/pull/12614) [#12806](https://github.com/rust-lang/cargo/pull/12806) ### Changed - ❗️ Changed how arrays in configuration are merged. The order was unspecified and now follows how other configuration types work for consistency. [summary](https://blog.rust-lang.org/inside-rust/2023/08/24/cargo-config-merging.html) [#12515](https://github.com/rust-lang/cargo/pull/12515) - ❗️ cargo-clean: error out if `--doc` is mixed with `-p`. [#12637](https://github.com/rust-lang/cargo/pull/12637) - ❗ cargo-new / cargo-init no longer exclude `Cargo.lock` in VCS ignore files for libraries. [#12382](https://github.com/rust-lang/cargo/pull/12382) - cargo-update: silently deprecate `--aggressive` in favor of the new `--recursive`. [#12544](https://github.com/rust-lang/cargo/pull/12544) - cargo-update: `-p/--package` can be used as a positional argument. [#12545](https://github.com/rust-lang/cargo/pull/12545) [#12586](https://github.com/rust-lang/cargo/pull/12586) - cargo-install: suggest `--git` when the package name looks like a URL. [#12575](https://github.com/rust-lang/cargo/pull/12575) - cargo-add: summarize the feature list when it's too long. [#12662](https://github.com/rust-lang/cargo/pull/12662) [#12702](https://github.com/rust-lang/cargo/pull/12702) - Shell completion for `--target` uses rustup but falls back to rustc. [#12606](https://github.com/rust-lang/cargo/pull/12606) - Help users know possible `--target` values. [#12607](https://github.com/rust-lang/cargo/pull/12607) - Enhanced "registry index not found" error message. [#12732](https://github.com/rust-lang/cargo/pull/12732) - Enhanced CLI help message of `--explain`. [#12592](https://github.com/rust-lang/cargo/pull/12592) - Enhanced deserialization errors of untagged enums with `serde-untagged`. [#12574](https://github.com/rust-lang/cargo/pull/12574) [#12581](https://github.com/rust-lang/cargo/pull/12581) - Enhanced the error when mismatching prerelease version candidates. [#12659](https://github.com/rust-lang/cargo/pull/12659) - Enhanced the suggestion on ambiguous Package ID spec. [#12685](https://github.com/rust-lang/cargo/pull/12685) - Enhanced TOML parse errors to show the context. [#12556](https://github.com/rust-lang/cargo/pull/12556) - Enhanced filesystem error by adding wrappers around `std::fs::metadata`. [#12636](https://github.com/rust-lang/cargo/pull/12636) - Enhanced resolver version mismatch warning. [#12573](https://github.com/rust-lang/cargo/pull/12573) - Use clap to suggest alternative argument for unsupported arguments. [#12529](https://github.com/rust-lang/cargo/pull/12529) [#12693](https://github.com/rust-lang/cargo/pull/12693) [#12723](https://github.com/rust-lang/cargo/pull/12723) - Removed redundant information from cargo new/init `--help` output. [#12594](https://github.com/rust-lang/cargo/pull/12594) - Console output and styling tweaks. [#12578](https://github.com/rust-lang/cargo/pull/12578) [#12655](https://github.com/rust-lang/cargo/pull/12655) [#12593](https://github.com/rust-lang/cargo/pull/12593) ### Fixed - Use full target spec for `cargo rustc --print --target`. [#12743](https://github.com/rust-lang/cargo/pull/12743) - Copy PDBs also for EFI targets. [#12688](https://github.com/rust-lang/cargo/pull/12688) - Fixed resolver behavior being independent of package order. [#12602](https://github.com/rust-lang/cargo/pull/12602) - Fixed unnecessary clean up of `profile.release.package."*"` for `cargo remove`. [#12624](https://github.com/rust-lang/cargo/pull/12624) ### Nightly only - `-Zasymmetric-token`: Created dedicated unstable flag for asymmetric-token support. [#12551](https://github.com/rust-lang/cargo/pull/12551) - `-Zasymmetric-token`: Improved logout message for asymmetric tokens. [#12587](https://github.com/rust-lang/cargo/pull/12587) - `-Zmsrv-policy`: **Very** preliminary MSRV resolver support. [#12560](https://github.com/rust-lang/cargo/pull/12560) - `-Zscript`: Hack in code fence support. [#12681](https://github.com/rust-lang/cargo/pull/12681) - `-Zbindeps`: Support dependencies from registries. [#12421](https://github.com/rust-lang/cargo/pull/12421) ### Documentation - ❗ Policy change: Checking `Cargo.lock` into version control is now the default choice, even for libraries. Lockfile and CI integration documentations are also expanded. [Policy docs](https://doc.rust-lang.org/nightly/cargo/faq.html#why-have-cargolock-in-version-control), [Lockfile docs](https://doc.rust-lang.org/nightly/cargo/guide/cargo-toml-vs-cargo-lock.html), [CI docs](https://doc.rust-lang.org/nightly/cargo/guide/continuous-integration.html), [#12382](https://github.com/rust-lang/cargo/pull/12382) [#12630](https://github.com/rust-lang/cargo/pull/12630) - SemVer: Update documentation about removing optional dependencies. [#12687](https://github.com/rust-lang/cargo/pull/12687) - Contrib: Add process for security responses. [#12487](https://github.com/rust-lang/cargo/pull/12487) - cargo-publish: warn about upload timeout. [#12733](https://github.com/rust-lang/cargo/pull/12733) - mdbook: use *AND* search when having multiple terms. [#12548](https://github.com/rust-lang/cargo/pull/12548) - Established publish best practices [#12745](https://github.com/rust-lang/cargo/pull/12745) - Clarify caret requirements. [#12679](https://github.com/rust-lang/cargo/pull/12679) - Clarify how `version` works for `git` dependencies. [#12270](https://github.com/rust-lang/cargo/pull/12270) - Clarify and differentiate defaults for split-debuginfo. [#12680](https://github.com/rust-lang/cargo/pull/12680) - Added missing `strip` entries in `dev` and `release` profiles. [#12748](https://github.com/rust-lang/cargo/pull/12748) ### Internal - Updated to `curl-sys` 0.4.66, which corresponds to curl 8.3.0. [#12718](https://github.com/rust-lang/cargo/pull/12718) - Updated to `gitoxide` 0.54.1. [#12731](https://github.com/rust-lang/cargo/pull/12731) - Updated to `git2` 0.18.0, which corresponds to libgit2 1.7.1. [#12580](https://github.com/rust-lang/cargo/pull/12580) - Updated to `cargo_metadata` 0.17.0. [#12758](https://github.com/rust-lang/cargo/pull/12610) - Updated target-arch-aware crates to support mips r6 targets [#12720](https://github.com/rust-lang/cargo/pull/12720) - publish.py: Remove obsolete `sleep()` calls. [#12686](https://github.com/rust-lang/cargo/pull/12686) - Define `{{command}}` for use in src/doc/man/includes [#12570](https://github.com/rust-lang/cargo/pull/12570) - Set tracing target `network` for networking messages. [#12582](https://github.com/rust-lang/cargo/pull/12582) - cargo-test-support: Add `with_stdout_unordered`. [#12635](https://github.com/rust-lang/cargo/pull/12635) - dep: Switch from `termcolor` to `anstream`. [#12751](https://github.com/rust-lang/cargo/pull/12751) - Put `Source` trait under `cargo::sources`. [#12527](https://github.com/rust-lang/cargo/pull/12527) - SourceId: merge `name` and `alt_registry_key` into one enum. [#12675](https://github.com/rust-lang/cargo/pull/12675) - TomlManifest: fail when package_root is not a directory. [#12722](https://github.com/rust-lang/cargo/pull/12722) - util: enhanced doc of `network::retry` doc. [#12583](https://github.com/rust-lang/cargo/pull/12583) - refactor: Pull out cargo-add MSRV code for reuse [#12553](https://github.com/rust-lang/cargo/pull/12553) - refactor(install): Move value parsing to clap [#12547](https://github.com/rust-lang/cargo/pull/12547) - Fixed spurious errors with networking tests. [#12726](https://github.com/rust-lang/cargo/pull/12726) - Use a more compact relative-time format for `CARGO_LOG` internal logging. [#12542](https://github.com/rust-lang/cargo/pull/12542) - Use newer std API for cleaner code. [#12559](https://github.com/rust-lang/cargo/pull/12559) [#12604](https://github.com/rust-lang/cargo/pull/12604) [#12615](https://github.com/rust-lang/cargo/pull/12615) [#12631](https://github.com/rust-lang/cargo/pull/12631) - Buffer console status messages. [#12727](https://github.com/rust-lang/cargo/pull/12727) - Use enum to describe index summaries to provide a richer information when summaries are not available for resolution. [#12643](https://github.com/rust-lang/cargo/pull/12643) - Use shortest path for resolving the path from the given dependency up to the root. [#12678](https://github.com/rust-lang/cargo/pull/12678) - Read/write the encoded `cargo update --precise` in the same place [#12629](https://github.com/rust-lang/cargo/pull/12629) - Set MSRV for internal packages. [#12381](https://github.com/rust-lang/cargo/pull/12381) - ci: Update Renovate schema [#12741](https://github.com/rust-lang/cargo/pull/12741) - ci: Ignore patch version in MSRV [#12716](https://github.com/rust-lang/cargo/pull/12716) ## Cargo 1.73 (2023-10-05) [45782b6b...rust-1.73.0](https://github.com/rust-lang/cargo/compare/45782b6b...rust-1.73.0) ### Added - Print environment variables for `cargo run/bench/test` in extra verbose mode `-vv`. [#12498](https://github.com/rust-lang/cargo/pull/12498) - Display package versions on Cargo timings graph. [#12420](https://github.com/rust-lang/cargo/pull/12420) ### Changed - ❗️ Cargo now bails out when using `cargo::` in custom build scripts. This is a preparation for an upcoming change in build script invocations. [#12332](https://github.com/rust-lang/cargo/pull/12332) - ❗️ `cargo login` no longer accept any token after the `--` syntax. Arguments after `--` are now reserved in the preparation of the new credential provider feature. This introduces a regression that overlooks the `cargo login -- ` support in previous versions. [#12499](https://github.com/rust-lang/cargo/pull/12499) - Make Cargo `--help` easier to browse. [#11905](https://github.com/rust-lang/cargo/pull/11905) - Prompt the use of `--nocapture` flag if `cargo test` process is terminated via a signal. [#12463](https://github.com/rust-lang/cargo/pull/12463) - Preserve jobserver file descriptors on the rustc invocation for getting target information. [#12447](https://github.com/rust-lang/cargo/pull/12447) - Clarify in `--help` that `cargo test --all-targets` excludes doctests. [#12422](https://github.com/rust-lang/cargo/pull/12422) - Normalize `cargo.toml` to `Cargo.toml` on publish, and warn on other cases of `Cargo.toml`. [#12399](https://github.com/rust-lang/cargo/pull/12399) ### Fixed - Only skip mtime check on `~/.cargo/{git,registry}`. [#12369](https://github.com/rust-lang/cargo/pull/12369) - Fixed `cargo doc --open` crash on WSL2. [#12373](https://github.com/rust-lang/cargo/pull/12373) - Fixed panic when enabling `http.debug` for certain strings. [#12468](https://github.com/rust-lang/cargo/pull/12468) - Fixed `cargo remove` incorrectly removing used patches. [#12454](https://github.com/rust-lang/cargo/pull/12454) - Fixed crate checksum lookup query should match on semver build metadata. [#11447](https://github.com/rust-lang/cargo/pull/11447) - Fixed printing multiple warning messages for unused fields in `[registries]` table. [#12439](https://github.com/rust-lang/cargo/pull/12439) ### Nightly only - πŸ”₯ The `-Zcredential-process` has been reimplemented with a clearer way to communicate with different credential providers. Several built-in providers are also added to Cargo. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process) [#12334](https://github.com/rust-lang/cargo/pull/12334) [#12396](https://github.com/rust-lang/cargo/pull/12396) [#12424](https://github.com/rust-lang/cargo/pull/12424) [#12440](https://github.com/rust-lang/cargo/pull/12440) [#12461](https://github.com/rust-lang/cargo/pull/12461) [#12469](https://github.com/rust-lang/cargo/pull/12469) [#12483](https://github.com/rust-lang/cargo/pull/12483) [#12499](https://github.com/rust-lang/cargo/pull/12499) [#12507](https://github.com/rust-lang/cargo/pull/12507) [#12512](https://github.com/rust-lang/cargo/pull/12512) [#12518](https://github.com/rust-lang/cargo/pull/12518) [#12521](https://github.com/rust-lang/cargo/pull/12521) [#12526](https://github.com/rust-lang/cargo/pull/12526) Some notable changes: - Renamed `credential-process` to `credential-provider` in Cargo configurations. - New JSON protocol for communicating with external credential providers via stdin/stdout. - The GNOME Secert provider now dynamically loads `libsecert`. - The 1password provider is no longer built-in. - Changed the unstable key for asymmetric tokens from `registry-auth` to `credential-process`. - ❗️ Removed `--keep-going` flag support from `cargo test` and `cargo bench`. [#12478](https://github.com/rust-lang/cargo/pull/12478) [#12492](https://github.com/rust-lang/cargo/pull/12492) - Fixed invalid package names generated by `-Zscript`. [#12349](https://github.com/rust-lang/cargo/pull/12349) - `-Zscript` now errors out on unsupported commands β€” `publish` and `package`. [#12350](https://github.com/rust-lang/cargo/pull/12350) - Encode URL params correctly for source ID in Cargo.lock. [#12280](https://github.com/rust-lang/cargo/pull/12280) - Replaced invalid `panic_unwind` std feature with `panic-unwind`. [#12364](https://github.com/rust-lang/cargo/pull/12364) - `-Zlints`: doctest extraction should respect `[lints]`. [#12501](https://github.com/rust-lang/cargo/pull/12501) ### Documentation - SemVer: Adding a section for changing the alignment, layout, or size of a well-defined type. [#12169](https://github.com/rust-lang/cargo/pull/12169) - Use heading attributes to control the fragment. [#12339](https://github.com/rust-lang/cargo/pull/12339) - Use "number" instead of "digit" when explaining Cargo's use of semver. [#12340](https://github.com/rust-lang/cargo/pull/12340) - contrib: Add some more detail about how publishing works. [#12344](https://github.com/rust-lang/cargo/pull/12344) - Clarify "Package ID" and "Source ID" in `cargo metadata` are opaque strings. [#12313](https://github.com/rust-lang/cargo/pull/12313) - Clarify that `rerun-if-env-changed` doesn't monitor the environment variables it set for crates and build script. [#12482](https://github.com/rust-lang/cargo/pull/12482) - Clarify that multiple versions that differ only in the metadata tag are disallowed on crates.io. [#12335](https://github.com/rust-lang/cargo/pull/12335) - Clarify `lto` setting passing `-Clinker-plugin-lto`. [#12407](https://github.com/rust-lang/cargo/pull/12407) - Added `profile.strip` to configuration and environment variable docs. [#12337](https://github.com/rust-lang/cargo/pull/12337) [#12408](https://github.com/rust-lang/cargo/pull/12408) - Added docs for artifact JSON debuginfo levels. [#12376](https://github.com/rust-lang/cargo/pull/12376) - Added a notice for the backward compatible `.cargo/credential` file existence. [#12479](https://github.com/rust-lang/cargo/pull/12479) - Raised the awareness of `resolver = 2` used inside workspaces. [#12388](https://github.com/rust-lang/cargo/pull/12388) - Replaced `master` branch by default branch in documentation. [#12435](https://github.com/rust-lang/cargo/pull/12435) ### Internal - Updated to `criterion` 0.5.1. [#12338](https://github.com/rust-lang/cargo/pull/12338) - Updated to `curl-sys` 0.4.65, which corresponds to curl 8.2.1. [#12406](https://github.com/rust-lang/cargo/pull/12406) - Updated to `indexmap` v2. [#12368](https://github.com/rust-lang/cargo/pull/12368) - Updated to `miow` 0.6.0, which drops old versions of `windows-sys`. [#12453](https://github.com/rust-lang/cargo/pull/12453) - ci: automatically test new packages by using `--workspace`. [#12342](https://github.com/rust-lang/cargo/pull/12342) - ci: automatically update dependencies monthly with Renovate. [#12341](https://github.com/rust-lang/cargo/pull/12341) [#12466](https://github.com/rust-lang/cargo/pull/12466) - ci: rewrote `xtask-bump-check` for respecting semver by adopting `cargo-semver-checks`. [#12395](https://github.com/rust-lang/cargo/pull/12395) [#12513](https://github.com/rust-lang/cargo/pull/12513) [#12508](https://github.com/rust-lang/cargo/pull/12508) - Rearranged and renamed test directories [#12397](https://github.com/rust-lang/cargo/pull/12397) [#12398](https://github.com/rust-lang/cargo/pull/12398) - Migrated from `log` to `tracing`. [#12458](https://github.com/rust-lang/cargo/pull/12458) [#12488](https://github.com/rust-lang/cargo/pull/12488) - Track `--help` output in tests. [#11912](https://github.com/rust-lang/cargo/pull/11912) - Cleaned up and shared package metadata within workspace. [#12352](https://github.com/rust-lang/cargo/pull/12352) - `crates-io`: expose HTTP headers and `Error` type. [#12310](https://github.com/rust-lang/cargo/pull/12310) - For `cargo update`, caught CLI flags conflict between `--aggressive` and `--precise` in clap. [#12428](https://github.com/rust-lang/cargo/pull/12428) - Several fixes for either making Cargo testsuite pass on nightly or in `rust-lang/rust`. [#12413](https://github.com/rust-lang/cargo/pull/12413) [#12416](https://github.com/rust-lang/cargo/pull/12416) [#12429](https://github.com/rust-lang/cargo/pull/12429) [#12450](https://github.com/rust-lang/cargo/pull/12450) [#12491](https://github.com/rust-lang/cargo/pull/12491) [#12500](https://github.com/rust-lang/cargo/pull/12500) ## Cargo 1.72 (2023-08-24) [64fb38c9...rust-1.72.0](https://github.com/rust-lang/cargo/compare/64fb38c9...rust-1.72.0) ### Added - ❗ Enable `-Zdoctest-in-workspace` by default. When running each documentation test, the working directory is set to the root directory of the package the test belongs to. [docs](https://doc.rust-lang.org/nightly/cargo/commands/cargo-test.html#working-directory-of-tests) [#12221](https://github.com/rust-lang/cargo/pull/12221) [#12288](https://github.com/rust-lang/cargo/pull/12288) - 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 - 🚨 [CVE-2023-40030](https://github.com/rust-lang/cargo/security/advisories/GHSA-wrrj-h57r-vx9p): Malicious dependencies can inject arbitrary JavaScript into cargo-generated timing reports. To mitigate this, feature name validation check is now turned into a hard error. The warning was added in Rust 1.49. These extended characters aren't allowed on crates.io, so this should only impact users of other registries, or people who don't publish to a registry. [#12291](https://github.com/rust-lang/cargo/pull/12291) - 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) - Respect scp-like URL as much as possible when fetching nested submodules. [#12359](https://github.com/rust-lang/cargo/pull/12359) [#12411](https://github.com/rust-lang/cargo/pull/12411) ### 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) [#12255](https://github.com/rust-lang/cargo/pull/12255) [#12258](https://github.com/rust-lang/cargo/pull/12258) [#12262](https://github.com/rust-lang/cargo/pull/12262) [#12268](https://github.com/rust-lang/cargo/pull/12268) [#12269](https://github.com/rust-lang/cargo/pull/12269) [#12281](https://github.com/rust-lang/cargo/pull/12281) [#12282](https://github.com/rust-lang/cargo/pull/12282) [#12283](https://github.com/rust-lang/cargo/pull/12283) [#12284](https://github.com/rust-lang/cargo/pull/12284) [#12287](https://github.com/rust-lang/cargo/pull/12287) [#12289](https://github.com/rust-lang/cargo/pull/12289) [#12303](https://github.com/rust-lang/cargo/pull/12303) [#12305](https://github.com/rust-lang/cargo/pull/12305) [#12308](https://github.com/rust-lang/cargo/pull/12308) - Automatically inherit workspace lints when running `cargo new`/`cargo init`. [#12174](https://github.com/rust-lang/cargo/pull/12174) - Removed `-Zjobserver-per-rustc` again. [#12285](https://github.com/rust-lang/cargo/pull/12285) - Added `.toml` file extension restriction for `-Zconfig-include`. [#12298](https://github.com/rust-lang/cargo/pull/12298) - Added `-Znext-lockfile-bump` to prepare for the next lockfile bump. [#12279](https://github.com/rust-lang/cargo/pull/12279) [#12302](https://github.com/rust-lang/cargo/pull/12302) ### 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) - Added more documentation for `Source` download functions. [#12319](https://github.com/rust-lang/cargo/pull/12319) - Added READMEs for the credential helpers. [#12322](https://github.com/rust-lang/cargo/pull/12322) - Fixed version requirement example in Dependency Resolution. [#12267](https://github.com/rust-lang/cargo/pull/12267) - Clarify the default behavior of cargo-install. [#12276](https://github.com/rust-lang/cargo/pull/12276) - Clarify the use of "default" branch instead of `main` by default. [#12251](https://github.com/rust-lang/cargo/pull/12251) - Provide guidance on version requirements. [#12323](https://github.com/rust-lang/cargo/pull/12323) ### 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) - Updated to `openssl` 0.10.55. [#12300](https://github.com/rust-lang/cargo/pull/12300) - Updated several dependencies. [#12261](https://github.com/rust-lang/cargo/pull/12261) - 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) - Switched to `OnceLock` for interning uses. [#12217](https://github.com/rust-lang/cargo/pull/12217) - Removed a unnecessary `.clone`. [#12213](https://github.com/rust-lang/cargo/pull/12213) - Don't try to compile `cargo-credential-gnome-secret` on non-Linux platforms. [#12321](https://github.com/rust-lang/cargo/pull/12321) - Use macro to remove duplication of workspace inheritable fields getters. [#12317](https://github.com/rust-lang/cargo/pull/12317) - Extracted and rearranged registry API items to their own modules. [#12290](https://github.com/rust-lang/cargo/pull/12290) - Show a better error when container tests fail. [#12264](https://github.com/rust-lang/cargo/pull/12264) ## Cargo 1.71.1 (2023-08-03) ### Fixed - 🚨 [CVE-2023-38497](https://github.com/rust-lang/cargo/security/advisories/GHSA-j3xp-wfr4-hx87): Cargo 1.71.1 or later respects umask when extracting crate archives. It also purges the caches it tries to access if they were generated by older Cargo versions. ## Cargo 1.71 (2023-07-13) [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) - 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` pointing a rustup proxy, it'll try bypassing the proxy and use the underlying binary directly. There are assumptions around the interaction with rustup and `RUSTUP_TOOLCHAIN`. However, it's not expected to affect normal users. [#11917](https://github.com/rust-lang/cargo/pull/11917) - ❗ When querying a package, Cargo tries only the original name, all hyphens, and all underscores to handle misspellings. Previously, Cargo tried each combination of hyphens and underscores, causing excessive requests to crates.io. [#12083](https://github.com/rust-lang/cargo/pull/12083) - ❗ Disallow `RUSTUP_HOME` and `RUSTUP_TOOLCHAIN` in the `[env]` configuration table. This is considered to be not a use case Cargo would like to support, since it will likely cause problems or lead to confusion. [#12101](https://github.com/rust-lang/cargo/pull/12101) [#12107](https://github.com/rust-lang/cargo/pull/12107) - Better error message when getting an empty dependency table in Cargo.toml. [#11997](https://github.com/rust-lang/cargo/pull/11997) - 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) - `cargo add` now considers `rust-version` when selecting packages with `-Zmsrv-policy`. [#12078](https://github.com/rust-lang/cargo/pull/12078) ### 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: changing 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 - 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) [#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) ### Added - πŸŽ‰ Added `cargo logout` command for removing an API token from the registry locally. [docs](https://doc.rust-lang.org/nightly/cargo/commands/cargo-logout.html) [#11919](https://github.com/rust-lang/cargo/pull/11919) [#11950](https://github.com/rust-lang/cargo/pull/11950) - Added `--ignore-rust-version` flag to `cargo install`. [#11859](https://github.com/rust-lang/cargo/pull/11859) - The `CARGO_PKG_README` environment variable is now set to the path to the README file when compiling a crate. [#11645](https://github.com/rust-lang/cargo/pull/11645) - Cargo now displays richer information of Cargo target failed to compile. [#11636](https://github.com/rust-lang/cargo/pull/11636) ### Changed - πŸŽ‰ The `sparse` protocol is now the default protocol for crates.io! ([RFC 2789](https://github.com/rust-lang/rfcs/blob/master/text/2789-sparse-index.md)) ([docs](https://doc.rust-lang.org/nightly/cargo/reference/registries.html#registry-protocols)) [#11791](https://github.com/rust-lang/cargo/pull/11791) [#11783](https://github.com/rust-lang/cargo/pull/11783) - ❗ `cargo login` and `cargo logout` now uses the registry specified in `registry.default`. This was an unintentional regression. [#11949](https://github.com/rust-lang/cargo/pull/11949) - `cargo update` accurately shows `Downgrading` status when downgrading dependencies. [#11839](https://github.com/rust-lang/cargo/pull/11839) - Added more information to HTTP errors to help with debugging. [#11878](https://github.com/rust-lang/cargo/pull/11878) - Added delays to network retries in Cargo. [#11881](https://github.com/rust-lang/cargo/pull/11881) - Refined `cargo 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. [#11835](https://github.com/rust-lang/cargo/pull/11835) ### Fixed - Removed duplicates of possible values in `--charset` option of `cargo tree`. [#11785](https://github.com/rust-lang/cargo/pull/11785) - Fixed `CARGO_CFG_` vars for configs defined both with and without value. [#11790](https://github.com/rust-lang/cargo/pull/11790) - Broke endless loop on cyclic features in added dependency in `cargo add`. [#11805](https://github.com/rust-lang/cargo/pull/11805) - Don't panic when [`patch`] involved in dependency resolution results in a conflict. [#11770](https://github.com/rust-lang/cargo/pull/11770) - Fixed credential token format validation. [#11951](https://github.com/rust-lang/cargo/pull/11951) - Added the missing token format validation on publish. [#11952](https://github.com/rust-lang/cargo/pull/11952) - Fixed case mismatches when looking up env vars in the Config snapshot. [#11824](https://github.com/rust-lang/cargo/pull/11824) - `cargo new` generates the correct `.hgignore` aligning semantics with other VCS ignore files. [#11855](https://github.com/rust-lang/cargo/pull/11855) - Stopped doing unnecessary fuzzy registry index queries. This significantly reduces the amount of HTTP requests to remote registries for crates containing `-` or `_` in their names. [#11936](https://github.com/rust-lang/cargo/pull/11936) [#11937](https://github.com/rust-lang/cargo/pull/11937) ### Nightly only - Added `-Zdirect-minimal-versions`. This behaves like `-Zminimal-versions` but only for direct dependencies. ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#direct-minimal-versions)) [#11688](https://github.com/rust-lang/cargo/pull/11688) - Added `-Zgitoxide` which switches all `git fetch` operation in Cargo to use `gitoxide` crate. This is still an MVP but could improve the performance up to 2 times. ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html##gitoxide)) [#11448](https://github.com/rust-lang/cargo/pull/11448) [#11800](https://github.com/rust-lang/cargo/pull/11800) [#11822](https://github.com/rust-lang/cargo/pull/11822) [#11830](https://github.com/rust-lang/cargo/pull/11830) - Removed `-Zjobserver-per-rustc`. Its rustc counterpart never got landed. [#11764](https://github.com/rust-lang/cargo/pull/11764) ### Documentation - Cleaned-up unstable documentation. [#11793](https://github.com/rust-lang/cargo/pull/11793) - Enhanced the documentation of timing report with graphs. [#11798](https://github.com/rust-lang/cargo/pull/11798) - Clarified requirements about the state of the registry index after publish. [#11926](https://github.com/rust-lang/cargo/pull/11926) - Clarified docs on `-C` that it appears before the command. [#11947](https://github.com/rust-lang/cargo/pull/11947) - Clarified working directory behaviour for `cargo test`, `cargo bench` and `cargo run`. [#11901](https://github.com/rust-lang/cargo/pull/11901) - Fixed the doc of `registries.name.index` configuration. [#11880](https://github.com/rust-lang/cargo/pull/11880) - Notice for potential unexpected shell expansions in help text of `cargo-add`. [#11826](https://github.com/rust-lang/cargo/pull/11826) - Updated external-tools JSON docs. [#11918](https://github.com/rust-lang/cargo/pull/11918) - Call out the differences between the index JSON and the API or metadata. [#11927](https://github.com/rust-lang/cargo/pull/11927) - Consistently use `@` when mentioning pkgid format. [#11956](https://github.com/rust-lang/cargo/pull/11956) - Enhanced Cargo Contributor Guide. [#11825](https://github.com/rust-lang/cargo/pull/11825) [#11842](https://github.com/rust-lang/cargo/pull/11842) [#11869](https://github.com/rust-lang/cargo/pull/11869) [#11876](https://github.com/rust-lang/cargo/pull/11876) - Moved a part of Cargo Contributor Guide to Cargo API documentation. [docs](https://doc.rust-lang.org/nightly/nightly-rustc/cargo) [#11809](https://github.com/rust-lang/cargo/pull/11809) [#11841](https://github.com/rust-lang/cargo/pull/11841) [#11850](https://github.com/rust-lang/cargo/pull/11850) [#11870](https://github.com/rust-lang/cargo/pull/11870) - Cargo team now arranges [office hours](https://github.com/rust-lang/cargo/wiki/Office-Hours)! [#11903](https://github.com/rust-lang/cargo/pull/11903) ### Internal - Switched to `sha2` crate for SHA256 calculation. [#11795](https://github.com/rust-lang/cargo/pull/11795) [#11807](https://github.com/rust-lang/cargo/pull/11807) - Switched benchsuite to the index archive. [#11933](https://github.com/rust-lang/cargo/pull/11933) - Updated to `base64` 0.21.0. [#11796](https://github.com/rust-lang/cargo/pull/11796) - Updated to `curl-sys` 0.4.61, which corresponds to curl 8.0.1. [#11871](https://github.com/rust-lang/cargo/pull/11871) - Updated to `proptest` 1.1.0. [#11886](https://github.com/rust-lang/cargo/pull/11886) - Updated to `git2` 0.17.0, which corresponds to libgit2 1.6.3. [#11928](https://github.com/rust-lang/cargo/pull/11928) - Updated to `clap` 4.2. [#11904](https://github.com/rust-lang/cargo/pull/11904) - Integrated `cargo-deny` in Cargo its own CI pipeline. [#11761](https://github.com/rust-lang/cargo/pull/11761) - Made non-blocking IO calls more robust. [#11624](https://github.com/rust-lang/cargo/pull/11624) - Dropped `derive` feature from `serde` in `cargo-platform`. [#11915](https://github.com/rust-lang/cargo/pull/11915) - Replaced `std::fs::canonicalize` with a more robust `try_canonicalize`. [#11866](https://github.com/rust-lang/cargo/pull/11866) - Enabled clippy warning on `disallowed_methods` for `std::env::var` and friends. [#11828](https://github.com/rust-lang/cargo/pull/11828) ## Cargo 1.69 (2023-04-20) [985d561f...rust-1.69.0](https://github.com/rust-lang/cargo/compare/985d561f...rust-1.69.0) ### Added - Cargo now suggests `cargo fix` or `cargo clippy --fix` when compilation warnings are auto-fixable. [#11558](https://github.com/rust-lang/cargo/pull/11558) - Cargo now suggests `cargo add` if you try to install a library crate. [#11410](https://github.com/rust-lang/cargo/pull/11410) - Cargo now sets the `CARGO_BIN_NAME` environment variable also for binary examples. [#11705](https://github.com/rust-lang/cargo/pull/11705) ### Changed - ❗ When `default-features` is set to false of a workspace dependency, and an inherited dependency of a member has `default-features = true`, Cargo will enable default features of that dependency. [#11409](https://github.com/rust-lang/cargo/pull/11409) - ❗ Deny `CARGO_HOME` in `[env]` configuration table. Cargo itself doesn't pick up this value, but recursive calls to cargo would, which was not intended. [#11644](https://github.com/rust-lang/cargo/pull/11644) - ❗ Debuginfo for build dependencies is now off if not explicitly set. This is expected to improve the overall build time. [#11252](https://github.com/rust-lang/cargo/pull/11252) - Cargo now emits errors on invalid alphanumeric characters in a registry token. [#11600](https://github.com/rust-lang/cargo/pull/11600) - `cargo add` now checks only the order of `[dependencies]` without considering `[dependencies.*]`. [#11612](https://github.com/rust-lang/cargo/pull/11612) - Cargo now respects the new jobserver IPC style in GNU Make 4.4, by updating its dependency `jobserver`. [#11767](https://github.com/rust-lang/cargo/pull/11767) - `cargo install` now reports required features when no binary meets its requirements. [#11647](https://github.com/rust-lang/cargo/pull/11647) ### Fixed - Uplifted `.dwp` DWARF package file next to the executable for debuggers to locate them. [#11572](https://github.com/rust-lang/cargo/pull/11572) - Fixed build scripts triggering recompiles when a `rerun-if-changed` points to a directory whose mtime is not preserved by the filesystem. [#11613](https://github.com/rust-lang/cargo/pull/11613) - Fixed panics when using dependencies from `[workspace.dependencies]` for `[patch]`. This usage is not supposed to be supported. [#11565](https://github.com/rust-lang/cargo/pull/11565) [#11630](https://github.com/rust-lang/cargo/pull/11630) - Fixed `cargo report` saving the same future-incompat reports multiple times. [#11648](https://github.com/rust-lang/cargo/pull/11648) - Fixed the incorrect inference of a directory ending with `.rs` as a file. [#11678](https://github.com/rust-lang/cargo/pull/11678) - Fixed `.cargo-ok` file being truncated wrongly, preventing from using a dependency. [#11665](https://github.com/rust-lang/cargo/pull/11665) [#11724](https://github.com/rust-lang/cargo/pull/11724) ### Nightly only - `-Zrustdoc-scrape-example` must fail with bad build script. [#11694](https://github.com/rust-lang/cargo/pull/11694) - Updated 1password credential manager integration to the version 2 CLI. [#11692](https://github.com/rust-lang/cargo/pull/11692) - Emit an error message for transitive artifact dependencies with targets the package doesn't directly interact with. [#11643](https://github.com/rust-lang/cargo/pull/11643) - Added `-C` flag for changing current dir before build starts. [#10952](https://github.com/rust-lang/cargo/pull/10952) ### Documentation - Clarified the difference between `CARGO_CRATE_NAME` and `CARGO_PKG_NAME`. [#11576](https://github.com/rust-lang/cargo/pull/11576) - Added links to the Target section of the glossary for occurrences of target triple. [#11603](https://github.com/rust-lang/cargo/pull/11603) - Described how the current resolver sometimes duplicates dependencies. [#11604](https://github.com/rust-lang/cargo/pull/11604) - Added a note about verifying your email address on crates.io. [#11620](https://github.com/rust-lang/cargo/pull/11620) - Mention current default value in `publish.timeout` docs. [#11652](https://github.com/rust-lang/cargo/pull/11652) - More doc comments for `cargo::core::compiler` modules. [#11669](https://github.com/rust-lang/cargo/pull/11669) [#11703](https://github.com/rust-lang/cargo/pull/11703) [#11711](https://github.com/rust-lang/cargo/pull/11711) [#11758](https://github.com/rust-lang/cargo/pull/11758) - Added more guidance on how to implement unstable features. [#11675](https://github.com/rust-lang/cargo/pull/11675) - Fixed unstable chapter layout for `codegen-backend`. [#11676](https://github.com/rust-lang/cargo/pull/11676) - Add a link to LTO doc. [#11701](https://github.com/rust-lang/cargo/pull/11701) - Added documentation for the configuration discovery of `cargo install` to the man pages [#11763](https://github.com/rust-lang/cargo/pull/11763) - Documented `-F` flag as an alias for `--features` in `cargo add`. [#11774](https://github.com/rust-lang/cargo/pull/11774) ### Internal - Disable network SSH tests on Windows. [#11610](https://github.com/rust-lang/cargo/pull/11610) - Made some blocking tests non-blocking. [#11650](https://github.com/rust-lang/cargo/pull/11650) - Deny warnings in CI, not locally. [#11699](https://github.com/rust-lang/cargo/pull/11699) - Re-export `cargo_new::NewProjectKind` as public. [#11700](https://github.com/rust-lang/cargo/pull/11700) - Made dependencies in alphabetical order. [#11719](https://github.com/rust-lang/cargo/pull/11719) - Switched some tests from `build` to `check`. [#11725](https://github.com/rust-lang/cargo/pull/11725) - Consolidated how Cargo reads environments variables internally. [#11727](https://github.com/rust-lang/cargo/pull/11727) [#11754](https://github.com/rust-lang/cargo/pull/11754) - Fixed tests with nondeterministic ordering [#11766](https://github.com/rust-lang/cargo/pull/11766) - Added a test to verify the intermediate artifacts persist in the temp directory. [#11771](https://github.com/rust-lang/cargo/pull/11771) - Updated cross test instructions for aarch64-apple-darwin. [#11663](https://github.com/rust-lang/cargo/pull/11663) - Updated to `toml` v0.6 and `toml_edit` v0.18 for TOML manipulations. [#11618](https://github.com/rust-lang/cargo/pull/11618) - Updated to `clap` v4.1.3. [#11619](https://github.com/rust-lang/cargo/pull/11619) - Replaced `winapi` with `windows-sys` crate for Windows bindings. [#11656](https://github.com/rust-lang/cargo/pull/11656) - Reused `url` crate for percent encoding instead of `percent-encoding`. [#11750](https://github.com/rust-lang/cargo/pull/11750) - Cargo contributors can benefit from smart punctuations when writing documentations, e.g., `---` is auto-converted into an em dash. ([docs](https://rust-lang.github.io/mdBook/format/markdown.html#smart-punctuation)) [#11646](https://github.com/rust-lang/cargo/pull/11646) [#11715](https://github.com/rust-lang/cargo/pull/11715) - Cargo's CI pipeline now covers macOS on nightly. [#11712](https://github.com/rust-lang/cargo/pull/11712) - Re-enabled some clippy lints in Cargo itself. [#11722](https://github.com/rust-lang/cargo/pull/11722) - Enabled sparse protocol in Cargo's CI. [#11632](https://github.com/rust-lang/cargo/pull/11632) - Pull requests in Cargo now get autolabelled for label `A-*` and `Command-*`. [#11664](https://github.com/rust-lang/cargo/pull/11664) [#11679](https://github.com/rust-lang/cargo/pull/11679) ## Cargo 1.68.2 (2023-03-28) [115f3455...rust-1.68.0](https://github.com/rust-lang/cargo/compare/115f3455...rust-1.68.0) - Updated the GitHub RSA SSH host key bundled within cargo. The key was [rotated by GitHub](https://github.blog/2023-03-23-we-updated-our-rsa-ssh-host-key/) on 2023-03-24 after the old one leaked. [#11883](https://github.com/rust-lang/cargo/pull/11883) - Added support for SSH known hosts marker `@revoked`. [#11635](https://github.com/rust-lang/cargo/pull/11635) - Marked the old GitHub RSA host key as revoked. This will prevent Cargo from accepting the leaked key even when trusted by the system. [#11889](https://github.com/rust-lang/cargo/pull/11889) ## Cargo 1.68 (2023-03-09) [f6e737b1...rust-1.68.0](https://github.com/rust-lang/cargo/compare/f6e737b1...rust-1.68.0) ### Added - πŸŽ‰ The new "sparse" protocol has been stabilized. It should provide a significant performance improvement when accessing crates.io. ([RFC 2789](https://github.com/rust-lang/rfcs/blob/master/text/2789-sparse-index.md)) ([docs](https://doc.rust-lang.org/nightly/cargo/reference/registries.html#registry-protocols)) [#11224](https://github.com/rust-lang/cargo/pull/11224) [#11480](https://github.com/rust-lang/cargo/pull/11480) [#11733](https://github.com/rust-lang/cargo/pull/11733) [#11756](https://github.com/rust-lang/cargo/pull/11756) - πŸŽ‰ `home` crate is now a subcrate in `rust-lang/cargo` repository. Welcome! [#11359](https://github.com/rust-lang/cargo/pull/11359) [#11481](https://github.com/rust-lang/cargo/pull/11481) - Long diagnostic messages now can be truncated to be more readable. [#11494](https://github.com/rust-lang/cargo/pull/11494) - Shows the progress of crates.io index update even when `net.git-fetch-with-cli` enabled. [#11579](https://github.com/rust-lang/cargo/pull/11579) - `cargo build --verbose` tells you more about why it recompiles. [#11407](https://github.com/rust-lang/cargo/pull/11407) - Cargo's file locking mechanism now supports Solaris by using `fcntl`. [#11439](https://github.com/rust-lang/cargo/pull/11439) [#11474](https://github.com/rust-lang/cargo/pull/11474) - Added a new SemVer compatibility rule explaining the expectations around diagnostic lints [#11596](https://github.com/rust-lang/cargo/pull/11596) - `cargo vendor` generates a different source replacement entry 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://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) ### Changed - Cargo now by default saves credentials to `.cargo/credentials.toml`. If `.cargo/credentials` exists, writes to it for backward compatibility reasons. [#11533](https://github.com/rust-lang/cargo/pull/11533) - To prevent sensitive data from being logged, Cargo introduces a new wrapper type internally. [#11545](https://github.com/rust-lang/cargo/pull/11545) - Several documentation improvements. [#11475](https://github.com/rust-lang/cargo/pull/11475) [#11504](https://github.com/rust-lang/cargo/pull/11504) [#11516](https://github.com/rust-lang/cargo/pull/11516) [#11517](https://github.com/rust-lang/cargo/pull/11517) [#11568](https://github.com/rust-lang/cargo/pull/11568) [#11586](https://github.com/rust-lang/cargo/pull/11586) [#11592](https://github.com/rust-lang/cargo/pull/11592) ### Fixed - ❗ `cargo package` and `cargo publish` now respects workspace's `Cargo.lock`. This is an expected behavior but previously got overlooked. [#11477](https://github.com/rust-lang/cargo/pull/11477) - Fixed `cargo vendor` failing on resolving git dependencies inherited from a workspace. [#11414](https://github.com/rust-lang/cargo/pull/11414) - `cargo install` can now correctly install root package when `workspace.default-members` is specified. [#11067](https://github.com/rust-lang/cargo/pull/11067) - Fixed panic on target specific dependency errors. [#11541](https://github.com/rust-lang/cargo/pull/11541) - Shows `--help` if there is no man page for a subcommand. [#11473](https://github.com/rust-lang/cargo/pull/11473) - Setting `target.cfg(…).rustflags` shouldn't erase `build.rustdocflags`. [#11323](https://github.com/rust-lang/cargo/pull/11323) - Unsupported `profile.split-debuginfo` options are now ignored, which previously made Cargo fail to compile on certain platforms. [#11347](https://github.com/rust-lang/cargo/pull/11347) [#11633](https://github.com/rust-lang/cargo/pull/11633) - Don't panic in Windows headless session with really long file names. [#11759](https://github.com/rust-lang/cargo/pull/11759) ### Nightly only - Implemented a initial support of asymmetric token authentication for registries. ([RFC 3231](https://github.com/rust-lang/rfcs/blob/master/text/3231-cargo-asymmetric-tokens.md)) ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#registry-auth)) [#10771](https://github.com/rust-lang/cargo/pull/10771) - Do not error for `auth-required: true` without `-Z sparse-registry` [#11661](https://github.com/rust-lang/cargo/pull/11661) - Supports `codegen-backend` and `rustflags` in profiles in config file. [#11562](https://github.com/rust-lang/cargo/pull/11562) - Suggests `cargo clippy --fix` when warnings/errors could be fixed with clippy. [#11399](https://github.com/rust-lang/cargo/pull/11399) - Fixed artifact deps not working when target field specified coexists with `optional = true`. [#11434](https://github.com/rust-lang/cargo/pull/11434) - Make Cargo distinguish `Unit`s with and without artifact targets. [#11478](https://github.com/rust-lang/cargo/pull/11478) - `cargo metadata` supports artifact dependencies. [#11550](https://github.com/rust-lang/cargo/pull/11550) - Allows builds of some crate to fail during optional doc-scraping. [#11450](https://github.com/rust-lang/cargo/pull/11450) - Add warning if potentially-scrapable examples are skipped due to dev-dependencies. [#11503](https://github.com/rust-lang/cargo/pull/11503) - Don't scrape examples from library targets by default. [#11499](https://github.com/rust-lang/cargo/pull/11499) - Fixed examples of proc-macro crates being scraped for examples. [#11497](https://github.com/rust-lang/cargo/pull/11497) ## Cargo 1.67 (2023-01-26) [7e484fc1...rust-1.67.0](https://github.com/rust-lang/cargo/compare/7e484fc1...rust-1.67.0) ### Added - `cargo remove` now cleans up the referenced dependency of the root workspace manifest, `profile`, `patch`, and `replace` sections after a successful removal of a dependency. [#11194](https://github.com/rust-lang/cargo/pull/11194) [#11242](https://github.com/rust-lang/cargo/pull/11242) [#11351](https://github.com/rust-lang/cargo/pull/11351) - `cargo package` and `cargo publish` now report total and compressed crate size after packaging. [#11270](https://github.com/rust-lang/cargo/pull/11270) ### Changed - ❗ Cargo now reuses the value of `$CARGO` if it's already set in the environment, and forwards the value when executing external subcommands and build scripts. [#11285](https://github.com/rust-lang/cargo/pull/11285) - ❗ Cargo now emits an error when running `cargo update --precise` without a `-p` flag. [#11349](https://github.com/rust-lang/cargo/pull/11349) - ❗ Cargo now emits an error if there are multiple registries in the configuration with the same index URL. [#10592](https://github.com/rust-lang/cargo/pull/10592) - Cargo now is aware of compression ratio when extracting crate files. This relaxes the hard size limit introduced in 1.64.0 to mitigate zip bomb attack. [#11337](https://github.com/rust-lang/cargo/pull/11337) - Cargo now errors out when `cargo fix` on a git repo with uncommitted changes. [#11400](https://github.com/rust-lang/cargo/pull/11400) - Cargo now warns when `cargo tree -i ` cannot find any package. [#11377](https://github.com/rust-lang/cargo/pull/11377) - Cargo now warns when running `cargo new/init` and `PATH` env separator is in the project path. [#11318](https://github.com/rust-lang/cargo/pull/11318) - Better error messages when multiple packages were found and `cargo add/remove` gets confused. [#11186](https://github.com/rust-lang/cargo/pull/11186) [#11375](https://github.com/rust-lang/cargo/pull/11375) - A better error message when `cargo init` but existing ignore files aren't UTF-8. [#11321](https://github.com/rust-lang/cargo/pull/11321) - A better error message for `cargo install .`. [#11401](https://github.com/rust-lang/cargo/pull/11401) - A better warning when the same file path found in multiple build targets. [#11299](https://github.com/rust-lang/cargo/pull/11299) - Updated the internal HTTP library libcurl with various fixes and updates. [#11307](https://github.com/rust-lang/cargo/pull/11307) [#11326](https://github.com/rust-lang/cargo/pull/11326) ### Fixed - Fixed `cargo clean` for removing fingerprints and build script artifacts of only the requested package [#10621](https://github.com/rust-lang/cargo/pull/10621) - Fixed `cargo install --index` not working when config `registry.default` is set. [#11302](https://github.com/rust-lang/cargo/pull/11302) - Fixed git2 safe-directory accidentally disabled when no network configuration was found. [#11366](https://github.com/rust-lang/cargo/pull/11366) - Migrate from crate `atty` to resolve potential soundness issue. [#11420](https://github.com/rust-lang/cargo/pull/11420) - Cleans stale git temp files left when libgit2 indexing is interrupted. [#11308](https://github.com/rust-lang/cargo/pull/11308) ### Nightly only - Suggests `cargo fix` when some compilation warnings/errors can be auto-fixed. [#10989](https://github.com/rust-lang/cargo/pull/10989) [#11368](https://github.com/rust-lang/cargo/pull/11368) - Changed `rustdoc-scrape-examples` to be a target-level configuration. [#10343](https://github.com/rust-lang/cargo/pull/10343) [#11425](https://github.com/rust-lang/cargo/pull/11425) [#11430](https://github.com/rust-lang/cargo/pull/11430) [#11445](https://github.com/rust-lang/cargo/pull/11445) - Propagates change of artifact bin dependency to its parent fingerprint. [#11353](https://github.com/rust-lang/cargo/pull/11353) - Fixed `wait-for-publish` to work with sparse registry. [#11356](https://github.com/rust-lang/cargo/pull/11356) [#11327](https://github.com/rust-lang/cargo/pull/11327) [#11388](https://github.com/rust-lang/cargo/pull/11388) - Stores the `sparse+` prefix in the `SourceId` for sparse registries [#11387](https://github.com/rust-lang/cargo/pull/11387) [#11403](https://github.com/rust-lang/cargo/pull/11403) - Implemented alternative registry authentication support. ([RFC 3139](https://github.com/rust-lang/rfcs/blob/master/text/3139-cargo-alternative-registry-auth.md)) ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#registry-auth)) [#10592](https://github.com/rust-lang/cargo/pull/10592) - Added documentation of config option `registries.crates-io.protocol`. [#11350](https://github.com/rust-lang/cargo/pull/11350) ## Cargo 1.66.1 (2023-01-10) ### Fixed - 🚨 [CVE-2022-46176](https://github.com/rust-lang/cargo/security/advisories/GHSA-r5w3-xm58-jv6j): Added validation of SSH host keys for git URLs. See [the docs](https://doc.rust-lang.org/cargo/appendix/git-authentication.html#ssh-known-hosts) for more information on how to configure the known host keys. ## Cargo 1.66 (2022-12-15) [08250398...rust-1.66.0](https://github.com/rust-lang/cargo/compare/08250398...rust-1.66.0) ### Added - πŸŽ‰ Added `cargo remove` command for removing dependencies from `Cargo.toml`. [docs](https://doc.rust-lang.org/nightly/cargo/commands/cargo-remove.html) [#11059](https://github.com/rust-lang/cargo/pull/11059) [#11099](https://github.com/rust-lang/cargo/pull/11099) [#11193](https://github.com/rust-lang/cargo/pull/11193) [#11204](https://github.com/rust-lang/cargo/pull/11204) [#11227](https://github.com/rust-lang/cargo/pull/11227) - Added support for git dependencies having git submodules with relative paths. [#11106](https://github.com/rust-lang/cargo/pull/11106) - Cargo now sends requests with a `Accept-Encoding` header to registries. [#11292](https://github.com/rust-lang/cargo/pull/11292) - Cargo now forwards non-UTF8 arguments to external subcommands. [#11118](https://github.com/rust-lang/cargo/pull/11118) ### Changed - ❗ Disambiguate source replacements from various angles. [RFC-3289](https://github.com/rust-lang/rfcs/blob/master/text/3289-source_replacement_ambiguity.md) [#10907](https://github.com/rust-lang/cargo/pull/10907) - When the crates-io source is replaced, the user is required to specify which registry to use with `--registry ` when performing an API operation. - Publishing to source-replaced crates.io is no longer permitted using the crates.io token (`registry.token`). - In source replacement, the `replace-with` key can reference the name of an alternative registry in the `[registries]` table. - ❗ `cargo publish` now blocks until it sees the published package in the index. [#11062](https://github.com/rust-lang/cargo/pull/11062) [#11210](https://github.com/rust-lang/cargo/pull/11210) [#11216](https://github.com/rust-lang/cargo/pull/11216) [#11255](https://github.com/rust-lang/cargo/pull/11255) - Cargo now uses the clap v4 library for command-line argument parsing. [#11116](https://github.com/rust-lang/cargo/pull/11116) [#11119](https://github.com/rust-lang/cargo/pull/11119) [#11159](https://github.com/rust-lang/cargo/pull/11159) [#11190](https://github.com/rust-lang/cargo/pull/11190) [#11239](https://github.com/rust-lang/cargo/pull/11239) [#11280](https://github.com/rust-lang/cargo/pull/11280) - Cargo now only warns on a user-defined alias shadowing an external command. [#11170](https://github.com/rust-lang/cargo/pull/11170) - Several documentation improvements. [#10770](https://github.com/rust-lang/cargo/pull/10770) [#10938](https://github.com/rust-lang/cargo/pull/10938) [#11082](https://github.com/rust-lang/cargo/pull/11082) [#11093](https://github.com/rust-lang/cargo/pull/11093) [#11157](https://github.com/rust-lang/cargo/pull/11157) [#11185](https://github.com/rust-lang/cargo/pull/11185) [#11207](https://github.com/rust-lang/cargo/pull/11207) [#11219](https://github.com/rust-lang/cargo/pull/11219) [#11240](https://github.com/rust-lang/cargo/pull/11240) [#11241](https://github.com/rust-lang/cargo/pull/11241) [#11282](https://github.com/rust-lang/cargo/pull/11282) ### Fixed - ❗ Config file loaded via `cargo --config ` now takes priority over environment variables. This is a documented behaviour but the old implementation accidentally got it wrong. [#11077](https://github.com/rust-lang/cargo/pull/11077) - ❗ Cargo collects rustflags in `target.cfg(…).rustflags` more correctly and warns if that's not enough for convergence. [#11114](https://github.com/rust-lang/cargo/pull/11114) - Final artifacts not removed by linker should be removed before a compilation gets started. [#11122](https://github.com/rust-lang/cargo/pull/11122) - `cargo add` now reports unknown features in a more discoverable manner. [#11098](https://github.com/rust-lang/cargo/pull/11098) - Cargo now reports command aliasing failure with more error contexts. [#11087](https://github.com/rust-lang/cargo/pull/11087) - A better error message when `cargo login` prompt receives empty input. [#11145](https://github.com/rust-lang/cargo/pull/11145) - A better error message for fields with wrong types where workspace inheritance is supported. [#11113](https://github.com/rust-lang/cargo/pull/11113) - A better error message when mixing feature syntax `dep:` with `/`. [#11172](https://github.com/rust-lang/cargo/pull/11172) - A better error message when publishing but `package.publish` is `false` in the manifest. [#11280](https://github.com/rust-lang/cargo/pull/11280) ### Nightly only - Added new config option `publish.timeout` behind `-Zpublish-timeout`. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#publish-timeout) [#11230](https://github.com/rust-lang/cargo/pull/11230) - Added retry support to sparse registries. [#11069](https://github.com/rust-lang/cargo/pull/11069) - Fixed sparse registry lockfile urls containing `registry+sparse+`. [#11177](https://github.com/rust-lang/cargo/pull/11177) - Add new config option `registries.crates-io.protocol` for controlling crates.io protocol. [#11215](https://github.com/rust-lang/cargo/pull/11215) - Removed `sparse+` prefix for index.crates.io. [#11247](https://github.com/rust-lang/cargo/pull/11247) - Fixed publishing with a dependency on a sparse registry. [#11268](https://github.com/rust-lang/cargo/pull/11268) - Fixed confusing error messages when using `-Zsparse-registry`. [#11283](https://github.com/rust-lang/cargo/pull/11283) - Fixed 410 gone response handling for sparse registries. [#11286](https://github.com/rust-lang/cargo/pull/11286) ## Cargo 1.65 (2022-11-03) [4fd148c4...rust-1.65.0](https://github.com/rust-lang/cargo/compare/4fd148c4...rust-1.65.0) ### Added - External subcommands can now inherit jobserver file descriptors from Cargo. [#10511](https://github.com/rust-lang/cargo/pull/10511) - Added an API documentation for private items in cargo-the-library. See . [#11019](https://github.com/rust-lang/cargo/pull/11019) ### Changed - Cargo now stops adding its bin path to `PATH` if it's already there. [#11023](https://github.com/rust-lang/cargo/pull/11023) - Improved the performance of Cargo build scheduling by sorting the queue of pending jobs. [#11032](https://github.com/rust-lang/cargo/pull/11032) - Improved the performance fetching git dependencies from GitHub even when using a partial hash in the `rev` field. [#10807](https://github.com/rust-lang/cargo/pull/10807) - Cargo now uses git2 v0.15 and libgit2-sys v0.14, which bring several compatibility fixes with git's new behaviors. [#11004](https://github.com/rust-lang/cargo/pull/11004) - Registry index files are cached in a more granular way based on content hash. [#11044](https://github.com/rust-lang/cargo/pull/11044) - Cargo now uses the standard library's `std::thread::scope` instead of the `crossbeam` crate for spawning scoped threads. [#10977](https://github.com/rust-lang/cargo/pull/10977) - Cargo now uses the standard library's `available_parallelism` instead of the `num_cpus` crate for determining the default parallelism. [#10969](https://github.com/rust-lang/cargo/pull/10969) - Cargo now guides you how to solve it when seeing an error message of `rust-version` requirement not satisfied. [#10891](https://github.com/rust-lang/cargo/pull/10891) - Cargo now tells you more about possible causes and how to fix it when a subcommand cannot be found. [#10924](https://github.com/rust-lang/cargo/pull/10924) - Cargo now lists available target names when a given Cargo target cannot be found. [#10999](https://github.com/rust-lang/cargo/pull/10999) - `cargo update` now warns if `--precise` is given without `--package` flag. This will become a hard error after a transition period. [#10988](https://github.com/rust-lang/cargo/pull/10988) [#11011](https://github.com/rust-lang/cargo/pull/11011) - `cargo bench` and `cargo test` now report a more precise test execution error right after a test fails. [#11028](https://github.com/rust-lang/cargo/pull/11028) - `cargo add` now tells you for which version the features are added. [#11075](https://github.com/rust-lang/cargo/pull/11075) - Call out that non-ASCII crate names are not supported by Rust anymore. [#11017](https://github.com/rust-lang/cargo/pull/11017) - Enhanced the error message when in the manifest a field is expected to be an array but a string is used. [#10944](https://github.com/rust-lang/cargo/pull/10944) ### Fixed - Removed the restriction on file locking supports on platforms other than Linux. [#10975](https://github.com/rust-lang/cargo/pull/10975) - Fixed incorrect OS detection by bumping os_info to 3.5.0. [#10943](https://github.com/rust-lang/cargo/pull/10943) - Scanning the package directory now ignores errors from broken but excluded symlink files. [#11008](https://github.com/rust-lang/cargo/pull/11008) - Fixed deadlock when build scripts are waiting for input on stdin. [#11257](https://github.com/rust-lang/cargo/pull/11257) ### Nightly - Progress indicator for sparse registries becomes more straightforward. [#11068](https://github.com/rust-lang/cargo/pull/11068) ## Cargo 1.64 (2022-09-22) [a5e08c47...rust-1.64.0](https://github.com/rust-lang/cargo/compare/a5e08c47...rust-1.64.0) ### Added - πŸŽ‰ Packages can now inherit settings from the workspace so that the settings can be centralized in one place. See [`workspace.package`](https://doc.rust-lang.org/nightly/cargo/reference/workspaces.html#the-package-table) and [`workspace.dependencies`](https://doc.rust-lang.org/nightly/cargo/reference/workspaces.html#the-dependencies-table) for more details on how to define these common settings. [#10859](https://github.com/rust-lang/cargo/pull/10859) - Added the [`--crate-type`](https://doc.rust-lang.org/nightly/cargo/commands/cargo-rustc.html#option-cargo-rustc---crate-type) flag to `cargo rustc` to override the crate type. [#10838](https://github.com/rust-lang/cargo/pull/10838) - Cargo commands can now accept multiple `--target` flags to build for multiple targets at once, and the [`build.target`](https://doc.rust-lang.org/nightly/cargo/reference/config.html#buildtarget) config option may now take an array of multiple targets. [#10766](https://github.com/rust-lang/cargo/pull/10766) - The `--jobs` argument can now take a negative number to count backwards from the max CPUs. [#10844](https://github.com/rust-lang/cargo/pull/10844) ### Changed - Bash completion of `cargo install --path` now supports path completion. [#10798](https://github.com/rust-lang/cargo/pull/10798) - Significantly improved the performance fetching git dependencies from GitHub when using a hash in the `rev` field. [#10079](https://github.com/rust-lang/cargo/pull/10079) - Published packages will now include the resolver setting from the workspace to ensure that they use the same resolver when used in isolation. [#10911](https://github.com/rust-lang/cargo/pull/10911) [#10961](https://github.com/rust-lang/cargo/pull/10961) [#10970](https://github.com/rust-lang/cargo/pull/10970) - `cargo add` will now update `Cargo.lock`. [#10902](https://github.com/rust-lang/cargo/pull/10902) - The path in the config output of `cargo vendor` now translates backslashes to forward slashes so that the settings should work across platforms. [#10668](https://github.com/rust-lang/cargo/pull/10668) - The [`workspace.default-members`](https://doc.rust-lang.org/nightly/cargo/reference/workspaces.html#package-selection) setting now allows a value of `"."` in a non-virtual workspace to refer to the root package. [#10784](https://github.com/rust-lang/cargo/pull/10784) ### Fixed - 🚨 [CVE-2022-36113](https://github.com/rust-lang/cargo/security/advisories/GHSA-rfj2-q3h3-hm5j): Extracting malicious crates can corrupt arbitrary files. [#11089](https://github.com/rust-lang/cargo/pull/11089) [#11088](https://github.com/rust-lang/cargo/pull/11088) - 🚨 [CVE-2022-36114](https://github.com/rust-lang/cargo/security/advisories/GHSA-2hvr-h6gw-qrxp): Extracting malicious crates can fill the file system. [#11089](https://github.com/rust-lang/cargo/pull/11089) [#11088](https://github.com/rust-lang/cargo/pull/11088) - The `os` output in `cargo --version --verbose` now supports more platforms. [#10802](https://github.com/rust-lang/cargo/pull/10802) - Cached git checkouts will now be rebuilt if they are corrupted. This may happen when using `net.git-fetch-with-cli` and interrupting the clone process. [#10829](https://github.com/rust-lang/cargo/pull/10829) - Fixed panic in `cargo add --offline`. [#10817](https://github.com/rust-lang/cargo/pull/10817) ### Nightly only - Fixed deserialization of unstable `check-cfg` in `config.toml`. [#10799](https://github.com/rust-lang/cargo/pull/10799) ## Cargo 1.63 (2022-08-11) [3f052d8e...rust-1.63.0](https://github.com/rust-lang/cargo/compare/3f052d8e...rust-1.63.0) ### Added - πŸŽ‰ Added the `--config` CLI option to pass config options directly on the CLI. [#10755](https://github.com/rust-lang/cargo/pull/10755) - The `CARGO_PKG_RUST_VERSION` environment variable is now set when compiling a crate if the manifest has the `rust-version` field set. [#10713](https://github.com/rust-lang/cargo/pull/10713) ### Changed - A warning is emitted when encountering multiple packages with the same name in a git dependency. This will ignore packages with `publish=false`. [#10701](https://github.com/rust-lang/cargo/pull/10701) [#10767](https://github.com/rust-lang/cargo/pull/10767) - Change tracking now uses the contents of a `.json` target spec file instead of its path. This should help avoid rebuilds if the path changes. [#10746](https://github.com/rust-lang/cargo/pull/10746) - Git dependencies with a submodule configured with the `update=none` strategy in `.gitmodules` is now honored, and the submodule will not be fetched. [#10717](https://github.com/rust-lang/cargo/pull/10717) - Crate files now use a more recent date (Jul 23, 2006 instead of Nov 29, 1973) for deterministic behavior. [#10720](https://github.com/rust-lang/cargo/pull/10720) - The initial template used for `cargo new` now includes a slightly more realistic test structure that has `use super::*;` in the test module. [#10706](https://github.com/rust-lang/cargo/pull/10706) - Updated the internal HTTP library libcurl with various small fixes and updates. [#10696](https://github.com/rust-lang/cargo/pull/10696) ### Fixed - Fix zsh completions for `cargo add` and `cargo locate-project` [#10810](https://github.com/rust-lang/cargo/pull/10810) [#10811](https://github.com/rust-lang/cargo/pull/10811) - Fixed `-p` being ignored with `cargo publish` in the root of a virtual workspace. Some additional checks were also added to generate an error if multiple packages were selected (previously it would pick the first one). [#10677](https://github.com/rust-lang/cargo/pull/10677) - The human-readable executable name is no longer displayed for `cargo test` when using JSON output. [#10691](https://github.com/rust-lang/cargo/pull/10691) ### Nightly only - Added `-Zcheck-cfg=output` to support build-scripts declaring their supported set of `cfg` values with `cargo:rustc-check-cfg`. [#10539](https://github.com/rust-lang/cargo/pull/10539) - `-Z sparse-registry` now uses https://index.crates.io/ when accessing crates-io. [#10725](https://github.com/rust-lang/cargo/pull/10725) - Fixed formatting of `.workspace` key in `cargo add` for workspace inheritance. [#10705](https://github.com/rust-lang/cargo/pull/10705) - Sparse HTTP registry URLs must now end with a `/`. [#10698](https://github.com/rust-lang/cargo/pull/10698) - Fixed issue with `cargo add` and workspace inheritance of the `default-features` key. [#10685](https://github.com/rust-lang/cargo/pull/10685) ## Cargo 1.62 (2022-06-30) [1ef1e0a1...rust-1.62.0](https://github.com/rust-lang/cargo/compare/1ef1e0a1...rust-1.62.0) ### Added - πŸŽ‰ Added the `cargo add` command for adding dependencies to `Cargo.toml` from the command-line. [docs](https://doc.rust-lang.org/nightly/cargo/commands/cargo-add.html) [#10472](https://github.com/rust-lang/cargo/pull/10472) [#10577](https://github.com/rust-lang/cargo/pull/10577) [#10578](https://github.com/rust-lang/cargo/pull/10578) - Package ID specs now support `name@version` syntax in addition to the previous `name:version` to align with the behavior in `cargo add` and other tools. `cargo install` and `cargo yank` also now support this syntax so the version does not need to passed as a separate flag. [#10582](https://github.com/rust-lang/cargo/pull/10582) [#10650](https://github.com/rust-lang/cargo/pull/10650) [#10597](https://github.com/rust-lang/cargo/pull/10597) - Added the CLI option `-F` as an alias of `--features`. [#10576](https://github.com/rust-lang/cargo/pull/10576) - The `git` and `registry` directories in Cargo's home directory (usually `~/.cargo`) are now marked as cache directories so that they are not included in backups or content indexing (on Windows). [#10553](https://github.com/rust-lang/cargo/pull/10553) - Added the `--version` flag to `cargo yank` to replace the `--vers` flag to be consistent with `cargo install`. [#10575](https://github.com/rust-lang/cargo/pull/10575) - Added automatic `@` argfile support, which will use "response files" if the command-line to `rustc` exceeds the operating system's limit. [#10546](https://github.com/rust-lang/cargo/pull/10546) - `cargo clean` now has a progress bar (if it takes longer than half a second). [#10236](https://github.com/rust-lang/cargo/pull/10236) ### Changed - `cargo install` no longer generates an error if no binaries were found to install (such as missing required features). [#10508](https://github.com/rust-lang/cargo/pull/10508) - `cargo test` now passes `--target` to `rustdoc` if the specified target is the same as the host target. [#10594](https://github.com/rust-lang/cargo/pull/10594) - `cargo doc` now automatically passes `-Arustdoc::private-intra-doc-links` when documenting a binary (which automatically includes `--document-private-items`). The [`private-intra-doc-links`](https://doc.rust-lang.org/rustdoc/lints.html#private_intra_doc_links) lint is only relevant when *not* documenting private items, which doesn't apply to binaries. [#10142](https://github.com/rust-lang/cargo/pull/10142) - The length of the short git hash in the `cargo --version` output is now fixed to 9 characters. Previously the length was inconsistent between different platforms. [#10579](https://github.com/rust-lang/cargo/pull/10579) - Attempting to publish a package with a `Cargo.toml.orig` file will now result in an error. The filename would otherwise conflict with the automatically-generated file. [#10551](https://github.com/rust-lang/cargo/pull/10551) ### Fixed - The `build.dep-info-basedir` configuration setting now properly supports the use of `..` in the path to refer to a parent directory. [#10281](https://github.com/rust-lang/cargo/pull/10281) - Fixed regression in automatic detection of the default number of CPUs to use on systems using cgroups v1. [#10737](https://github.com/rust-lang/cargo/pull/10737) [#10739](https://github.com/rust-lang/cargo/pull/10739) ### Nightly only - `cargo fetch` now works with `-Zbuild-std` to fetch the standard library's dependencies. [#10129](https://github.com/rust-lang/cargo/pull/10129) - Added support for workspace inheritance. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#workspace-inheritance) [#10584](https://github.com/rust-lang/cargo/pull/10584) [#10568](https://github.com/rust-lang/cargo/pull/10568) [#10565](https://github.com/rust-lang/cargo/pull/10565) [#10564](https://github.com/rust-lang/cargo/pull/10564) [#10563](https://github.com/rust-lang/cargo/pull/10563) [#10606](https://github.com/rust-lang/cargo/pull/10606) [#10548](https://github.com/rust-lang/cargo/pull/10548) [#10538](https://github.com/rust-lang/cargo/pull/10538) - Added `-Zcheck-cfg` which adds various forms of validating `cfg` expressions for unknown names and values. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg) [#10486](https://github.com/rust-lang/cargo/pull/10486) [#10566](https://github.com/rust-lang/cargo/pull/10566) - The `--config` CLI option no longer allows setting a registry token. [#10580](https://github.com/rust-lang/cargo/pull/10580) - Fixed issues with proc-macros and `-Z rustdoc-scrape-examples`. [#10549](https://github.com/rust-lang/cargo/pull/10549) [#10533](https://github.com/rust-lang/cargo/pull/10533) ## Cargo 1.61 (2022-05-19) [ea2a21c9...rust-1.61.0](https://github.com/rust-lang/cargo/compare/ea2a21c9...rust-1.61.0) ### Added ### Changed - `cargo test --no-run` will now display the path to the test executables. [#10346](https://github.com/rust-lang/cargo/pull/10346) - `cargo tree --duplicates` no longer reports dependencies that are shared between the host and the target as duplicates. [#10466](https://github.com/rust-lang/cargo/pull/10466) - Updated to the 1.4.2 release of libgit2 which brings in several fixes [#10442](https://github.com/rust-lang/cargo/pull/10442) [#10479](https://github.com/rust-lang/cargo/pull/10479) - `cargo vendor` no longer allows multiple values for `--sync`, you must pass multiple `--sync` flags instead. [#10448](https://github.com/rust-lang/cargo/pull/10448) - Warnings are now issued for manifest keys that have mixed both underscore and dash variants (such as specifying both `proc_macro` and `proc-macro`) [#10316](https://github.com/rust-lang/cargo/pull/10316) - Cargo now uses the standard library's `available_parallelism` instead of the `num_cpus` crate for determining the default parallelism. [#10427](https://github.com/rust-lang/cargo/pull/10427) - `cargo search` terms are now highlighted. [#10425](https://github.com/rust-lang/cargo/pull/10425) ### Fixed - Paths passed to VCS tools like `hg` are now added after `--` to avoid conflict with VCS flags. [#10483](https://github.com/rust-lang/cargo/pull/10483) - Fixed the `http.timeout` configuration value to actually work. [#10456](https://github.com/rust-lang/cargo/pull/10456) - Fixed issues with `cargo rustc --crate-type` not working in some situations. [#10388](https://github.com/rust-lang/cargo/pull/10388) ### Nightly only - Added `-Z check-cfg-features` to enable compile-time checking of features [#10408](https://github.com/rust-lang/cargo/pull/10408) - Added `-Z bindeps` to support binary artifact dependencies (RFC-3028) [#9992](https://github.com/rust-lang/cargo/pull/9992) - `-Z multitarget` is now supported in the `build.target` config value with an array. [#10473](https://github.com/rust-lang/cargo/pull/10473) - Added `--keep-going` flag which will continue compilation even if one crate fails to compile. [#10383](https://github.com/rust-lang/cargo/pull/10383) - Start work on inheriting manifest values in a workspace. [#10497](https://github.com/rust-lang/cargo/pull/10497) [#10517](https://github.com/rust-lang/cargo/pull/10517) - Added support for sparse HTTP registries. [#10470](https://github.com/rust-lang/cargo/pull/10470) [#10064](https://github.com/rust-lang/cargo/pull/10064) - Fixed panic when artifact target is used for `[target.'cfg()'.dependencies]` [#10433](https://github.com/rust-lang/cargo/pull/10433) - Fixed host flags to pass to build scripts (`-Z target-applies-to-host`) [#10395](https://github.com/rust-lang/cargo/pull/10395) - Added `-Z check-cfg-features` support for rustdoc [#10428](https://github.com/rust-lang/cargo/pull/10428) ## Cargo 1.60 (2022-04-07) [358e79fe...rust-1.60.0](https://github.com/rust-lang/cargo/compare/358e79fe...rust-1.60.0) ### Added - πŸŽ‰ Added the `dep:` prefix in the `[features]` table to refer to an optional dependency. This allows creating feature names with the same name as a dependency, and allows for "hiding" optional dependencies so that they do not implicitly expose a feature name. [docs](https://doc.rust-lang.org/nightly/cargo/reference/features.html#optional-dependencies) [#10269](https://github.com/rust-lang/cargo/pull/10269) - πŸŽ‰ Added the `dep-name?/feature-name` syntax to the `[features]` table to only enable the feature `feature-name` if the optional dependency `dep-name` is already enabled by some other feature. [docs](https://doc.rust-lang.org/nightly/cargo/reference/features.html#dependency-features) [#10269](https://github.com/rust-lang/cargo/pull/10269) - πŸŽ‰ Added `--timings` option to generate an HTML report about build timing, concurrency, and CPU use. [docs](https://doc.rust-lang.org/nightly/cargo/reference/timings.html) [#10245](https://github.com/rust-lang/cargo/pull/10245) - Added the `"v"` and `"features2"` fields to the registry index. The `"v"` field provides a method for compatibility with future changes to the index. [docs](https://doc.rust-lang.org/nightly/cargo/reference/registries.html#index-format) [#10269](https://github.com/rust-lang/cargo/pull/10269) - Added bash completion for `cargo clippy` [#10347](https://github.com/rust-lang/cargo/pull/10347) - Added bash completion for `cargo report` [#10295](https://github.com/rust-lang/cargo/pull/10295) - Added support to build scripts for `rustc-link-arg-tests`, `rustc-link-arg-examples`, and `rustc-link-arg-benches`. [docs](https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#outputs-of-the-build-script) [#10274](https://github.com/rust-lang/cargo/pull/10274) ### Changed - Cargo now uses the clap 3 library for command-line argument parsing. [#10265](https://github.com/rust-lang/cargo/pull/10265) - The `build.pipelining` config option is now deprecated, pipelining will now always be enabled. [#10258](https://github.com/rust-lang/cargo/pull/10258) - `cargo new` will now generate a `.gitignore` which only ignores `Cargo.lock` in the root of the repo, instead of any directory. [#10379](https://github.com/rust-lang/cargo/pull/10379) - Improved startup time of bash completion. [#10365](https://github.com/rust-lang/cargo/pull/10365) - The `--features` flag is now honored when used with the `--all-features` flag, which allows enabling features from other packages. [#10337](https://github.com/rust-lang/cargo/pull/10337) - Cargo now uses a different TOML parser. This should not introduce any user-visible changes. This paves the way to support format-preserving programmatic modification of TOML files for supporting `cargo add` and other future enhancements. [#10086](https://github.com/rust-lang/cargo/pull/10086) - Setting a library to emit both a `dylib` and `cdylib` is now an error, as this combination is not supported. [#10243](https://github.com/rust-lang/cargo/pull/10243) - `cargo --list` now includes the `help` command. [#10300](https://github.com/rust-lang/cargo/pull/10300) ### Fixed - Fixed running `cargo doc` on examples with dev-dependencies. [#10341](https://github.com/rust-lang/cargo/pull/10341) - Fixed `cargo install --path` for a path that is relative to a directory outside of the workspace in the current directory. [#10335](https://github.com/rust-lang/cargo/pull/10335) - `cargo test TEST_FILTER` should no longer build binaries that are explicitly disabled with `test = false`. [#10305](https://github.com/rust-lang/cargo/pull/10305) - Fixed regression with `term.verbose` without `term.quiet`, and vice versa. [#10429](https://github.com/rust-lang/cargo/pull/10429) [#10436](https://github.com/rust-lang/cargo/pull/10436) ### Nightly only - Added `rustflags` option to a profile definition. [#10217](https://github.com/rust-lang/cargo/pull/10217) - Changed `--config` to only support dotted keys. [#10176](https://github.com/rust-lang/cargo/pull/10176) - Fixed profile `rustflags` not being gated in profile overrides. [#10411](https://github.com/rust-lang/cargo/pull/10411) [#10413](https://github.com/rust-lang/cargo/pull/10413) ## Cargo 1.59 (2022-02-24) [7f08ace4...rust-1.59.0](https://github.com/rust-lang/cargo/compare/7f08ace4...rust-1.59.0) ### Added - πŸŽ‰ The `strip` option can now be specified in a profile to specify the behavior for removing symbols and debug information from binaries. [docs](https://doc.rust-lang.org/nightly/cargo/reference/profiles.html#strip) [#10088](https://github.com/rust-lang/cargo/pull/10088) [#10376](https://github.com/rust-lang/cargo/pull/10376) - πŸŽ‰ Added future incompatible reporting. This provides reporting for when a future change in `rustc` may cause a package or any of its dependencies to stop building. [docs](https://doc.rust-lang.org/nightly/cargo/reference/future-incompat-report.html) [#10165](https://github.com/rust-lang/cargo/pull/10165) - SSH authentication on Windows now supports ssh-agent. [docs](https://doc.rust-lang.org/nightly/cargo/appendix/git-authentication.html#ssh-authentication) [#10248](https://github.com/rust-lang/cargo/pull/10248) - Added `term.quiet` configuration option to enable the `--quiet` behavior from a config file. [docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#termquiet) [#10152](https://github.com/rust-lang/cargo/pull/10152) - Added `-r` CLI option as an alias for `--release`. [#10133](https://github.com/rust-lang/cargo/pull/10133) ### Changed - Scanning the package directory should now be resilient to errors, such as filesystem loops or access issues. [#10188](https://github.com/rust-lang/cargo/pull/10188) [#10214](https://github.com/rust-lang/cargo/pull/10214) [#10286](https://github.com/rust-lang/cargo/pull/10286) - `cargo help ` will now show the target of the alias. [#10193](https://github.com/rust-lang/cargo/pull/10193) - Removed the deprecated `--host` CLI option. [#10145](https://github.com/rust-lang/cargo/pull/10145) [#10327](https://github.com/rust-lang/cargo/pull/10327) - Cargo should now report its version to always be in sync with `rustc`. [#10178](https://github.com/rust-lang/cargo/pull/10178) - Added EOPNOTSUPP to ignored file locking errors, which is relevant to BSD operating systems. [#10157](https://github.com/rust-lang/cargo/pull/10157) ### Fixed - macOS: Fixed an issue where running an executable would sporadically be killed by the kernel (likely starting in macOS 12). [#10196](https://github.com/rust-lang/cargo/pull/10196) - Fixed so that the `doc=false` setting is honored in the `[lib]` definition of a dependency. [#10201](https://github.com/rust-lang/cargo/pull/10201) [#10324](https://github.com/rust-lang/cargo/pull/10324) - The `"executable"` field in the JSON option was incorrectly including the path to `index.html` when documenting a binary. It is now null. [#10171](https://github.com/rust-lang/cargo/pull/10171) - Documenting a binary now waits for the package library to finish documenting before starting. This fixes some race conditions if the binary has intra-doc links to the library. [#10172](https://github.com/rust-lang/cargo/pull/10172) - Fixed panic when displaying help text to a closed pipe. [#10164](https://github.com/rust-lang/cargo/pull/10164) ### Nightly only - Added the `--crate-type` flag to `cargo rustc`. [#10093](https://github.com/rust-lang/cargo/pull/10093) ## Cargo 1.58 (2022-01-13) [b2e52d7c...rust-1.58.0](https://github.com/rust-lang/cargo/compare/b2e52d7c...rust-1.58.0) ### Added - Added `rust_version` field to package data in `cargo metadata`. [#9967](https://github.com/rust-lang/cargo/pull/9967) - Added `--message-format` option to `cargo install`. [#10107](https://github.com/rust-lang/cargo/pull/10107) ### Changed - A warning is now shown when an alias shadows an external command. [#10082](https://github.com/rust-lang/cargo/pull/10082) - Updated curl to 7.80.0. [#10040](https://github.com/rust-lang/cargo/pull/10040) [#10106](https://github.com/rust-lang/cargo/pull/10106) ### Fixed - Doctests now include rustc-link-args from build scripts. [#9916](https://github.com/rust-lang/cargo/pull/9916) - Fixed `cargo tree` entering an infinite loop with cyclical dev-dependencies. Fixed an edge case where the resolver would fail to handle a cyclical dev-dependency with a feature. [#10103](https://github.com/rust-lang/cargo/pull/10103) - Fixed `cargo clean -p` when the directory path contains glob characters. [#10072](https://github.com/rust-lang/cargo/pull/10072) - Fixed debug builds of `cargo` which could panic when downloading a crate when the server has a redirect with a non-empty body. [#10048](https://github.com/rust-lang/cargo/pull/10048) ### Nightly only - Make future-incompat-report output more user-friendly. [#9953](https://github.com/rust-lang/cargo/pull/9953) - Added support to scrape code examples from the `examples` directory to be included in the documentation. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#scrape-examples) [#9525](https://github.com/rust-lang/cargo/pull/9525) [#10037](https://github.com/rust-lang/cargo/pull/10037) [#10017](https://github.com/rust-lang/cargo/pull/10017) - Fixed `cargo report future-incompatibilities` to check stdout if it supports color. [#10024](https://github.com/rust-lang/cargo/pull/10024) ## Cargo 1.57 (2021-12-02) [18751dd3...rust-1.57.0](https://github.com/rust-lang/cargo/compare/18751dd3...rust-1.57.0) ### Added - πŸŽ‰ Added custom named profiles. This also changes the `test` and `bench` profiles to inherit their settings from `dev` and `release`, and Cargo will now only use a single profile during a given command instead of using different profiles for dependencies and cargo-targets. [docs](https://doc.rust-lang.org/nightly/cargo/reference/profiles.html#custom-profiles) [#9943](https://github.com/rust-lang/cargo/pull/9943) - The `rev` option for a git dependency now supports git references that start with `refs/`. An example where this can be used is to depend on a pull request from a service like GitHub before it is merged. [#9859](https://github.com/rust-lang/cargo/pull/9859) - Added `path_in_vcs` field to the `.cargo_vcs_info.json` file. [docs](https://doc.rust-lang.org/nightly/cargo/commands/cargo-package.html#cargo_vcs_infojson-format) [#9866](https://github.com/rust-lang/cargo/pull/9866) ### Changed - ❗ `RUSTFLAGS` is no longer set for build scripts. This change was made in 1.55, but the release notes did not highlight this change. Build scripts should use `CARGO_ENCODED_RUSTFLAGS` instead. See the [documentation](https://doc.rust-lang.org/nightly/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts) for more details. - The `cargo version` command now includes some extra information. [#9968](https://github.com/rust-lang/cargo/pull/9968) - Updated libgit2 to 1.3 which brings in a number of fixes and changes to git handling. [#9963](https://github.com/rust-lang/cargo/pull/9963) [#9988](https://github.com/rust-lang/cargo/pull/9988) - Shell completions now include shorthand b/r/c/d subcommands. [#9951](https://github.com/rust-lang/cargo/pull/9951) - `cargo update --precise` now allows specifying a version without semver metadata (stuff after `+` in the version number). [#9945](https://github.com/rust-lang/cargo/pull/9945) - zsh completions now complete `--example` names. [#9939](https://github.com/rust-lang/cargo/pull/9939) - The progress bar now differentiates when building unittests. [#9934](https://github.com/rust-lang/cargo/pull/9934) - Some backwards-compatibility support for invalid TOML syntax has been removed. [#9932](https://github.com/rust-lang/cargo/pull/9932) - Reverted the change from 1.55 that triggered an error for dependency specifications that did not include any fields. [#9911](https://github.com/rust-lang/cargo/pull/9911) ### Fixed - Removed a log message (from `CARGO_LOG`) that may leak tokens. [#9873](https://github.com/rust-lang/cargo/pull/9873) - `cargo fix` will now avoid writing fixes to the global registry cache. [#9938](https://github.com/rust-lang/cargo/pull/9938) - Fixed `-Z help` CLI option when used with a shorthand alias (b/c/r/d). [#9933](https://github.com/rust-lang/cargo/pull/9933) ### Nightly only ## Cargo 1.56 (2021-10-21) [cebef295...rust-1.56.0](https://github.com/rust-lang/cargo/compare/cebef295...rust-1.56.0) ### Added - πŸŽ‰ Cargo now supports the 2021 edition. More information may be found in the [edition guide](https://doc.rust-lang.org/nightly/edition-guide/rust-2021/index.html). [#9800](https://github.com/rust-lang/cargo/pull/9800) - πŸŽ‰ Added the [`rust-version`](https://doc.rust-lang.org/nightly/cargo/reference/manifest.html#the-rust-version-field) field to `Cargo.toml` to specify the minimum supported Rust version, and the `--ignore-rust-version` command line option to override it. [#9732](https://github.com/rust-lang/cargo/pull/9732) - Added the `[env]` table to config files to specify environment variables to set. [docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#env) [#9411](https://github.com/rust-lang/cargo/pull/9411) - `[patch]` tables may now be specified in config files. [docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#patch) [#9839](https://github.com/rust-lang/cargo/pull/9839) - `cargo doc` now supports the `--example` and `--examples` flags. [#9808](https://github.com/rust-lang/cargo/pull/9808) - πŸŽ‰ Build scripts can now pass additional linker arguments for binaries or all linkable targets. [docs](https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#outputs-of-the-build-script) [#9557](https://github.com/rust-lang/cargo/pull/9557) - Added support for the `-p` flag for `cargo publish` to publish a specific package in a workspace. `cargo package` also now supports `-p` and `--workspace`. [#9559](https://github.com/rust-lang/cargo/pull/9559) - Added documentation about third-party registries. [#9830](https://github.com/rust-lang/cargo/pull/9830) - Added the `{sha256-checksum}` placeholder for URLs in a registry `config.json`. [docs](https://doc.rust-lang.org/nightly/cargo/reference/registries.html#index-format) [#9801](https://github.com/rust-lang/cargo/pull/9801) - Added a warning when a dependency does not have a library. [#9771](https://github.com/rust-lang/cargo/pull/9771) ### Changed - Doc tests now support the `-q` flag to show terse test output. [#9730](https://github.com/rust-lang/cargo/pull/9730) - `features` used in a `[replace]` table now issues a warning, as they are ignored. [#9681](https://github.com/rust-lang/cargo/pull/9681) - Changed so that only `wasm32-unknown-emscripten` executables are built without a hash in the filename. Previously it was all `wasm32` targets. Additionally, all `apple` binaries are now built with a hash in the filename. This allows multiple copies to be cached at once, and matches the behavior on other platforms (except `msvc`). [#9653](https://github.com/rust-lang/cargo/pull/9653) - `cargo new` now generates an example that doesn't generate a warning with clippy. [#9796](https://github.com/rust-lang/cargo/pull/9796) - `cargo fix --edition` now only applies edition-specific lints. [#9846](https://github.com/rust-lang/cargo/pull/9846) - Improve resolver message to include dependency requirements. [#9827](https://github.com/rust-lang/cargo/pull/9827) - `cargo fix` now has more debug logging available with the `CARGO_LOG` environment variable. [#9831](https://github.com/rust-lang/cargo/pull/9831) - Changed `cargo fix --edition` to emit a warning when on the latest stable edition when running on stable instead of generating an error. [#9792](https://github.com/rust-lang/cargo/pull/9792) - `cargo install` will now determine all of the packages to install before starting the installation, which should help with reporting errors without partially installing. [#9793](https://github.com/rust-lang/cargo/pull/9793) - The resolver report for `cargo fix --edition` now includes differences for dev-dependencies. [#9803](https://github.com/rust-lang/cargo/pull/9803) - `cargo fix` will now show better diagnostics for abnormal errors from `rustc`. [#9799](https://github.com/rust-lang/cargo/pull/9799) - Entries in `cargo --list` are now deduplicated. [#9773](https://github.com/rust-lang/cargo/pull/9773) - Aliases are now included in `cargo --list`. [#9764](https://github.com/rust-lang/cargo/pull/9764) ### Fixed - Fixed panic with build-std of a proc-macro. [#9834](https://github.com/rust-lang/cargo/pull/9834) - Fixed running `cargo` recursively from proc-macros while running `cargo fix`. [#9818](https://github.com/rust-lang/cargo/pull/9818) - Return an error instead of a stack overflow for command alias loops. [#9791](https://github.com/rust-lang/cargo/pull/9791) - Updated to curl 7.79.1, which will hopefully fix intermittent http2 errors. [#9937](https://github.com/rust-lang/cargo/pull/9937) ### Nightly only - Added `[future-incompat-report]` config section. [#9774](https://github.com/rust-lang/cargo/pull/9774) - Fixed value-after-table error with custom named profiles. [#9789](https://github.com/rust-lang/cargo/pull/9789) - Added the `different-binary-name` feature to support specifying a non-rust-identifier for a binary name. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#different-binary-name) [#9627](https://github.com/rust-lang/cargo/pull/9627) - Added a profile option to select the codegen backend. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#codegen-backend) [#9118](https://github.com/rust-lang/cargo/pull/9118) ## Cargo 1.55 (2021-09-09) [aa8b0929...rust-1.55.0](https://github.com/rust-lang/cargo/compare/aa8b0929...rust-1.55.0) ### Added - The package definition in `cargo metadata` now includes the `"default_run"` field from the manifest. [#9550](https://github.com/rust-lang/cargo/pull/9550) - ❗ Build scripts now have access to the following environment variables: `RUSTC_WRAPPER`, `RUSTC_WORKSPACE_WRAPPER`, `CARGO_ENCODED_RUSTFLAGS`. `RUSTFLAGS` is no longer set for build scripts; they should use `CARGO_ENCODED_RUSTFLAGS` instead. [docs](https://doc.rust-lang.org/nightly/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts) [#9601](https://github.com/rust-lang/cargo/pull/9601) - Added `cargo d` as an alias for `cargo doc`. [#9680](https://github.com/rust-lang/cargo/pull/9680) - Added `{lib}` to the `cargo tree --format` option to display the library name of a package. [#9663](https://github.com/rust-lang/cargo/pull/9663) - Added `members_mut` method to the `Workspace` API. [#9547](https://github.com/rust-lang/cargo/pull/9547) ### Changed - If a build command does not match any targets when using the `--all-targets`, `--bins`, `--tests`, `--examples`, or `--benches` flags, a warning is now displayed to inform you that there were no matching targets. [#9549](https://github.com/rust-lang/cargo/pull/9549) - The way `cargo init` detects whether or not existing source files represent a binary or library has been changed to respect the command-line flags instead of trying to guess which type it is. [#9522](https://github.com/rust-lang/cargo/pull/9522) - Registry names are now displayed instead of registry URLs when possible. [#9632](https://github.com/rust-lang/cargo/pull/9632) - Duplicate compiler diagnostics are no longer shown. This can often happen with `cargo test` which builds multiple copies of the same code in parallel. This also updates the warning summary to provide more context. [#9675](https://github.com/rust-lang/cargo/pull/9675) - The output for warnings or errors is now improved to be leaner, cleaner, and show more context. [#9655](https://github.com/rust-lang/cargo/pull/9655) - Network send errors are now treated as "spurious" which means they will be retried. [#9695](https://github.com/rust-lang/cargo/pull/9695) - Git keys (`branch`, `tag`, `rev`) on a non-git dependency are now an error. Additionally, specifying both `git` and `path` is now an error. [#9689](https://github.com/rust-lang/cargo/pull/9689) - Specifying a dependency without any keys is now an error. [#9686](https://github.com/rust-lang/cargo/pull/9686) - The resolver now prefers to use `[patch]` table entries of dependencies when possible. [#9639](https://github.com/rust-lang/cargo/pull/9639) - Package name typo errors in dependencies are now displayed aligned with the original to help make it easier to see the difference. [#9665](https://github.com/rust-lang/cargo/pull/9665) - Windows platforms may now warn on environment variables that have the wrong case. [#9654](https://github.com/rust-lang/cargo/pull/9654) - `features` used in a `[patch]` table now issues a warning, as they are ignored. [#9666](https://github.com/rust-lang/cargo/pull/9666) - The `target` directory is now excluded from content indexing on Windows. [#9635](https://github.com/rust-lang/cargo/pull/9635) - When `Cargo.toml` is not found, the error message now detects if it was misnamed with a lowercase `c` to suggest the correct form. [#9607](https://github.com/rust-lang/cargo/pull/9607) - Building `diesel` with the new resolver displays a compatibility notice. [#9602](https://github.com/rust-lang/cargo/pull/9602) - Updated the `opener` dependency, which handles opening a web browser, which includes several changes, such as new behavior when run on WSL, and using the system `xdg-open` on Linux. [#9583](https://github.com/rust-lang/cargo/pull/9583) - Updated to libcurl 7.78. [#9809](https://github.com/rust-lang/cargo/pull/9809) [#9810](https://github.com/rust-lang/cargo/pull/9810) ### Fixed - Fixed dep-info files including non-local build script paths. [#9596](https://github.com/rust-lang/cargo/pull/9596) - Handle "jobs = 0" case in cargo config files [#9584](https://github.com/rust-lang/cargo/pull/9584) - Implement warning for ignored trailing arguments after `--` [#9561](https://github.com/rust-lang/cargo/pull/9561) - Fixed rustc/rustdoc config values to be config-relative. [#9566](https://github.com/rust-lang/cargo/pull/9566) - `cargo fix` now supports rustc's suggestions with multiple spans. [#9567](https://github.com/rust-lang/cargo/pull/9567) - `cargo fix` now fixes each target serially instead of in parallel to avoid problems with fixing the same file concurrently. [#9677](https://github.com/rust-lang/cargo/pull/9677) - Changes to the target `linker` config value now trigger a rebuild. [#9647](https://github.com/rust-lang/cargo/pull/9647) - Git unstaged deleted files are now ignored when using the `--allow-dirty` flag with `cargo publish` or `cargo package`. [#9645](https://github.com/rust-lang/cargo/pull/9645) ### Nightly only - Enabled support for `cargo fix --edition` for 2021. [#9588](https://github.com/rust-lang/cargo/pull/9588) - Several changes to named profiles. [#9685](https://github.com/rust-lang/cargo/pull/9685) - Extended instructions on what to do when running `cargo fix --edition` on the 2021 edition. [#9694](https://github.com/rust-lang/cargo/pull/9694) - Multiple updates to error messages using nightly features to help better explain the situation. [#9657](https://github.com/rust-lang/cargo/pull/9657) - Adjusted the edition 2021 resolver diff report. [#9649](https://github.com/rust-lang/cargo/pull/9649) - Fixed error using `cargo doc --open` with `doc.extern-map`. [#9531](https://github.com/rust-lang/cargo/pull/9531) - Unified weak and namespaced features. [#9574](https://github.com/rust-lang/cargo/pull/9574) - Various updates to future-incompatible reporting. [#9606](https://github.com/rust-lang/cargo/pull/9606) - `[env]` environment variables are not allowed to set vars set by Cargo. [#9579](https://github.com/rust-lang/cargo/pull/9579) ## Cargo 1.54 (2021-07-29) [4369396c...rust-1.54.0](https://github.com/rust-lang/cargo/compare/4369396c...rust-1.54.0) ### Added - Fetching from a git repository (such as the crates.io index) now displays the network transfer rate. [#9395](https://github.com/rust-lang/cargo/pull/9395) - Added `--prune` option for `cargo tree` to limit what is displayed. [#9520](https://github.com/rust-lang/cargo/pull/9520) - Added `--depth` option for `cargo tree` to limit what is displayed. [#9499](https://github.com/rust-lang/cargo/pull/9499) - Added `cargo tree -e no-proc-macro` to hide procedural macro dependencies. [#9488](https://github.com/rust-lang/cargo/pull/9488) - Added `doc.browser` config option to set which browser to open with `cargo doc --open`. [#9473](https://github.com/rust-lang/cargo/pull/9473) - Added `CARGO_TARGET_TMPDIR` environment variable set for integration tests & benches. This provides a temporary or "scratch" directory in the `target` directory for tests and benches to use. [#9375](https://github.com/rust-lang/cargo/pull/9375) ### Changed - `--features` CLI flags now provide typo suggestions with the new feature resolver. [#9420](https://github.com/rust-lang/cargo/pull/9420) - Cargo now uses a new parser for SemVer versions. This should behave mostly the same as before with some minor exceptions where invalid syntax for version requirements is now rejected. [#9508](https://github.com/rust-lang/cargo/pull/9508) - Mtime handling of `.crate` published packages has changed slightly to avoid mtime values of 0. This was causing problems with lldb which refused to read those files. [#9517](https://github.com/rust-lang/cargo/pull/9517) - Improved performance of git status check in `cargo package`. [#9478](https://github.com/rust-lang/cargo/pull/9478) - `cargo new` with fossil now places the ignore settings in the new repository instead of using `fossil settings` to set them globally. This also includes several other cleanups to make it more consistent with other VCS configurations. [#9469](https://github.com/rust-lang/cargo/pull/9469) - `rustc-cdylib-link-arg` applying transitively displays a warning that this was not intended, and may be an error in the future. [#9563](https://github.com/rust-lang/cargo/pull/9563) ### Fixed - Fixed `package.exclude` in `Cargo.toml` using inverted exclusions (`!somefile`) when not in a git repository or when vendoring a dependency. [#9186](https://github.com/rust-lang/cargo/pull/9186) - Dep-info files now adjust build script `rerun-if-changed` paths to be absolute paths. [#9421](https://github.com/rust-lang/cargo/pull/9421) - Fixed a bug when with resolver = "1" non-virtual package was allowing unknown features. [#9437](https://github.com/rust-lang/cargo/pull/9437) - Fixed an issue with the index cache mishandling versions that only differed in build metadata (such as `110.0.0` and `110.0.0+1.1.0f`). [#9476](https://github.com/rust-lang/cargo/pull/9476) - Fixed `cargo install` with a semver metadata version. [#9467](https://github.com/rust-lang/cargo/pull/9467) ### Nightly only - Added `report` subcommand, and changed `cargo describe-future-incompatibilitie` to `cargo report future-incompatibilities`. [#9438](https://github.com/rust-lang/cargo/pull/9438) - Added a `[host]` table to the config files to be able to set build flags for host target. Also added `target-applies-to-host` to control how the `[target]` tables behave. [#9322](https://github.com/rust-lang/cargo/pull/9322) - Added some validation to build script `rustc-link-arg-*` instructions to return an error if the target doesn't exist. [#9523](https://github.com/rust-lang/cargo/pull/9523) - Added `cargo:rustc-link-arg-bin` instruction for build scripts. [#9486](https://github.com/rust-lang/cargo/pull/9486) ## Cargo 1.53 (2021-06-17) [90691f2b...rust-1.53.0](https://github.com/rust-lang/cargo/compare/90691f2b...rust-1.53.0) ### Added ### Changed - πŸ”₯ Cargo now supports git repositories where the default `HEAD` branch is not "master". This also includes a switch to the version 3 `Cargo.lock` format which can handle default branches correctly. [#9133](https://github.com/rust-lang/cargo/pull/9133) [#9397](https://github.com/rust-lang/cargo/pull/9397) [#9384](https://github.com/rust-lang/cargo/pull/9384) [#9392](https://github.com/rust-lang/cargo/pull/9392) - πŸ”₯ macOS targets now default to `unpacked` split-debuginfo. [#9298](https://github.com/rust-lang/cargo/pull/9298) - ❗ The `authors` field is no longer included in `Cargo.toml` for new projects. [#9282](https://github.com/rust-lang/cargo/pull/9282) - `cargo update` may now work with the `--offline` flag. [#9279](https://github.com/rust-lang/cargo/pull/9279) - `cargo doc` will now erase the `doc` directory when switching between different toolchain versions. There are shared, unversioned files (such as the search index) that can become broken when using different versions. [#8640](https://github.com/rust-lang/cargo/pull/8640) [#9404](https://github.com/rust-lang/cargo/pull/9404) - Improved error messages when path dependency/workspace member is missing. [#9368](https://github.com/rust-lang/cargo/pull/9368) ### Fixed - Fixed `cargo doc` detecting if the documentation needs to be rebuilt when changing some settings such as features. [#9419](https://github.com/rust-lang/cargo/pull/9419) - `cargo doc` now deletes the output directory for the package before running rustdoc to clear out any stale files. [#9419](https://github.com/rust-lang/cargo/pull/9419) - Fixed the `-C metadata` value to always include all information for all builds. Previously, in some situations, the hash only included the package name and version. This fixes some issues, such as incremental builds with split-debuginfo on macOS corrupting the incremental cache in some cases. [#9418](https://github.com/rust-lang/cargo/pull/9418) - Fixed man pages not working on Windows if `man` is in `PATH`. [#9378](https://github.com/rust-lang/cargo/pull/9378) - The `rustc` cache is now aware of `RUSTC_WRAPPER` and `RUSTC_WORKSPACE_WRAPPER`. [#9348](https://github.com/rust-lang/cargo/pull/9348) - Track the `CARGO` environment variable in the rebuild fingerprint if the code uses `env!("CARGO")`. [#9363](https://github.com/rust-lang/cargo/pull/9363) ### Nightly only - Fixed config includes not working. [#9299](https://github.com/rust-lang/cargo/pull/9299) - Emit note when `--future-incompat-report` had nothing to report. [#9263](https://github.com/rust-lang/cargo/pull/9263) - Error messages for nightly features flags (like `-Z` and `cargo-features`) now provides more information. [#9290](https://github.com/rust-lang/cargo/pull/9290) - Added the ability to set the target for an individual package in `Cargo.toml`. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#per-package-target) [#9030](https://github.com/rust-lang/cargo/pull/9030) - Fixed build-std updating the index on every build. [#9393](https://github.com/rust-lang/cargo/pull/9393) - `-Z help` now displays all the `-Z` options. [#9369](https://github.com/rust-lang/cargo/pull/9369) - Added `-Zallow-features` to specify which nightly features are allowed to be used. [#9283](https://github.com/rust-lang/cargo/pull/9283) - Added `cargo config` subcommand. [#9302](https://github.com/rust-lang/cargo/pull/9302) ## Cargo 1.52 (2021-05-06) [34170fcd...rust-1.52.0](https://github.com/rust-lang/cargo/compare/34170fcd...rust-1.52.0) ### Added - Added the `"manifest_path"` field to JSON messages for a package. [#9022](https://github.com/rust-lang/cargo/pull/9022) [#9247](https://github.com/rust-lang/cargo/pull/9247) ### Changed - Build scripts are now forbidden from setting `RUSTC_BOOTSTRAP` on stable. [#9181](https://github.com/rust-lang/cargo/pull/9181) [#9385](https://github.com/rust-lang/cargo/pull/9385) - crates.io now supports SPDX 3.11 licenses. [#9209](https://github.com/rust-lang/cargo/pull/9209) - An error is now reported if `CARGO_TARGET_DIR` is an empty string. [#8939](https://github.com/rust-lang/cargo/pull/8939) - Doc tests now pass the `--message-format` flag into the test so that the "short" format can now be used for doc tests. [#9128](https://github.com/rust-lang/cargo/pull/9128) - `cargo test` now prints a clearer indicator of which target is currently running. [#9195](https://github.com/rust-lang/cargo/pull/9195) - The `CARGO_TARGET_` environment variable will now issue a warning if it is using lowercase letters. [#9169](https://github.com/rust-lang/cargo/pull/9169) ### Fixed - Fixed publication of packages with metadata and resolver fields in `Cargo.toml`. [#9300](https://github.com/rust-lang/cargo/pull/9300) [#9304](https://github.com/rust-lang/cargo/pull/9304) - Fixed logic for determining prefer-dynamic for a dylib which differed in a workspace vs a single package. [#9252](https://github.com/rust-lang/cargo/pull/9252) - Fixed an issue where exclusive target-specific dependencies that overlapped across dependency kinds (like regular and build-dependencies) would incorrectly include the dependencies in both. [#9255](https://github.com/rust-lang/cargo/pull/9255) - Fixed panic with certain styles of Package IDs when passed to the `-p` flag. [#9188](https://github.com/rust-lang/cargo/pull/9188) - When running cargo with output not going to a TTY, and with the progress bar and color force-enabled, the output will now correctly clear the progress line. [#9231](https://github.com/rust-lang/cargo/pull/9231) - Error instead of panic when JSON may contain non-utf8 paths. [#9226](https://github.com/rust-lang/cargo/pull/9226) - Fixed a hang that can happen on broken stderr. [#9201](https://github.com/rust-lang/cargo/pull/9201) - Fixed thin-local LTO not being disabled correctly when `lto=off` is set. [#9182](https://github.com/rust-lang/cargo/pull/9182) ### Nightly only - The `strip` profile option now supports `true` and `false` values. [#9153](https://github.com/rust-lang/cargo/pull/9153) - `cargo fix --edition` now displays a report when switching to 2021 if the new resolver changes features. [#9268](https://github.com/rust-lang/cargo/pull/9268) - Added `[patch]` table support in `.cargo/config` files. [#9204](https://github.com/rust-lang/cargo/pull/9204) - Added `cargo describe-future-incompatibilities` for generating a report on dependencies that contain future-incompatible warnings. [#8825](https://github.com/rust-lang/cargo/pull/8825) - Added easier support for testing the 2021 edition. [#9184](https://github.com/rust-lang/cargo/pull/9184) - Switch the default resolver to "2" in the 2021 edition. [#9184](https://github.com/rust-lang/cargo/pull/9184) - `cargo fix --edition` now supports 2021. [#9184](https://github.com/rust-lang/cargo/pull/9184) - Added `--print` flag to `cargo rustc` to pass along to `rustc` to display information from rustc. [#9002](https://github.com/rust-lang/cargo/pull/9002) - Added `-Zdoctest-in-workspace` for changing the directory where doctests are *run* versus where they are *compiled*. [#9105](https://github.com/rust-lang/cargo/pull/9105) - Added support for an `[env]` section in `.cargo/config.toml` to set environment variables when running cargo. [#9175](https://github.com/rust-lang/cargo/pull/9175) - Added a schema field and `features2` field to the index. [#9161](https://github.com/rust-lang/cargo/pull/9161) - Changes to JSON spec targets will now trigger a rebuild. [#9223](https://github.com/rust-lang/cargo/pull/9223) ## Cargo 1.51 (2021-03-25) [75d5d8cf...rust-1.51.0](https://github.com/rust-lang/cargo/compare/75d5d8cf...rust-1.51.0) ### Added - πŸ”₯ Added the `split-debuginfo` profile option. [docs](https://doc.rust-lang.org/nightly/cargo/reference/profiles.html#split-debuginfo) [#9112](https://github.com/rust-lang/cargo/pull/9112) - Added the `path` field to `cargo metadata` for the package dependencies list to show the path for "path" dependencies. [#8994](https://github.com/rust-lang/cargo/pull/8994) - πŸ”₯ Added a new feature resolver, and new CLI feature flag behavior. See the new [features](https://doc.rust-lang.org/nightly/cargo/reference/features.html#feature-resolver-version-2) and [resolver](https://doc.rust-lang.org/nightly/cargo/reference/resolver.html#feature-resolver-version-2) documentation for the `resolver = "2"` option. See the [CLI](https://doc.rust-lang.org/nightly/cargo/reference/features.html#command-line-feature-options) and [resolver 2 CLI](https://doc.rust-lang.org/nightly/cargo/reference/features.html#resolver-version-2-command-line-flags) options for the new CLI behavior. And, finally, see [RFC 2957](https://github.com/rust-lang/rfcs/blob/master/text/2957-cargo-features2.md) for a detailed look at what has changed. [#8997](https://github.com/rust-lang/cargo/pull/8997) ### Changed - `cargo install --locked` now emits a warning if `Cargo.lock` is not found. [#9108](https://github.com/rust-lang/cargo/pull/9108) - Unknown or ambiguous package IDs passed on the command-line now display suggestions for the correct package ID. [#9095](https://github.com/rust-lang/cargo/pull/9095) - Slightly optimize `cargo vendor` [#8937](https://github.com/rust-lang/cargo/pull/8937) [#9131](https://github.com/rust-lang/cargo/pull/9131) [#9132](https://github.com/rust-lang/cargo/pull/9132) ### Fixed - Fixed environment variables and cfg settings emitted by a build script that are set for `cargo test` and `cargo run` when the build script runs multiple times during the same build session. [#9122](https://github.com/rust-lang/cargo/pull/9122) - Fixed a panic with `cargo doc` and the new feature resolver. This also introduces some heuristics to try to avoid path collisions with `rustdoc` by only documenting one variant of a package if there are multiple (such as multiple versions, or the same package shared for host and target platforms). [#9077](https://github.com/rust-lang/cargo/pull/9077) - Fixed a bug in Cargo's cyclic dep graph detection that caused a stack overflow. [#9075](https://github.com/rust-lang/cargo/pull/9075) - Fixed build script `links` environment variables (`DEP_*`) not showing up for testing packages in some cases. [#9065](https://github.com/rust-lang/cargo/pull/9065) - Fixed features being selected in a nondeterministic way for a specific scenario when building an entire workspace with all targets with a proc-macro in the workspace with `resolver="2"`. [#9059](https://github.com/rust-lang/cargo/pull/9059) - Fixed to use `http.proxy` setting in `~/.gitconfig`. [#8986](https://github.com/rust-lang/cargo/pull/8986) - Fixed --feature pkg/feat for V1 resolver for non-member. [#9275](https://github.com/rust-lang/cargo/pull/9275) [#9277](https://github.com/rust-lang/cargo/pull/9277) - Fixed panic in `cargo doc` when there are colliding output filenames in a workspace. [#9276](https://github.com/rust-lang/cargo/pull/9276) [#9277](https://github.com/rust-lang/cargo/pull/9277) - Fixed `cargo install` from exiting with success if one of several packages did not install successfully. [#9185](https://github.com/rust-lang/cargo/pull/9185) [#9196](https://github.com/rust-lang/cargo/pull/9196) - Fix panic with doc collision orphan. [#9142](https://github.com/rust-lang/cargo/pull/9142) [#9196](https://github.com/rust-lang/cargo/pull/9196) ### Nightly only - Removed the `publish-lockfile` unstable feature, it was stabilized without the need for an explicit flag 1.5 years ago. [#9092](https://github.com/rust-lang/cargo/pull/9092) - Added better diagnostics, help messages, and documentation for nightly features (such as those passed with the `-Z` flag, or specified with `cargo-features` in `Cargo.toml`). [#9092](https://github.com/rust-lang/cargo/pull/9092) - Added support for Rust edition 2021. [#8922](https://github.com/rust-lang/cargo/pull/8922) - Added support for the `rust-version` field in project metadata. [#8037](https://github.com/rust-lang/cargo/pull/8037) - Added a schema field to the index. [#9161](https://github.com/rust-lang/cargo/pull/9161) [#9196](https://github.com/rust-lang/cargo/pull/9196) ## Cargo 1.50 (2021-02-11) [8662ab42...rust-1.50.0](https://github.com/rust-lang/cargo/compare/8662ab42...rust-1.50.0) ### Added - Added the `doc` field to `cargo metadata`, which indicates if a target is documented. [#8869](https://github.com/rust-lang/cargo/pull/8869) - Added `RUSTC_WORKSPACE_WRAPPER`, an alternate RUSTC wrapper that only runs for the local workspace packages, and caches its artifacts independently of non-wrapped builds. [#8976](https://github.com/rust-lang/cargo/pull/8976) - Added `--workspace` to `cargo update` to update only the workspace members, and not their dependencies. This is particularly useful if you update the version in `Cargo.toml` and want to update `Cargo.lock` without running any other commands. [#8725](https://github.com/rust-lang/cargo/pull/8725) ### Changed - `.crate` files uploaded to a registry are now built with reproducible settings, so that the same `.crate` file created on different machines should be identical. [#8864](https://github.com/rust-lang/cargo/pull/8864) - Git dependencies that specify more than one of `branch`, `tag`, or `rev` are now rejected. [#8984](https://github.com/rust-lang/cargo/pull/8984) - The `rerun-if-changed` build script directive can now point to a directory, in which case Cargo will check if any file in that directory changes. [#8973](https://github.com/rust-lang/cargo/pull/8973) - If Cargo cannot determine the username or email address, `cargo new` will no longer fail, and instead create an empty authors list. [#8912](https://github.com/rust-lang/cargo/pull/8912) - The progress bar width has been reduced to provide more room to display the crates currently being built. [#8892](https://github.com/rust-lang/cargo/pull/8892) - `cargo new` will now support `includeIf` directives in `.gitconfig` to match the correct directory when determining the username and email address. [#8886](https://github.com/rust-lang/cargo/pull/8886) ### Fixed - Fixed `cargo metadata` and `cargo tree` to only download packages for the requested target. [#8987](https://github.com/rust-lang/cargo/pull/8987) - Updated libgit2, which brings in many fixes, particularly fixing a zlib error that occasionally appeared on 32-bit systems. [#8998](https://github.com/rust-lang/cargo/pull/8998) - Fixed stack overflow with a circular dev-dependency that uses the `links` field. [#8969](https://github.com/rust-lang/cargo/pull/8969) - Fixed `cargo publish` failing on some filesystems, particularly 9p on WSL2. [#8950](https://github.com/rust-lang/cargo/pull/8950) ### Nightly only - Allow `resolver="1"` to specify the original feature resolution behavior. [#8857](https://github.com/rust-lang/cargo/pull/8857) - Added `-Z extra-link-arg` which adds the `cargo:rustc-link-arg-bins` and `cargo:rustc-link-arg` build script options. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#extra-link-arg) [#8441](https://github.com/rust-lang/cargo/pull/8441) - Implemented external credential process support, and added `cargo logout`. ([RFC 2730](https://github.com/rust-lang/rfcs/blob/master/text/2730-cargo-token-from-process.md)) ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process)) [#8934](https://github.com/rust-lang/cargo/pull/8934) - Fix panic with `-Zbuild-std` and no roots. [#8942](https://github.com/rust-lang/cargo/pull/8942) - Set docs.rs as the default extern-map for crates.io [#8877](https://github.com/rust-lang/cargo/pull/8877) ## Cargo 1.49 (2020-12-31) [75615f8e...rust-1.49.0](https://github.com/rust-lang/cargo/compare/75615f8e...rust-1.49.0) ### Added - Added `homepage` and `documentation` fields to `cargo metadata`. [#8744](https://github.com/rust-lang/cargo/pull/8744) - Added the `CARGO_PRIMARY_PACKAGE` environment variable which is set when running `rustc` if the package is one of the "root" packages selected on the command line. [#8758](https://github.com/rust-lang/cargo/pull/8758) - Added support for Unix-style glob patterns for package and target selection flags on the command-line (such as `-p 'serde*'` or `--test '*'`). [#8752](https://github.com/rust-lang/cargo/pull/8752) ### Changed - Computed LTO flags are now included in the filename metadata hash so that changes in LTO settings will independently cache build artifacts instead of overwriting previous ones. This prevents rebuilds in some situations such as switching between `cargo build` and `cargo test` in some circumstances. [#8755](https://github.com/rust-lang/cargo/pull/8755) - `cargo tree` now displays `(proc-macro)` next to proc-macro packages. [#8765](https://github.com/rust-lang/cargo/pull/8765) - Added a warning that the allowed characters for a feature name have been restricted to letters, digits, `_`, `-`, and `+` to accommodate future syntax changes. This is still a superset of the allowed syntax on crates.io, which requires ASCII. This is intended to be changed to an error in the future. [#8814](https://github.com/rust-lang/cargo/pull/8814) - `-p` without a value will now print a list of workspace package names. [#8808](https://github.com/rust-lang/cargo/pull/8808) - Add period to allowed feature name characters. [#8932](https://github.com/rust-lang/cargo/pull/8932) [#8943](https://github.com/rust-lang/cargo/pull/8943) ### Fixed - Fixed building a library with both "dylib" and "rlib" crate types with LTO enabled. [#8754](https://github.com/rust-lang/cargo/pull/8754) - Fixed paths in Cargo's dep-info files. [#8819](https://github.com/rust-lang/cargo/pull/8819) - Fixed inconsistent source IDs in `cargo metadata` for git dependencies that explicitly specify `branch="master"`. [#8824](https://github.com/rust-lang/cargo/pull/8824) - Fixed re-extracting dependencies which contained a `.cargo-ok` file. [#8835](https://github.com/rust-lang/cargo/pull/8835) ### Nightly only - Fixed a panic with `cargo doc -Zfeatures=itarget` in some situations. [#8777](https://github.com/rust-lang/cargo/pull/8777) - New implementation for namespaced features, using the syntax `dep:serde`. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#namespaced-features) [#8799](https://github.com/rust-lang/cargo/pull/8799) - Added support for "weak" dependency features, using the syntax `dep_name?/feat_name`, which will enable a feature for a dependency without also enabling the dependency. [#8818](https://github.com/rust-lang/cargo/pull/8818) - Fixed the new feature resolver downloading extra dependencies that weren't strictly necessary. [#8823](https://github.com/rust-lang/cargo/pull/8823) ## Cargo 1.48 (2020-11-19) [51b66125...rust-1.48.0](https://github.com/rust-lang/cargo/compare/51b66125...rust-1.48.0) ### Added - Added `term.progress` configuration option to control when and how the progress bar is displayed. [docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#termprogresswhen) [#8165](https://github.com/rust-lang/cargo/pull/8165) - Added `--message-format plain` option to `cargo locate-project` to display the project location without JSON to make it easier to use in a script. [#8707](https://github.com/rust-lang/cargo/pull/8707) - Added `--workspace` option to `cargo locate-project` to display the path to the workspace manifest. [#8712](https://github.com/rust-lang/cargo/pull/8712) - A new contributor guide has been added for contributing to Cargo itself. This is published at . [#8715](https://github.com/rust-lang/cargo/pull/8715) - Zsh `--target` completion will now complete with the built-in rustc targets. [#8740](https://github.com/rust-lang/cargo/pull/8740) ### Changed ### Fixed - Fixed `cargo new` creating a fossil repository to properly ignore the `target` directory. [#8671](https://github.com/rust-lang/cargo/pull/8671) - Don't show warnings about the workspace in the current directory when using `cargo install` of a remote package. [#8681](https://github.com/rust-lang/cargo/pull/8681) - Automatically reinitialize the index when an "Object not found" error is encountered in the git repository. [#8735](https://github.com/rust-lang/cargo/pull/8735) - Updated libgit2, which brings in several fixes for git repository handling. [#8778](https://github.com/rust-lang/cargo/pull/8778) [#8780](https://github.com/rust-lang/cargo/pull/8780) ### Nightly only - Fixed `cargo install` so that it will ignore the `[unstable]` table in local config files. [#8656](https://github.com/rust-lang/cargo/pull/8656) - Fixed nondeterministic behavior of the new feature resolver. [#8701](https://github.com/rust-lang/cargo/pull/8701) - Fixed running `cargo test` on a proc-macro with the new feature resolver under a specific combination of circumstances. [#8742](https://github.com/rust-lang/cargo/pull/8742) ## Cargo 1.47 (2020-10-08) [4f74d9b2...rust-1.47.0](https://github.com/rust-lang/cargo/compare/4f74d9b2...rust-1.47.0) ### Added - `cargo doc` will now include the package's version in the left sidebar. [#8509](https://github.com/rust-lang/cargo/pull/8509) - Added the `test` field to `cargo metadata` targets. [#8478](https://github.com/rust-lang/cargo/pull/8478) - Cargo's man pages are now displayed via the `cargo help` command (such as `cargo help build`). [#8456](https://github.com/rust-lang/cargo/pull/8456) [#8577](https://github.com/rust-lang/cargo/pull/8577) - Added new documentation chapters on [how dependency resolution works](https://doc.rust-lang.org/nightly/cargo/reference/resolver.html) and [SemVer compatibility](https://doc.rust-lang.org/nightly/cargo/reference/semver.html), along with suggestions on how to version your project and work with dependencies. [#8609](https://github.com/rust-lang/cargo/pull/8609) ### Changed - The comments added to `.gitignore` when it is modified have been tweaked to add some spacing. [#8476](https://github.com/rust-lang/cargo/pull/8476) - `cargo metadata` output should now be sorted to be deterministic. [#8489](https://github.com/rust-lang/cargo/pull/8489) - By default, build scripts and proc-macros are now built with `opt-level=0` and the default codegen units, even in release mode. [#8500](https://github.com/rust-lang/cargo/pull/8500) - `workspace.default-members` is now filtered by `workspace.exclude`. [#8485](https://github.com/rust-lang/cargo/pull/8485) - `workspace.members` globs now ignore non-directory paths. [#8511](https://github.com/rust-lang/cargo/pull/8511) - git zlib errors now trigger a retry. [#8520](https://github.com/rust-lang/cargo/pull/8520) - "http" class git errors now trigger a retry. [#8553](https://github.com/rust-lang/cargo/pull/8553) - git dependencies now override the `core.autocrlf` git configuration value to ensure they behave consistently across platforms, particularly when vendoring git dependencies on Windows. [#8523](https://github.com/rust-lang/cargo/pull/8523) - If `Cargo.lock` needs to be updated, then it will be automatically transitioned to the new V2 format. This format removes the `[metadata]` table, and should be easier to merge changes in source control systems. This format was introduced in 1.38, and made the default for new projects in 1.41. [#8554](https://github.com/rust-lang/cargo/pull/8554) - Added preparation for support of git repositories with a non-"master" default branch. Actual support will arrive in a future version. This introduces some warnings: - Warn if a git dependency does not specify a branch, and the default branch on the repository is not "master". In the future, Cargo will fetch the default branch. In this scenario, the branch should be explicitly specified. - Warn if a workspace has multiple dependencies to the same git repository, one without a `branch` and one with `branch="master"`. Dependencies should all use one form or the other. [#8522](https://github.com/rust-lang/cargo/pull/8522) - Warnings are now issued if a `required-features` entry lists a feature that does not exist. [#7950](https://github.com/rust-lang/cargo/pull/7950) - Built-in aliases are now included in `cargo --list`. [#8542](https://github.com/rust-lang/cargo/pull/8542) - `cargo install` with a specific version that has been yanked will now display an error message that it has been yanked, instead of "could not find". [#8565](https://github.com/rust-lang/cargo/pull/8565) - `cargo publish` with a package that has the `publish` field set to a single registry, and no `--registry` flag has been given, will now publish to that registry instead of generating an error. [#8571](https://github.com/rust-lang/cargo/pull/8571) ### Fixed - Fixed issue where if a project directory was moved, and one of the build scripts did not use the `rerun-if-changed` directive, then that build script was being rebuilt when it shouldn't. [#8497](https://github.com/rust-lang/cargo/pull/8497) - Console colors should now work on Windows 7 and 8. [#8540](https://github.com/rust-lang/cargo/pull/8540) - The `CARGO_TARGET_{triplet}_RUNNER` environment variable will now correctly override the config file instead of trying to merge the commands. [#8629](https://github.com/rust-lang/cargo/pull/8629) - Fixed LTO with doctests. [#8657](https://github.com/rust-lang/cargo/pull/8657) [#8658](https://github.com/rust-lang/cargo/pull/8658) ### Nightly only - Added support for `-Z terminal-width` which tells `rustc` the width of the terminal so that it can format diagnostics better. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#terminal-width) [#8427](https://github.com/rust-lang/cargo/pull/8427) - Added ability to configure `-Z` unstable flags in config files via the `[unstable]` table. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html) [#8393](https://github.com/rust-lang/cargo/pull/8393) - Added `-Z build-std-features` flag to set features for the standard library. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std-features) [#8490](https://github.com/rust-lang/cargo/pull/8490) ## Cargo 1.46 (2020-08-27) [9fcb8c1d...rust-1.46.0](https://github.com/rust-lang/cargo/compare/9fcb8c1d...rust-1.46.0) ### Added - The `dl` key in `config.json` of a registry index now supports the replacement markers `{prefix}` and `{lowerprefix}` to allow spreading crates across directories similar to how the index itself is structured. [docs](https://doc.rust-lang.org/nightly/cargo/reference/registries.html#index-format) [#8267](https://github.com/rust-lang/cargo/pull/8267) - Added new environment variables that are set during compilation: - `CARGO_CRATE_NAME`: The name of the crate being built. - `CARGO_BIN_NAME`: The name of the executable binary (if this is a binary crate). - `CARGO_PKG_LICENSE`: The `license` field from the manifest. - `CARGO_PKG_LICENSE_FILE`: The `license-file` field from the manifest. [#8270](https://github.com/rust-lang/cargo/pull/8270) [#8325](https://github.com/rust-lang/cargo/pull/8325) [#8387](https://github.com/rust-lang/cargo/pull/8387) - If the value for `readme` is not specified in `Cargo.toml`, it is now automatically inferred from the existence of a file named `README`, `README.md`, or `README.txt`. This can be suppressed by setting `readme = false`. [#8277](https://github.com/rust-lang/cargo/pull/8277) - `cargo install` now supports the `--index` flag to install directly from an index. [#8344](https://github.com/rust-lang/cargo/pull/8344) - Added the `metadata` table to the `workspace` definition in `Cargo.toml`. This can be used for arbitrary data similar to the `package.metadata` table. [#8323](https://github.com/rust-lang/cargo/pull/8323) - Added the `--target-dir` flag to `cargo install` to set the target directory. [#8391](https://github.com/rust-lang/cargo/pull/8391) - Changes to environment variables used by the [`env!`](https://doc.rust-lang.org/std/macro.env.html) or [`option_env!`](https://doc.rust-lang.org/std/macro.option_env.html) macros are now automatically detected to trigger a rebuild. [#8421](https://github.com/rust-lang/cargo/pull/8421) - The `target` directory now includes the `CACHEDIR.TAG` file which is used by some tools to exclude the directory from backups. [#8378](https://github.com/rust-lang/cargo/pull/8378) - Added docs about rustup's `+toolchain` syntax. [#8455](https://github.com/rust-lang/cargo/pull/8455) ### Changed - A warning is now displayed if a git dependency includes a `#` fragment in the URL. This was potentially confusing because Cargo itself displays git URLs with this syntax, but it does not have any meaning outside of the `Cargo.lock` file, and would not work properly. [#8297](https://github.com/rust-lang/cargo/pull/8297) - Various optimizations and fixes for bitcode embedding and LTO. [#8349](https://github.com/rust-lang/cargo/pull/8349) - Reduced the amount of data fetched for git dependencies. If Cargo knows the branch or tag to fetch, it will now only fetch that branch or tag instead of all branches and tags. [#8363](https://github.com/rust-lang/cargo/pull/8363) - Enhanced git fetch error messages. [#8409](https://github.com/rust-lang/cargo/pull/8409) - `.crate` files are now generated with GNU tar format instead of UStar, which supports longer file names. [#8453](https://github.com/rust-lang/cargo/pull/8453) ### Fixed - Fixed a rare situation where an update to `Cargo.lock` failed once, but then subsequent runs allowed it proceed. [#8274](https://github.com/rust-lang/cargo/pull/8274) - Removed assertion that Windows dylibs must have a `.dll` extension. Some custom JSON spec targets may change the extension. [#8310](https://github.com/rust-lang/cargo/pull/8310) - Updated libgit2, which brings in a fix for zlib errors for some remote git servers like googlesource.com. [#8320](https://github.com/rust-lang/cargo/pull/8320) - Fixed the GitHub fast-path check for up-to-date git dependencies on non-master branches. [#8363](https://github.com/rust-lang/cargo/pull/8363) - Fixed issue when enabling a feature with `pkg/feature` syntax, and `pkg` is an optional dependency, but also a dev-dependency, and the dev-dependency appears before the optional normal dependency in the registry summary, then the optional dependency would not get activated. [#8395](https://github.com/rust-lang/cargo/pull/8395) - Fixed `clean -p` deleting the build directory if there is a test named `build`. [#8398](https://github.com/rust-lang/cargo/pull/8398) - Fixed indentation of multi-line Cargo error messages. [#8409](https://github.com/rust-lang/cargo/pull/8409) - Fixed issue where the automatic inclusion of the `--document-private-items` flag for rustdoc would override any flags passed to the `cargo rustdoc` command. [#8449](https://github.com/rust-lang/cargo/pull/8449) - Cargo will now include a version in the hash of the fingerprint directories to support backwards-incompatible changes to the fingerprint structure. [#8473](https://github.com/rust-lang/cargo/pull/8473) [#8488](https://github.com/rust-lang/cargo/pull/8488) ### Nightly only - Added `-Zrustdoc-map` feature which provides external mappings for rustdoc (such as https://docs.rs/ links). [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#rustdoc-map) [#8287](https://github.com/rust-lang/cargo/pull/8287) - Fixed feature calculation when a proc-macro is declared in `Cargo.toml` with an underscore (like `proc_macro = true`). [#8319](https://github.com/rust-lang/cargo/pull/8319) - Added support for setting `-Clinker` with `-Zdoctest-xcompile`. [#8359](https://github.com/rust-lang/cargo/pull/8359) - Fixed setting the `strip` profile field in config files. [#8454](https://github.com/rust-lang/cargo/pull/8454) ## Cargo 1.45 (2020-07-16) [ebda5065e...rust-1.45.0](https://github.com/rust-lang/cargo/compare/ebda5065...rust-1.45.0) ### Added ### Changed - Changed official documentation to recommend `.cargo/config.toml` filenames (with the `.toml` extension). `.toml` extension support was added in 1.39. [#8121](https://github.com/rust-lang/cargo/pull/8121) - The `registry.index` config value is no longer allowed (it has been deprecated for 4 years). [#7973](https://github.com/rust-lang/cargo/pull/7973) - An error is generated if both `--index` and `--registry` are passed (previously `--index` was silently ignored). [#7973](https://github.com/rust-lang/cargo/pull/7973) - The `registry.token` config value is no longer used with the `--index` flag. This is intended to avoid potentially leaking the crates.io token to another registry. [#7973](https://github.com/rust-lang/cargo/pull/7973) - Added a warning if `registry.token` is used with source replacement. It is intended this will be an error in future versions. [#7973](https://github.com/rust-lang/cargo/pull/7973) - Windows GNU targets now copy `.dll.a` import library files for DLL crate types to the output directory. [#8141](https://github.com/rust-lang/cargo/pull/8141) - Dylibs for all dependencies are now unconditionally copied to the output directory. Some obscure scenarios can cause an old dylib to be referenced between builds, and this ensures that all the latest copies are used. [#8139](https://github.com/rust-lang/cargo/pull/8139) - `package.exclude` can now match directory names. If a directory is specified, the entire directory will be excluded, and Cargo will not attempt to inspect it further. Previously Cargo would try to check every file in the directory which could cause problems if the directory contained unreadable files. [#8095](https://github.com/rust-lang/cargo/pull/8095) - When packaging with `cargo publish` or `cargo package`, Cargo can use git to guide its decision on which files to include. Previously this git-based logic required a `Cargo.toml` file to exist at the root of the repository. This is no longer required, so Cargo will now use git-based guidance even if there is not a `Cargo.toml` in the root of the repository. [#8095](https://github.com/rust-lang/cargo/pull/8095) - While unpacking a crate on Windows, if it fails to write a file because the file is a reserved Windows filename (like "aux.rs"), Cargo will display an extra message to explain why it failed. [#8136](https://github.com/rust-lang/cargo/pull/8136) - Failures to set mtime on files are now ignored. Some filesystems did not support this. [#8185](https://github.com/rust-lang/cargo/pull/8185) - Certain classes of git errors will now recommend enabling `net.git-fetch-with-cli`. [#8166](https://github.com/rust-lang/cargo/pull/8166) - When doing an LTO build, Cargo will now instruct rustc not to perform codegen when possible. This may result in a faster build and use less disk space. Additionally, for non-LTO builds, Cargo will instruct rustc to not embed LLVM bitcode in libraries, which should decrease their size. [#8192](https://github.com/rust-lang/cargo/pull/8192) [#8226](https://github.com/rust-lang/cargo/pull/8226) [#8254](https://github.com/rust-lang/cargo/pull/8254) - The implementation for `cargo clean -p` has been rewritten so that it can more accurately remove the files for a specific package. [#8210](https://github.com/rust-lang/cargo/pull/8210) - The way Cargo computes the outputs from a build has been rewritten to be more complete and accurate. Newly tracked files will be displayed in JSON messages, and may be uplifted to the output directory in some cases. Some of the changes from this are: - `.exp` export files on Windows MSVC dynamic libraries are now tracked. - Proc-macros on Windows track import/export files. - All targets (like tests, etc.) that generate separate debug files (pdb/dSYM) are tracked. - Added .map files for wasm32-unknown-emscripten. - macOS dSYM directories are tracked for all dynamic libraries (dylib/cdylib/proc-macro) and for build scripts. There are a variety of other changes as a consequence of this: - Binary examples on Windows MSVC with a hyphen will now show up twice in the examples directory (`foo_bar.exe` and `foo-bar.exe`). Previously Cargo just renamed the file instead of hard-linking it. - Example libraries now follow the same rules for hyphen/underscore translation as normal libs (they will now use underscores). [#8210](https://github.com/rust-lang/cargo/pull/8210) - Cargo attempts to scrub any secrets from the debug log for HTTP debugging. [#8222](https://github.com/rust-lang/cargo/pull/8222) - Context has been added to many of Cargo's filesystem operations, so that error messages now provide more information, such as the path that caused the problem. [#8232](https://github.com/rust-lang/cargo/pull/8232) - Several commands now ignore the error if stdout or stderr is closed while it is running. For example `cargo install --list | grep -q cargo-fuzz` would previously sometimes panic because `grep -q` may close stdout before the command finishes. Regular builds continue to fail if stdout or stderr is closed, matching the behavior of many other build systems. [#8236](https://github.com/rust-lang/cargo/pull/8236) - If `cargo install` is given an exact version, like `--version=1.2.3`, it will now avoid updating the index if that version is already installed, and exit quickly indicating it is already installed. [#8022](https://github.com/rust-lang/cargo/pull/8022) - Changes to the `[patch]` section will now attempt to automatically update `Cargo.lock` to the new version. It should now also provide better error messages for the rare cases where it is unable to automatically update. [#8248](https://github.com/rust-lang/cargo/pull/8248) ### Fixed - Fixed copying Windows `.pdb` files to the output directory when the filename contained dashes. [#8123](https://github.com/rust-lang/cargo/pull/8123) - Fixed error where Cargo would fail when scanning if a package is inside a git repository when any of its ancestor paths is a symlink. [#8186](https://github.com/rust-lang/cargo/pull/8186) - Fixed `cargo update` with an unused `[patch]` so that it does not get stuck and refuse to update. [#8243](https://github.com/rust-lang/cargo/pull/8243) - Fixed a situation where Cargo would hang if stderr is closed, and the compiler generated a large number of messages. [#8247](https://github.com/rust-lang/cargo/pull/8247) - Fixed backtraces on macOS not showing filenames or line numbers. As a consequence of this, binary executables on apple targets do not include a hash in the filename in Cargo's cache. This means Cargo can only track one copy, so if you switch features or rustc versions, Cargo will need to rebuild the executable. [#8329](https://github.com/rust-lang/cargo/pull/8329) [#8335](https://github.com/rust-lang/cargo/pull/8335) - Fixed fingerprinting when using lld on Windows with a dylib. Cargo was erroneously thinking the dylib was never fresh. [#8290](https://github.com/rust-lang/cargo/pull/8290) [#8335](https://github.com/rust-lang/cargo/pull/8335) ### Nightly only - Fixed passing the full path for `--target` to `rustdoc` when using JSON spec targets. [#8094](https://github.com/rust-lang/cargo/pull/8094) - `-Cembed-bitcode=no` renamed to `-Cbitcode-in-rlib=no` [#8134](https://github.com/rust-lang/cargo/pull/8134) - Added new `resolver` field to `Cargo.toml` to opt-in to the new feature resolver. [#8129](https://github.com/rust-lang/cargo/pull/8129) - `-Zbuild-std` no longer treats std dependencies as "local". This means that it won't use incremental compilation for those dependencies, removes them from dep-info files, and caps lints at "allow". [#8177](https://github.com/rust-lang/cargo/pull/8177) - Added `-Zmultitarget` which allows multiple `--target` flags to build the same thing for multiple targets at once. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#multitarget) [#8167](https://github.com/rust-lang/cargo/pull/8167) - Added `strip` option to the profile to remove symbols and debug information. [docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#profile-strip-option) [#8246](https://github.com/rust-lang/cargo/pull/8246) - Fixed panic with `cargo tree --target=all -Zfeatures=all`. [#8269](https://github.com/rust-lang/cargo/pull/8269) ## Cargo 1.44 (2020-06-04) [bda50510...rust-1.44.0](https://github.com/rust-lang/cargo/compare/bda50510...rust-1.44.0) ### Added - πŸ”₯ Added the `cargo tree` command. [docs](https://doc.rust-lang.org/nightly/cargo/commands/cargo-tree.html) [#8062](https://github.com/rust-lang/cargo/pull/8062) - Added warnings if a package has Windows-restricted filenames (like `nul`, `con`, `aux`, `prn`, etc.). [#7959](https://github.com/rust-lang/cargo/pull/7959) - Added a `"build-finished"` JSON message when compilation is complete so that tools can detect when they can stop listening for JSON messages with commands like `cargo run` or `cargo test`. [#8069](https://github.com/rust-lang/cargo/pull/8069) ### Changed - Valid package names are now restricted to Unicode XID identifiers. This is mostly the same as before, except package names cannot start with a number or `-`. [#7959](https://github.com/rust-lang/cargo/pull/7959) - `cargo new` and `init` will warn or reject additional package names (reserved Windows names, reserved Cargo directories, non-ASCII names, conflicting std names like `core`, etc.). [#7959](https://github.com/rust-lang/cargo/pull/7959) - Tests are no longer hard-linked into the output directory (`target/debug/`). This ensures tools will have access to debug symbols and execute tests in the same way as Cargo. Tools should use JSON messages to discover the path to the executable. [#7965](https://github.com/rust-lang/cargo/pull/7965) - Updating git submodules now displays an "Updating" message for each submodule. [#7989](https://github.com/rust-lang/cargo/pull/7989) - File modification times are now preserved when extracting a `.crate` file. This reverses the change made in 1.40 where the mtime was not preserved. [#7935](https://github.com/rust-lang/cargo/pull/7935) - Build script warnings are now displayed separately when the build script fails. [#8017](https://github.com/rust-lang/cargo/pull/8017) - Removed the `git-checkout` subcommand. [#8040](https://github.com/rust-lang/cargo/pull/8040) - The progress bar is now enabled for all unix platforms. Previously it was only Linux, macOS, and FreeBSD. [#8054](https://github.com/rust-lang/cargo/pull/8054) - Artifacts generated by pre-release versions of `rustc` now share the same filenames. This means that changing nightly versions will not leave stale files in the build directory. [#8073](https://github.com/rust-lang/cargo/pull/8073) - Invalid package names are rejected when using renamed dependencies. [#8090](https://github.com/rust-lang/cargo/pull/8090) - Added a certain class of HTTP2 errors as "spurious" that will get retried. [#8102](https://github.com/rust-lang/cargo/pull/8102) - Allow `cargo package --list` to succeed, even if there are other validation errors (such as `Cargo.lock` generation problem, or missing dependencies). [#8175](https://github.com/rust-lang/cargo/pull/8175) [#8215](https://github.com/rust-lang/cargo/pull/8215) ### Fixed - Cargo no longer buffers excessive amounts of compiler output in memory. [#7838](https://github.com/rust-lang/cargo/pull/7838) - Symbolic links in git repositories now work on Windows. [#7996](https://github.com/rust-lang/cargo/pull/7996) - Fixed an issue where `profile.dev` was not loaded from a config file with `cargo test` when the `dev` profile was not defined in `Cargo.toml`. [#8012](https://github.com/rust-lang/cargo/pull/8012) - When a binary is built as an implicit dependency of an integration test, it now checks `dep_name/feature_name` syntax in `required-features` correctly. [#8020](https://github.com/rust-lang/cargo/pull/8020) - Fixed an issue where Cargo would not detect that an executable (such as an integration test) needs to be rebuilt when the previous build was interrupted with Ctrl-C. [#8087](https://github.com/rust-lang/cargo/pull/8087) - Protect against some (unknown) situations where Cargo could panic when the system monotonic clock doesn't appear to be monotonic. [#8114](https://github.com/rust-lang/cargo/pull/8114) - Fixed panic with `cargo clean -p` if the package has a build script. [#8216](https://github.com/rust-lang/cargo/pull/8216) ### Nightly only - Fixed panic with new feature resolver and required-features. [#7962](https://github.com/rust-lang/cargo/pull/7962) - Added `RUSTC_WORKSPACE_WRAPPER` environment variable, which provides a way to wrap `rustc` for workspace members only, and affects the filename hash so that artifacts produced by the wrapper are cached separately. This usage can be seen on nightly clippy with `cargo clippy -Zunstable-options`. [#7533](https://github.com/rust-lang/cargo/pull/7533) - Added `--unit-graph` CLI option to display Cargo's internal dependency graph as JSON. [#7977](https://github.com/rust-lang/cargo/pull/7977) - Changed `-Zbuild_dep` to `-Zhost_dep`, and added proc-macros to the feature decoupling logic. [#8003](https://github.com/rust-lang/cargo/pull/8003) [#8028](https://github.com/rust-lang/cargo/pull/8028) - Fixed so that `--crate-version` is not automatically passed when the flag is found in `RUSTDOCFLAGS`. [#8014](https://github.com/rust-lang/cargo/pull/8014) - Fixed panic with `-Zfeatures=dev_dep` and `check --profile=test`. [#8027](https://github.com/rust-lang/cargo/pull/8027) - Fixed panic with `-Zfeatures=itarget` with certain host dependencies. [#8048](https://github.com/rust-lang/cargo/pull/8048) - Added support for `-Cembed-bitcode=no`, which provides a performance boost and disk-space usage reduction for non-LTO builds. [#8066](https://github.com/rust-lang/cargo/pull/8066) - `-Zpackage-features` has been extended with several changes intended to make it easier to select features on the command-line in a workspace. [#8074](https://github.com/rust-lang/cargo/pull/8074) ## Cargo 1.43 (2020-04-23) [9d32b7b0...rust-1.43.0](https://github.com/rust-lang/cargo/compare/9d32b7b0...rust-1.43.0) ### Added - πŸ”₯ Profiles may now be specified in config files (and environment variables). [docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#profile) [#7823](https://github.com/rust-lang/cargo/pull/7823) - ❗ Added `CARGO_BIN_EXE_` environment variable when building integration tests. This variable contains the path to any `[[bin]]` targets in the package. Integration tests should use the `env!` macro to determine the path to a binary to execute. [docs](https://doc.rust-lang.org/nightly/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates) [#7697](https://github.com/rust-lang/cargo/pull/7697) ### Changed - `cargo install --git` now honors workspaces in a git repository. This allows workspace settings, like `[patch]`, `[replace]`, or `[profile]` to be used. [#7768](https://github.com/rust-lang/cargo/pull/7768) - `cargo new` will now run `rustfmt` on the new files to pick up rustfmt settings like `tab_spaces` so that the new file matches the user's preferred indentation settings. [#7827](https://github.com/rust-lang/cargo/pull/7827) - Environment variables printed with "very verbose" output (`-vv`) are now consistently sorted. [#7877](https://github.com/rust-lang/cargo/pull/7877) - Debug logging for fingerprint rebuild-detection now includes more information. [#7888](https://github.com/rust-lang/cargo/pull/7888) [#7890](https://github.com/rust-lang/cargo/pull/7890) [#7952](https://github.com/rust-lang/cargo/pull/7952) - Added warning during publish if the license-file doesn't exist. [#7905](https://github.com/rust-lang/cargo/pull/7905) - The `license-file` file is automatically included during publish, even if it is not explicitly listed in the `include` list or is in a location outside of the root of the package. [#7905](https://github.com/rust-lang/cargo/pull/7905) - `CARGO_CFG_DEBUG_ASSERTIONS` and `CARGO_CFG_PROC_MACRO` are no longer set when running a build script. These were inadvertently set in the past, but had no meaning as they were always true. Additionally, `cfg(proc-macro)` is no longer supported in a `target` expression. [#7943](https://github.com/rust-lang/cargo/pull/7943) [#7970](https://github.com/rust-lang/cargo/pull/7970) ### Fixed - Global command-line flags now work with aliases (like `cargo -v b`). [#7837](https://github.com/rust-lang/cargo/pull/7837) - Required-features using dependency syntax (like `renamed_dep/feat_name`) now handle renamed dependencies correctly. [#7855](https://github.com/rust-lang/cargo/pull/7855) - Fixed a rare situation where if a build script is run multiple times during the same build, Cargo will now keep the results separate instead of losing the output of the first execution. [#7857](https://github.com/rust-lang/cargo/pull/7857) - Fixed incorrect interpretation of environment variable `CARGO_TARGET_*_RUNNER=true` as a boolean. Also improved related env var error messages. [#7891](https://github.com/rust-lang/cargo/pull/7891) - Updated internal libgit2 library, bringing various fixes to git support. [#7939](https://github.com/rust-lang/cargo/pull/7939) - `cargo package` / `cargo publish` should no longer buffer the entire contents of each file in memory. [#7946](https://github.com/rust-lang/cargo/pull/7946) - Ignore more invalid `Cargo.toml` files in a git dependency. Cargo currently walks the entire repo to find the requested package. Certain invalid manifests were already skipped, and now it should skip all of them. [#7947](https://github.com/rust-lang/cargo/pull/7947) ### Nightly only - Added `build.out-dir` config variable to set the output directory. [#7810](https://github.com/rust-lang/cargo/pull/7810) - Added `-Zjobserver-per-rustc` feature to support improved performance for parallel rustc. [#7731](https://github.com/rust-lang/cargo/pull/7731) - Fixed filename collision with `build-std` and crates like `cc`. [#7860](https://github.com/rust-lang/cargo/pull/7860) - `-Ztimings` will now save its report even if there is an error. [#7872](https://github.com/rust-lang/cargo/pull/7872) - Updated `--config` command-line flag to support taking a path to a config file to load. [#7901](https://github.com/rust-lang/cargo/pull/7901) - Added new feature resolver. [#7820](https://github.com/rust-lang/cargo/pull/7820) - Rustdoc docs now automatically include the version of the package in the side bar (requires `-Z crate-versions` flag). [#7903](https://github.com/rust-lang/cargo/pull/7903) ## Cargo 1.42 (2020-03-12) [0bf7aafe...rust-1.42.0](https://github.com/rust-lang/cargo/compare/0bf7aafe...rust-1.42.0) ### Added - Added documentation on git authentication. [#7658](https://github.com/rust-lang/cargo/pull/7658) - Bitbucket Pipeline badges are now supported on crates.io. [#7663](https://github.com/rust-lang/cargo/pull/7663) - `cargo vendor` now accepts the `--versioned-dirs` option to force it to always include the version number in each package's directory name. [#7631](https://github.com/rust-lang/cargo/pull/7631) - The `proc_macro` crate is now automatically added to the extern prelude for proc-macro packages. This means that `extern crate proc_macro;` is no longer necessary for proc-macros. [#7700](https://github.com/rust-lang/cargo/pull/7700) ### Changed - Emit a warning if `debug_assertions`, `test`, `proc_macro`, or `feature=` is used in a `cfg()` expression. [#7660](https://github.com/rust-lang/cargo/pull/7660) - Large update to the Cargo documentation, adding new chapters on Cargo targets, workspaces, and features. [#7733](https://github.com/rust-lang/cargo/pull/7733) - Windows: `.lib` DLL import libraries are now copied next to the dll for all Windows MSVC targets. Previously it was only supported for `pc-windows-msvc`. This adds DLL support for `uwp-windows-msvc` targets. [#7758](https://github.com/rust-lang/cargo/pull/7758) - The `ar` field in the `[target]` configuration is no longer read. It has been ignored for over 4 years. [#7763](https://github.com/rust-lang/cargo/pull/7763) - Bash completion file simplified and updated for latest changes. [#7789](https://github.com/rust-lang/cargo/pull/7789) - Credentials are only loaded when needed, instead of every Cargo command. [#7774](https://github.com/rust-lang/cargo/pull/7774) ### Fixed - Removed `--offline` empty index check, which was a false positive in some cases. [#7655](https://github.com/rust-lang/cargo/pull/7655) - Files and directories starting with a `.` can now be included in a package by adding it to the `include` list. [#7680](https://github.com/rust-lang/cargo/pull/7680) - Fixed `cargo login` removing alternative registry tokens when previous entries existed in the credentials file. [#7708](https://github.com/rust-lang/cargo/pull/7708) - Fixed `cargo vendor` from panicking when used with alternative registries. [#7718](https://github.com/rust-lang/cargo/pull/7718) - Fixed incorrect explanation in the fingerprint debug log message. [#7749](https://github.com/rust-lang/cargo/pull/7749) - A `[source]` that is defined multiple times will now result in an error. Previously it was randomly picking a source, which could cause non-deterministic behavior. [#7751](https://github.com/rust-lang/cargo/pull/7751) - `dep_kinds` in `cargo metadata` are now de-duplicated. [#7756](https://github.com/rust-lang/cargo/pull/7756) - Fixed packaging where `Cargo.lock` was listed in `.gitignore` in a subdirectory inside a git repository. Previously it was assuming `Cargo.lock` was at the root of the repo. [#7779](https://github.com/rust-lang/cargo/pull/7779) - Partial file transfer errors will now cause an automatic retry. [#7788](https://github.com/rust-lang/cargo/pull/7788) - Linux: Fixed panic if CPU iowait stat decreases. [#7803](https://github.com/rust-lang/cargo/pull/7803) - Fixed using the wrong sysroot for detecting host compiler settings when `--sysroot` is passed in via `RUSTFLAGS`. [#7798](https://github.com/rust-lang/cargo/pull/7798) ### Nightly only - `build-std` now uses `--extern` instead of `--sysroot` to find sysroot packages. [#7699](https://github.com/rust-lang/cargo/pull/7699) - Added `--config` command-line option to set config settings. [#7649](https://github.com/rust-lang/cargo/pull/7649) - Added `include` config setting which allows including another config file. [#7649](https://github.com/rust-lang/cargo/pull/7649) - Profiles in config files now support any named profile. Previously it was limited to dev/release. [#7750](https://github.com/rust-lang/cargo/pull/7750) ## Cargo 1.41 (2020-01-30) [5da4b4d4...rust-1.41.0](https://github.com/rust-lang/cargo/compare/5da4b4d4...rust-1.41.0) ### Added - πŸ”₯ Cargo now uses a new `Cargo.lock` file format. This new format should support easier merges in source control systems. Projects using the old format will continue to use the old format, only new `Cargo.lock` files will use the new format. [#7579](https://github.com/rust-lang/cargo/pull/7579) - πŸ”₯ `cargo install` will now upgrade already installed packages instead of failing. [#7560](https://github.com/rust-lang/cargo/pull/7560) - πŸ”₯ Profile overrides have been added. This allows overriding profiles for individual dependencies or build scripts. See [the documentation](https://doc.rust-lang.org/nightly/cargo/reference/profiles.html#overrides) for more. [#7591](https://github.com/rust-lang/cargo/pull/7591) - Added new documentation for build scripts. [#7565](https://github.com/rust-lang/cargo/pull/7565) - Added documentation for Cargo's JSON output. [#7595](https://github.com/rust-lang/cargo/pull/7595) - Significant expansion of config and environment variable documentation. [#7650](https://github.com/rust-lang/cargo/pull/7650) - Add back support for `BROWSER` environment variable for `cargo doc --open`. [#7576](https://github.com/rust-lang/cargo/pull/7576) - Added `kind` and `platform` for dependencies in `cargo metadata`. [#7132](https://github.com/rust-lang/cargo/pull/7132) - The `OUT_DIR` value is now included in the `build-script-executed` JSON message. [#7622](https://github.com/rust-lang/cargo/pull/7622) ### Changed - `cargo doc` will now document private items in binaries by default. [#7593](https://github.com/rust-lang/cargo/pull/7593) - Subcommand typo suggestions now include aliases. [#7486](https://github.com/rust-lang/cargo/pull/7486) - Tweak how the "already existing..." comment is added to `.gitignore`. [#7570](https://github.com/rust-lang/cargo/pull/7570) - Ignore `cargo login` text from copy/paste in token. [#7588](https://github.com/rust-lang/cargo/pull/7588) - Windows: Ignore errors for locking files when not supported by the filesystem. [#7602](https://github.com/rust-lang/cargo/pull/7602) - Remove `**/*.rs.bk` from `.gitignore`. [#7647](https://github.com/rust-lang/cargo/pull/7647) ### Fixed - Fix unused warnings for some keys in the `build` config section. [#7575](https://github.com/rust-lang/cargo/pull/7575) - Linux: Don't panic when parsing `/proc/stat`. [#7580](https://github.com/rust-lang/cargo/pull/7580) - Don't show canonical path in `cargo vendor`. [#7629](https://github.com/rust-lang/cargo/pull/7629) ### Nightly only ## Cargo 1.40 (2019-12-19) [1c6ec66d...5da4b4d4](https://github.com/rust-lang/cargo/compare/1c6ec66d...5da4b4d4) ### Added - Added `http.ssl-version` config option to control the version of TLS, along with min/max versions. [#7308](https://github.com/rust-lang/cargo/pull/7308) - πŸ”₯ Compiler warnings are now cached on disk. If a build generates warnings, re-running the build will now re-display the warnings. [#7450](https://github.com/rust-lang/cargo/pull/7450) - Added `--filter-platform` option to `cargo metadata` to narrow the nodes shown in the resolver graph to only packages included for the given target triple. [#7376](https://github.com/rust-lang/cargo/pull/7376) ### Changed - Cargo's "platform" `cfg` parsing has been extracted into a separate crate named `cargo-platform`. [#7375](https://github.com/rust-lang/cargo/pull/7375) - Dependencies extracted into Cargo's cache no longer preserve mtimes to reduce syscall overhead. [#7465](https://github.com/rust-lang/cargo/pull/7465) - Windows: EXE files no longer include a metadata hash in the filename. This helps with debuggers correlating the filename with the PDB file. [#7400](https://github.com/rust-lang/cargo/pull/7400) - Wasm32: `.wasm` files are no longer treated as an "executable", allowing `cargo test` and `cargo run` to work properly with the generated `.js` file. [#7476](https://github.com/rust-lang/cargo/pull/7476) - crates.io now supports SPDX 3.6 licenses. [#7481](https://github.com/rust-lang/cargo/pull/7481) - Improved cyclic dependency error message. [#7470](https://github.com/rust-lang/cargo/pull/7470) - Bare `cargo clean` no longer locks the package cache. [#7502](https://github.com/rust-lang/cargo/pull/7502) - `cargo publish` now allows dev-dependencies without a version key to be published. A git or path-only dev-dependency will be removed from the package manifest before uploading. [#7333](https://github.com/rust-lang/cargo/pull/7333) - `--features` and `--no-default-features` in the root of a virtual workspace will now generate an error instead of being ignored. [#7507](https://github.com/rust-lang/cargo/pull/7507) - Generated files (like `Cargo.toml` and `Cargo.lock`) in a package archive now have their timestamp set to the current time instead of the epoch. [#7523](https://github.com/rust-lang/cargo/pull/7523) - The `-Z` flag parser is now more strict, rejecting more invalid syntax. [#7531](https://github.com/rust-lang/cargo/pull/7531) ### Fixed - Fixed an issue where if a package had an `include` field, and `Cargo.lock` in `.gitignore`, and a binary or example target, and the `Cargo.lock` exists in the current project, it would fail to publish complaining the `Cargo.lock` was dirty. [#7448](https://github.com/rust-lang/cargo/pull/7448) - Fixed a panic in a particular combination of `[patch]` entries. [#7452](https://github.com/rust-lang/cargo/pull/7452) - Windows: Better error message when `cargo test` or `rustc` crashes in an abnormal way, such as a signal or seg fault. [#7535](https://github.com/rust-lang/cargo/pull/7535) ### Nightly only - The `mtime-on-use` feature may now be enabled via the `unstable.mtime_on_use` config option. [#7411](https://github.com/rust-lang/cargo/pull/7411) - Added support for named profiles. [#6989](https://github.com/rust-lang/cargo/pull/6989) - Added `-Zpanic-abort-tests` to allow building and running tests with the "abort" panic strategy. [#7460](https://github.com/rust-lang/cargo/pull/7460) - Changed `build-std` to use `--sysroot`. [#7421](https://github.com/rust-lang/cargo/pull/7421) - Various fixes and enhancements to `-Ztimings`. [#7395](https://github.com/rust-lang/cargo/pull/7395) [#7398](https://github.com/rust-lang/cargo/pull/7398) [#7397](https://github.com/rust-lang/cargo/pull/7397) [#7403](https://github.com/rust-lang/cargo/pull/7403) [#7428](https://github.com/rust-lang/cargo/pull/7428) [#7429](https://github.com/rust-lang/cargo/pull/7429) - Profile overrides have renamed the syntax to be `[profile.dev.package.NAME]`. [#7504](https://github.com/rust-lang/cargo/pull/7504) - Fixed warnings for unused profile overrides in a workspace. [#7536](https://github.com/rust-lang/cargo/pull/7536) ## Cargo 1.39 (2019-11-07) [e853aa97...1c6ec66d](https://github.com/rust-lang/cargo/compare/e853aa97...1c6ec66d) ### Added - Config files may now use the `.toml` filename extension. [#7295](https://github.com/rust-lang/cargo/pull/7295) - The `--workspace` flag has been added as an alias for `--all` to help avoid confusion about the meaning of "all". [#7241](https://github.com/rust-lang/cargo/pull/7241) - The `publish` field has been added to `cargo metadata`. [#7354](https://github.com/rust-lang/cargo/pull/7354) ### Changed - Display more information if parsing the output from `rustc` fails. [#7236](https://github.com/rust-lang/cargo/pull/7236) - TOML errors now show the column number. [#7248](https://github.com/rust-lang/cargo/pull/7248) - `cargo vendor` no longer deletes files in the `vendor` directory that starts with a `.`. [#7242](https://github.com/rust-lang/cargo/pull/7242) - `cargo fetch` will now show manifest warnings. [#7243](https://github.com/rust-lang/cargo/pull/7243) - `cargo publish` will now check git submodules if they contain any uncommitted changes. [#7245](https://github.com/rust-lang/cargo/pull/7245) - In a build script, `cargo:rustc-flags` now allows `-l` and `-L` flags without spaces. [#7257](https://github.com/rust-lang/cargo/pull/7257) - When `cargo install` replaces an older version of a package it will now delete any installed binaries that are no longer present in the newly installed version. [#7246](https://github.com/rust-lang/cargo/pull/7246) - A git dependency may now also specify a `version` key when published. The `git` value will be stripped from the uploaded crate, matching the behavior of `path` dependencies. [#7237](https://github.com/rust-lang/cargo/pull/7237) - The behavior of workspace default-members has changed. The default-members now only applies when running Cargo in the root of the workspace. Previously it would always apply regardless of which directory Cargo is running in. [#7270](https://github.com/rust-lang/cargo/pull/7270) - libgit2 updated pulling in all upstream changes. [#7275](https://github.com/rust-lang/cargo/pull/7275) - Bump `home` dependency for locating home directories. [#7277](https://github.com/rust-lang/cargo/pull/7277) - zsh completions have been updated. [#7296](https://github.com/rust-lang/cargo/pull/7296) - SSL connect errors are now retried. [#7318](https://github.com/rust-lang/cargo/pull/7318) - The jobserver has been changed to acquire N tokens (instead of N-1), and then immediately acquires the extra token. This was changed to accommodate the `cc` crate on Windows to allow it to release its implicit token. [#7344](https://github.com/rust-lang/cargo/pull/7344) - The scheduling algorithm for choosing which crate to build next has been changed. It now chooses the crate with the greatest number of transitive crates waiting on it. Previously it used a maximum topological depth. [#7390](https://github.com/rust-lang/cargo/pull/7390) - RUSTFLAGS are no longer incorporated in the metadata and filename hash, reversing the change from 1.33 that added it. This means that any change to RUSTFLAGS will cause a recompile, and will not affect symbol munging. [#7459](https://github.com/rust-lang/cargo/pull/7459) ### Fixed - Git dependencies with submodules with shorthand SSH URLs (like `git@github.com/user/repo.git`) should now work. [#7238](https://github.com/rust-lang/cargo/pull/7238) - Handle broken symlinks when creating `.dSYM` symlinks on macOS. [#7268](https://github.com/rust-lang/cargo/pull/7268) - Fixed issues with multiple versions of the same crate in a `[patch]` table. [#7303](https://github.com/rust-lang/cargo/pull/7303) - Fixed issue with custom target `.json` files where a substring of the name matches an unsupported crate type (like "bin"). [#7363](https://github.com/rust-lang/cargo/issues/7363) - Fixed issues with generating documentation for proc-macro crate types. [#7159](https://github.com/rust-lang/cargo/pull/7159) - Fixed hang if Cargo panics within a build thread. [#7366](https://github.com/rust-lang/cargo/pull/7366) - Fixed rebuild detection if a `build.rs` script issues different `rerun-if` directives between builds. Cargo was erroneously causing a rebuild after the change. [#7373](https://github.com/rust-lang/cargo/pull/7373) - Properly handle canonical URLs for `[patch]` table entries, preventing the patch from working after the first time it is used. [#7368](https://github.com/rust-lang/cargo/pull/7368) - Fixed an issue where integration tests were waiting for the package binary to finish building before starting their own build. They now may build concurrently. [#7394](https://github.com/rust-lang/cargo/pull/7394) - Fixed accidental change in the previous release on how `--features a b` flag is interpreted, restoring the original behavior where this is interpreted as `--features a` along with the argument `b` passed to the command. To pass multiple features, use quotes around the features to pass multiple features like `--features "a b"`, or use commas, or use multiple `--features` flags. [#7419](https://github.com/rust-lang/cargo/pull/7419) ### Nightly only - Basic support for building the standard library directly from Cargo has been added. ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std)) [#7216](https://github.com/rust-lang/cargo/pull/7216) - Added `-Ztimings` feature to generate an HTML report on the time spent on individual compilation steps. This also may output completion steps on the console and JSON data. ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#timings)) [#7311](https://github.com/rust-lang/cargo/pull/7311) - Added ability to cross-compile doctests. ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#doctest-xcompile)) [#6892](https://github.com/rust-lang/cargo/pull/6892) ## Cargo 1.38 (2019-09-26) [4c1fa54d...23ef9a4e](https://github.com/rust-lang/cargo/compare/4c1fa54d...23ef9a4e) ### Added - πŸ”₯ Cargo build pipelining has been enabled by default to leverage more idle CPU parallelism during builds. [#7143](https://github.com/rust-lang/cargo/pull/7143) - The `--message-format` option to Cargo can now be specified multiple times and accepts a comma-separated list of values. In addition to the previous values it also now accepts `json-diagnostic-short` and `json-diagnostic-rendered-ansi` which configures the output coming from rustc in `json` message mode. [#7214](https://github.com/rust-lang/cargo/pull/7214) - Cirrus CI badges are now supported on crates.io. [#7119](https://github.com/rust-lang/cargo/pull/7119) - A new format for `Cargo.lock` has been introduced. This new format is intended to avoid source-control merge conflicts more often, and to generally make it safer to merge changes. This new format is *not* enabled at this time, though Cargo will use it if it sees it. At some point in the future, it is intended that this will become the default. [#7070](https://github.com/rust-lang/cargo/pull/7070) - Progress bar support added for FreeBSD. [#7222](https://github.com/rust-lang/cargo/pull/7222) ### Changed - The `-q` flag will no longer suppress the root error message for an error from Cargo itself. [#7116](https://github.com/rust-lang/cargo/pull/7116) - The Cargo Book is now published with mdbook 0.3 providing a number of formatting fixes and improvements. [#7140](https://github.com/rust-lang/cargo/pull/7140) - The `--features` command-line flag can now be specified multiple times. The list of features from all the flags are joined together. [#7084](https://github.com/rust-lang/cargo/pull/7084) - Package include/exclude glob-vs-gitignore warnings have been removed. Packages may now use gitignore-style matching without producing any warnings. [#7170](https://github.com/rust-lang/cargo/pull/7170) - Cargo now shows the command and output when parsing `rustc` output fails when querying `rustc` for information like `cfg` values. [#7185](https://github.com/rust-lang/cargo/pull/7185) - `cargo package`/`cargo publish` now allows a symbolic link to a git submodule to include that submodule. [#6817](https://github.com/rust-lang/cargo/pull/6817) - Improved the error message when a version requirement does not match any versions, but there are pre-release versions available. [#7191](https://github.com/rust-lang/cargo/pull/7191) ### Fixed - Fixed using the wrong directory when updating git repositories when using the `git-fetch-with-cli` config option, and the `GIT_DIR` environment variable is set. This may happen when running cargo from git callbacks. [#7082](https://github.com/rust-lang/cargo/pull/7082) - Fixed dep-info files being overwritten for targets that have separate debug outputs. For example, binaries on `-apple-` targets with `.dSYM` directories would overwrite the `.d` file. [#7057](https://github.com/rust-lang/cargo/pull/7057) - Fix `[patch]` table not preserving "one major version per source" rule. [#7118](https://github.com/rust-lang/cargo/pull/7118) - Ignore `--remap-path-prefix` flags for the metadata hash in the `cargo rustc` command. This was causing the remap settings to inadvertently affect symbol names. [#7134](https://github.com/rust-lang/cargo/pull/7134) - Fixed cycle detection in `[patch]` dependencies. [#7174](https://github.com/rust-lang/cargo/pull/7174) - Fixed `cargo new` leaving behind a symlink on Windows when `core.symlinks` git config is true. Also adds a number of fixes and updates from upstream libgit2. [#7176](https://github.com/rust-lang/cargo/pull/7176) - macOS: Fixed setting the flag to mark the `target` directory to be excluded from backups. [#7192](https://github.com/rust-lang/cargo/pull/7192) - Fixed `cargo fix` panicking under some situations involving multi-byte characters. [#7221](https://github.com/rust-lang/cargo/pull/7221) ### Nightly only - Added `cargo fix --clippy` which will apply machine-applicable fixes from Clippy. [#7069](https://github.com/rust-lang/cargo/pull/7069) - Added `-Z binary-dep-depinfo` flag to add change tracking for binary dependencies like the standard library. [#7137](https://github.com/rust-lang/cargo/pull/7137) [#7219](https://github.com/rust-lang/cargo/pull/7219) - `cargo clippy-preview` will always run, even if no changes have been made. [#7157](https://github.com/rust-lang/cargo/pull/7157) - Fixed exponential blowup when using `CARGO_BUILD_PIPELINING`. [#7062](https://github.com/rust-lang/cargo/pull/7062) - Fixed passing args to clippy in `cargo clippy-preview`. [#7162](https://github.com/rust-lang/cargo/pull/7162) ## Cargo 1.37 (2019-08-15) [c4fcfb72...9edd0891](https://github.com/rust-lang/cargo/compare/c4fcfb72...9edd0891) ### Added - Added `doctest` field to `cargo metadata` to determine if a target's documentation is tested. [#6953](https://github.com/rust-lang/cargo/pull/6953) [#6965](https://github.com/rust-lang/cargo/pull/6965) - πŸ”₯ The [`cargo vendor`](https://doc.rust-lang.org/nightly/cargo/commands/cargo-vendor.html) command is now built-in to Cargo. This command may be used to create a local copy of the sources of all dependencies. [#6869](https://github.com/rust-lang/cargo/pull/6869) - πŸ”₯ The "publish lockfile" feature is now stable. This feature will automatically include the `Cargo.lock` file when a package is published if it contains a binary executable target. By default, Cargo will ignore `Cargo.lock` when installing a package. To force Cargo to use the `Cargo.lock` file included in the published package, use `cargo install --locked`. This may be useful to ensure that `cargo install` consistently reproduces the same result. It may also be useful when a semver-incompatible change is accidentally published to a dependency, providing a way to fall back to a version that is known to work. [#7026](https://github.com/rust-lang/cargo/pull/7026) - πŸ”₯ The `default-run` feature has been stabilized. This feature allows you to specify which binary executable to run by default with `cargo run` when a package includes multiple binaries. Set the `default-run` key in the `[package]` table in `Cargo.toml` to the name of the binary to use by default. [#7056](https://github.com/rust-lang/cargo/pull/7056) ### Changed - `cargo package` now verifies that build scripts do not create empty directories. [#6973](https://github.com/rust-lang/cargo/pull/6973) - A warning is now issued if `cargo doc` generates duplicate outputs, which causes files to be randomly stomped on. This may happen for a variety of reasons (renamed dependencies, multiple versions of the same package, packages with renamed libraries, etc.). This is a known bug, which needs more work to handle correctly. [#6998](https://github.com/rust-lang/cargo/pull/6998) - Enabling a dependency's feature with `--features foo/bar` will no longer compile the current crate with the `foo` feature if `foo` is not an optional dependency. [#7010](https://github.com/rust-lang/cargo/pull/7010) - If `--remap-path-prefix` is passed via RUSTFLAGS, it will no longer affect the filename metadata hash. [#6966](https://github.com/rust-lang/cargo/pull/6966) - libgit2 has been updated to 0.28.2, which Cargo uses to access git repositories. This brings in hundreds of changes and fixes since it was last updated in November. [#7018](https://github.com/rust-lang/cargo/pull/7018) - Cargo now supports absolute paths in the dep-info files generated by rustc. This is laying the groundwork for [tracking binaries](https://github.com/rust-lang/rust/pull/61727), such as libstd, for rebuild detection. (Note: this contains a known bug.) [#7030](https://github.com/rust-lang/cargo/pull/7030) ### Fixed - Fixed how zsh completions fetch the list of commands. [#6956](https://github.com/rust-lang/cargo/pull/6956) - "+ debuginfo" is no longer printed in the build summary when `debug` is set to 0. [#6971](https://github.com/rust-lang/cargo/pull/6971) - Fixed `cargo doc` with an example configured with `doc = true` to document correctly. [#7023](https://github.com/rust-lang/cargo/pull/7023) - Don't fail if a read-only lock cannot be acquired in CARGO_HOME. This helps when CARGO_HOME doesn't exist, but `--locked` is used which means CARGO_HOME is not needed. [#7149](https://github.com/rust-lang/cargo/pull/7149) - Reverted a change in 1.35 which released jobserver tokens when Cargo blocked on a lock file. It caused a deadlock in some situations. [#7204](https://github.com/rust-lang/cargo/pull/7204) ### Nightly only - Added [compiler message caching](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#cache-messages). The `-Z cache-messages` flag makes cargo cache the compiler output so that future runs can redisplay previous warnings. [#6933](https://github.com/rust-lang/cargo/pull/6933) - `-Z mtime-on-use` no longer touches intermediate artifacts. [#7050](https://github.com/rust-lang/cargo/pull/7050) ## Cargo 1.36 (2019-07-04) [6f3e9c36...c4fcfb72](https://github.com/rust-lang/cargo/compare/6f3e9c36...c4fcfb72) ### Added - Added more detailed documentation on target auto-discovery. [#6898](https://github.com/rust-lang/cargo/pull/6898) - πŸ”₯ Stabilize the `--offline` flag which allows using cargo without a network connection. [#6934](https://github.com/rust-lang/cargo/pull/6934) [#6871](https://github.com/rust-lang/cargo/pull/6871) ### Changed - `publish = ["crates-io"]` may be added to the manifest to restrict publishing to crates.io only. [#6838](https://github.com/rust-lang/cargo/pull/6838) - macOS: Only include the default paths if `DYLD_FALLBACK_LIBRARY_PATH` is not set. Also, remove `/lib` from the default set. [#6856](https://github.com/rust-lang/cargo/pull/6856) - `cargo publish` will now exit early if the login token is not available. [#6854](https://github.com/rust-lang/cargo/pull/6854) - HTTP/2 stream errors are now considered "spurious" and will cause a retry. [#6861](https://github.com/rust-lang/cargo/pull/6861) - Setting a feature on a dependency where that feature points to a *required* dependency is now an error. Previously it was a warning. [#6860](https://github.com/rust-lang/cargo/pull/6860) - The `registry.index` config value now supports relative `file:` URLs. [#6873](https://github.com/rust-lang/cargo/pull/6873) - macOS: The `.dSYM` directory is now symbolically linked next to example binaries without the metadata hash so that debuggers can find it. [#6891](https://github.com/rust-lang/cargo/pull/6891) - The default `Cargo.toml` template for now projects now includes a comment providing a link to the documentation. [#6881](https://github.com/rust-lang/cargo/pull/6881) - Some improvements to the wording of the crate download summary. [#6916](https://github.com/rust-lang/cargo/pull/6916) [#6920](https://github.com/rust-lang/cargo/pull/6920) - ✨ Changed `RUST_LOG` environment variable to `CARGO_LOG` so that user code that uses the `log` crate will not display cargo's debug output. [#6918](https://github.com/rust-lang/cargo/pull/6918) - `Cargo.toml` is now always included when packaging, even if it is not listed in `package.include`. [#6925](https://github.com/rust-lang/cargo/pull/6925) - Package include/exclude values now use gitignore patterns instead of glob patterns. [#6924](https://github.com/rust-lang/cargo/pull/6924) - Provide a better error message when crates.io times out. Also improve error messages with other HTTP response codes. [#6936](https://github.com/rust-lang/cargo/pull/6936) ### Performance - Resolver performance improvements for some cases. [#6853](https://github.com/rust-lang/cargo/pull/6853) - Optimized how cargo reads the index JSON files by caching the results. [#6880](https://github.com/rust-lang/cargo/pull/6880) [#6912](https://github.com/rust-lang/cargo/pull/6912) [#6940](https://github.com/rust-lang/cargo/pull/6940) - Various performance improvements. [#6867](https://github.com/rust-lang/cargo/pull/6867) ### Fixed - More carefully track the on-disk fingerprint information for dependencies. This can help in some rare cases where the build is interrupted and restarted. [#6832](https://github.com/rust-lang/cargo/pull/6832) - `cargo run` now correctly passes non-UTF8 arguments to the child process. [#6849](https://github.com/rust-lang/cargo/pull/6849) - Fixed bash completion to run on bash 3.2, the stock version in macOS. [#6905](https://github.com/rust-lang/cargo/pull/6905) - Various fixes and improvements to zsh completion. [#6926](https://github.com/rust-lang/cargo/pull/6926) [#6929](https://github.com/rust-lang/cargo/pull/6929) - Fix `cargo update` ignoring `-p` arguments if the `Cargo.lock` file was missing. [#6904](https://github.com/rust-lang/cargo/pull/6904) ### Nightly only - Added [`-Z install-upgrade` feature](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#install-upgrade) to track details about installed crates and to update them if they are out-of-date. [#6798](https://github.com/rust-lang/cargo/pull/6798) - Added the [`public-dependency` feature](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#public-dependency) which allows tracking public versus private dependencies. [#6772](https://github.com/rust-lang/cargo/pull/6772) - Added build pipelining via the `build.pipelining` config option (`CARGO_BUILD_PIPELINING` env var). [#6883](https://github.com/rust-lang/cargo/pull/6883) - The `publish-lockfile` feature has had some significant changes. The default is now `true`, the `Cargo.lock` will always be published for binary crates. The `Cargo.lock` is now regenerated during publishing. `cargo install` now ignores the `Cargo.lock` file by default, and requires `--locked` to use the lock file. Warnings have been added if yanked dependencies are detected. [#6840](https://github.com/rust-lang/cargo/pull/6840) ## Cargo 1.35 (2019-05-23) [6789d8a0...6f3e9c36](https://github.com/rust-lang/cargo/compare/6789d8a0...6f3e9c36) ### Added - Added the `rustc-cdylib-link-arg` key for build scripts to specify linker arguments for cdylib crates. [#6298](https://github.com/rust-lang/cargo/pull/6298) ### Changed - When passing a test filter, such as `cargo test foo`, don't build examples (unless they set `test = true`). [#6683](https://github.com/rust-lang/cargo/pull/6683) - Forward the `--quiet` flag from `cargo test` to the libtest harness so that tests are actually quiet. [#6358](https://github.com/rust-lang/cargo/pull/6358) - The verification step in `cargo package` that checks if any files are modified is now stricter. It uses a hash of the contents instead of checking filesystem mtimes. It also checks *all* files in the package. [#6740](https://github.com/rust-lang/cargo/pull/6740) - Jobserver tokens are now released whenever Cargo blocks on a file lock. [#6748](https://github.com/rust-lang/cargo/pull/6748) - Issue a warning for a previous bug in the TOML parser that allowed multiple table headers with the same name. [#6761](https://github.com/rust-lang/cargo/pull/6761) - Removed the `CARGO_PKG_*` environment variables from the metadata hash and added them to the fingerprint instead. This means that when these values change, stale artifacts are not left behind. Also added the "repository" value to the fingerprint. [#6785](https://github.com/rust-lang/cargo/pull/6785) - `cargo metadata` no longer shows a `null` field for a dependency without a library in `resolve.nodes.deps`. The dependency is no longer shown. [#6534](https://github.com/rust-lang/cargo/pull/6534) - `cargo new` will no longer include an email address in the `authors` field if it is set to the empty string. [#6802](https://github.com/rust-lang/cargo/pull/6802) - `cargo doc --open` now works when documenting multiple packages. [#6803](https://github.com/rust-lang/cargo/pull/6803) - `cargo install --path P` now loads the `.cargo/config` file from the directory P. [#6805](https://github.com/rust-lang/cargo/pull/6805) - Using semver metadata in a version requirement (such as `1.0.0+1234`) now issues a warning that it is ignored. [#6806](https://github.com/rust-lang/cargo/pull/6806) - `cargo install` now rejects certain combinations of flags where some flags would have been ignored. [#6801](https://github.com/rust-lang/cargo/pull/6801) - Resolver performance improvements for some cases. [#6776](https://github.com/rust-lang/cargo/pull/6776) ### Fixed - Fixed running separate commands (such as `cargo build` then `cargo test`) where the second command could use stale results from a build script. [#6720](https://github.com/rust-lang/cargo/pull/6720) - Fixed `cargo fix` not working properly if a `.gitignore` file that matched the root package directory. [#6767](https://github.com/rust-lang/cargo/pull/6767) - Fixed accidentally compiling a lib multiple times if `panic=unwind` was set in a profile. [#6781](https://github.com/rust-lang/cargo/pull/6781) - Paths to JSON files in `build.target` config value are now canonicalized to fix building dependencies. [#6778](https://github.com/rust-lang/cargo/pull/6778) - Fixed re-running a build script if its compilation was interrupted (such as if it is killed). [#6782](https://github.com/rust-lang/cargo/pull/6782) - Fixed `cargo new` initializing a fossil repo. [#6792](https://github.com/rust-lang/cargo/pull/6792) - Fixed supporting updating a git repo that has a force push when using the `git-fetch-with-cli` feature. `git-fetch-with-cli` also shows more error information now when it fails. [#6800](https://github.com/rust-lang/cargo/pull/6800) - `--example` binaries built for the WASM target are fixed to no longer include a metadata hash in the filename, and are correctly emitted in the `compiler-artifact` JSON message. [#6812](https://github.com/rust-lang/cargo/pull/6812) ### Nightly only - `cargo clippy-preview` is now a built-in cargo command. [#6759](https://github.com/rust-lang/cargo/pull/6759) - The `build-override` profile setting now includes proc-macros and their dependencies. [#6811](https://github.com/rust-lang/cargo/pull/6811) - Optional and target dependencies now work better with `-Z offline`. [#6814](https://github.com/rust-lang/cargo/pull/6814) ## Cargo 1.34 (2019-04-11) [f099fe94...6789d8a0](https://github.com/rust-lang/cargo/compare/f099fe94...6789d8a0) ### Added - πŸ”₯ Stabilized support for [alternate registries](https://doc.rust-lang.org/1.34.0/cargo/reference/registries.html). [#6654](https://github.com/rust-lang/cargo/pull/6654) - Added documentation on using builds.sr.ht Continuous Integration with Cargo. [#6565](https://github.com/rust-lang/cargo/pull/6565) - `Cargo.lock` now includes a comment at the top that it is `@generated`. [#6548](https://github.com/rust-lang/cargo/pull/6548) - Azure DevOps badges are now supported. [#6264](https://github.com/rust-lang/cargo/pull/6264) - Added a warning if `--exclude` flag specifies an unknown package. [#6679](https://github.com/rust-lang/cargo/pull/6679) ### Changed - `cargo test --doc --no-run` doesn't do anything, so it now displays an error to that effect. [#6628](https://github.com/rust-lang/cargo/pull/6628) - Various updates to bash completion: add missing options and commands, support libtest completions, use rustup for `--target` completion, fallback to filename completion, fix editing the command line. [#6644](https://github.com/rust-lang/cargo/pull/6644) - Publishing a crate with a `[patch]` section no longer generates an error. The `[patch]` section is removed from the manifest before publishing. [#6535](https://github.com/rust-lang/cargo/pull/6535) - `build.incremental = true` config value is now treated the same as `CARGO_INCREMENTAL=1`, previously it was ignored. [#6688](https://github.com/rust-lang/cargo/pull/6688) - Errors from a registry are now always displayed regardless of the HTTP response code. [#6771](https://github.com/rust-lang/cargo/pull/6771) ### Fixed - Fixed bash completion for `cargo run --example`. [#6578](https://github.com/rust-lang/cargo/pull/6578) - Fixed a race condition when using a *local* registry and running multiple cargo commands at the same time that build the same crate. [#6591](https://github.com/rust-lang/cargo/pull/6591) - Fixed some flickering and excessive updates of the progress bar. [#6615](https://github.com/rust-lang/cargo/pull/6615) - Fixed a hang when using a git credential helper that returns incorrect credentials. [#6681](https://github.com/rust-lang/cargo/pull/6681) - Fixed resolving yanked crates with a local registry. [#6750](https://github.com/rust-lang/cargo/pull/6750) ### Nightly only - Added `-Z mtime-on-use` flag to cause the mtime to be updated on the filesystem when a crate is used. This is intended to be able to track stale artifacts in the future for cleaning up unused files. [#6477](https://github.com/rust-lang/cargo/pull/6477) [#6573](https://github.com/rust-lang/cargo/pull/6573) - Added experimental `-Z dual-proc-macros` to build proc macros for both the host and the target. [#6547](https://github.com/rust-lang/cargo/pull/6547) ## Cargo 1.33 (2019-02-28) [8610973a...f099fe94](https://github.com/rust-lang/cargo/compare/8610973a...f099fe94) ### Added - `compiler-artifact` JSON messages now include an `"executable"` key which includes the path to the executable that was built. [#6363](https://github.com/rust-lang/cargo/pull/6363) - The man pages have been rewritten, and are now published with the web documentation. [#6405](https://github.com/rust-lang/cargo/pull/6405) - `cargo login` now displays a confirmation after saving the token. [#6466](https://github.com/rust-lang/cargo/pull/6466) - A warning is now emitted if a `[patch]` entry does not match any package. [#6470](https://github.com/rust-lang/cargo/pull/6470) - `cargo metadata` now includes the `links` key for a package. [#6480](https://github.com/rust-lang/cargo/pull/6480) - "Very verbose" output with `-vv` now displays the environment variables that cargo sets when it runs a process. [#6492](https://github.com/rust-lang/cargo/pull/6492) - `--example`, `--bin`, `--bench`, or `--test` without an argument now lists the available targets for those options. [#6505](https://github.com/rust-lang/cargo/pull/6505) - Windows: If a process fails with an extended status exit code, a human-readable name for the code is now displayed. [#6532](https://github.com/rust-lang/cargo/pull/6532) - Added `--features`, `--no-default-features`, and `--all-features` flags to the `cargo package` and `cargo publish` commands to use the given features when verifying the package. [#6453](https://github.com/rust-lang/cargo/pull/6453) ### Changed - If `cargo fix` fails to compile the fixed code, the rustc errors are now displayed on the console. [#6419](https://github.com/rust-lang/cargo/pull/6419) - Hide the `--host` flag from `cargo login`, it is unused. [#6466](https://github.com/rust-lang/cargo/pull/6466) - Build script fingerprints now include the rustc version. [#6473](https://github.com/rust-lang/cargo/pull/6473) - macOS: Switched to setting `DYLD_FALLBACK_LIBRARY_PATH` instead of `DYLD_LIBRARY_PATH`. [#6355](https://github.com/rust-lang/cargo/pull/6355) - `RUSTFLAGS` is now included in the metadata hash, meaning that changing the flags will not overwrite previously built files. [#6503](https://github.com/rust-lang/cargo/pull/6503) - When updating the crate graph, unrelated yanked crates were erroneously removed. They are now kept at their original version if possible. This was causing unrelated packages to be downgraded during `cargo update -p somecrate`. [#5702](https://github.com/rust-lang/cargo/issues/5702) - TOML files now support the [0.5 TOML syntax](https://github.com/toml-lang/toml/blob/master/CHANGELOG.md#050--2018-07-11). ### Fixed - `cargo fix` will now ignore suggestions that modify multiple files. [#6402](https://github.com/rust-lang/cargo/pull/6402) - `cargo fix` will now only fix one target at a time, to deal with targets which share the same source files. [#6434](https://github.com/rust-lang/cargo/pull/6434) - Fixed bash completion showing the list of cargo commands. [#6461](https://github.com/rust-lang/cargo/issues/6461) - `cargo init` will now avoid creating duplicate entries in `.gitignore` files. [#6521](https://github.com/rust-lang/cargo/pull/6521) - Builds now attempt to detect if a file is modified in the middle of a compilation, allowing you to build again and pick up the new changes. This is done by keeping track of when the compilation *starts* not when it finishes. Also, [#5919](https://github.com/rust-lang/cargo/pull/5919) was reverted, meaning that cargo does *not* treat equal filesystem mtimes as requiring a rebuild. [#6484](https://github.com/rust-lang/cargo/pull/6484) ### Nightly only - Allow using registry *names* in `[patch]` tables instead of just URLs. [#6456](https://github.com/rust-lang/cargo/pull/6456) - `cargo metadata` added the `registry` key for dependencies. [#6500](https://github.com/rust-lang/cargo/pull/6500) - Registry names are now restricted to the same style as package names (alphanumeric, `-` and `_` characters). [#6469](https://github.com/rust-lang/cargo/pull/6469) - `cargo login` now displays the `/me` URL from the registry config. [#6466](https://github.com/rust-lang/cargo/pull/6466) - `cargo login --registry=NAME` now supports interactive input for the token. [#6466](https://github.com/rust-lang/cargo/pull/6466) - Registries may now elide the `api` key from `config.json` to indicate they do not support API access. [#6466](https://github.com/rust-lang/cargo/pull/6466) - Fixed panic when using `--message-format=json` with metabuild. [#6432](https://github.com/rust-lang/cargo/pull/6432) - Fixed detection of publishing to crates.io when using alternate registries. [#6525](https://github.com/rust-lang/cargo/pull/6525) ## Cargo 1.32 (2019-01-17) [339d9f9c...8610973a](https://github.com/rust-lang/cargo/compare/339d9f9c...8610973a) ### Added - Registries may now display warnings after a successful publish. [#6303](https://github.com/rust-lang/cargo/pull/6303) - Added a [glossary](https://doc.rust-lang.org/cargo/appendix/glossary.html) to the documentation. [#6321](https://github.com/rust-lang/cargo/pull/6321) - Added the alias `c` for `cargo check`. [#6218](https://github.com/rust-lang/cargo/pull/6218) ### Changed - πŸ”₯ HTTP/2 multiplexing is now enabled by default. The `http.multiplexing` config value may be used to disable it. [#6271](https://github.com/rust-lang/cargo/pull/6271) - Use ANSI escape sequences to clear lines instead of spaces. [#6233](https://github.com/rust-lang/cargo/pull/6233) - Disable git templates when checking out git dependencies, which can cause problems. [#6252](https://github.com/rust-lang/cargo/pull/6252) - Include the `--update-head-ok` git flag when using the `net.git-fetch-with-cli` option. This can help prevent failures when fetching some repositories. [#6250](https://github.com/rust-lang/cargo/pull/6250) - When extracting a crate during the verification step of `cargo package`, the filesystem mtimes are no longer set, which was failing on some rare filesystems. [#6257](https://github.com/rust-lang/cargo/pull/6257) - `crate-type = ["proc-macro"]` is now treated the same as `proc-macro = true` in `Cargo.toml`. [#6256](https://github.com/rust-lang/cargo/pull/6256) - An error is raised if `dependencies`, `features`, `target`, or `badges` is set in a virtual workspace. Warnings are displayed if `replace` or `patch` is used in a workspace member. [#6276](https://github.com/rust-lang/cargo/pull/6276) - Improved performance of the resolver in some cases. [#6283](https://github.com/rust-lang/cargo/pull/6283) [#6366](https://github.com/rust-lang/cargo/pull/6366) - `.rmeta` files are no longer hard-linked into the base target directory (`target/debug`). [#6292](https://github.com/rust-lang/cargo/pull/6292) - A warning is issued if multiple targets are built with the same output filenames. [#6308](https://github.com/rust-lang/cargo/pull/6308) - When using `cargo build` (without `--release`) benchmarks are now built using the "test" profile instead of "bench". This makes it easier to debug benchmarks, and avoids confusing behavior. [#6309](https://github.com/rust-lang/cargo/pull/6309) - User aliases may now override built-in aliases (`b`, `r`, `t`, and `c`). [#6259](https://github.com/rust-lang/cargo/pull/6259) - Setting `autobins=false` now disables auto-discovery of inferred targets. [#6329](https://github.com/rust-lang/cargo/pull/6329) - `cargo verify-project` will now fail on stable if the project uses unstable features. [#6326](https://github.com/rust-lang/cargo/pull/6326) - Platform targets with an internal `.` within the name are now allowed. [#6255](https://github.com/rust-lang/cargo/pull/6255) - `cargo clean --release` now only deletes the release directory. [#6349](https://github.com/rust-lang/cargo/pull/6349) ### Fixed - Avoid adding extra angle brackets in email address for `cargo new`. [#6243](https://github.com/rust-lang/cargo/pull/6243) - The progress bar is disabled if the CI environment variable is set. [#6281](https://github.com/rust-lang/cargo/pull/6281) - Avoid retaining all rustc output in memory. [#6289](https://github.com/rust-lang/cargo/pull/6289) - If JSON parsing fails, and rustc exits nonzero, don't lose the parse failure message. [#6290](https://github.com/rust-lang/cargo/pull/6290) - Fixed renaming a project directory with build scripts. [#6328](https://github.com/rust-lang/cargo/pull/6328) - Fixed `cargo run --example NAME` to work correctly if the example sets `crate_type = ["bin"]`. [#6330](https://github.com/rust-lang/cargo/pull/6330) - Fixed issue with `cargo package` git discovery being too aggressive. The `--allow-dirty` now completely disables the git repo checks. [#6280](https://github.com/rust-lang/cargo/pull/6280) - Fixed build change tracking for `[patch]` deps which resulted in `cargo build` rebuilding when it shouldn't. [#6493](https://github.com/rust-lang/cargo/pull/6493) ### Nightly only - Allow usernames in registry URLs. [#6242](https://github.com/rust-lang/cargo/pull/6242) - Added `"compile_mode"` key to the build-plan JSON structure to be able to distinguish running a custom build script versus compiling the build script. [#6331](https://github.com/rust-lang/cargo/pull/6331) - `--out-dir` no longer copies over build scripts. [#6300](https://github.com/rust-lang/cargo/pull/6300) ## Cargo 1.31 (2018-12-06) [36d96825...339d9f9c](https://github.com/rust-lang/cargo/compare/36d96825...339d9f9c) ### Added - πŸ”₯ Stabilized support for the 2018 edition. [#5984](https://github.com/rust-lang/cargo/pull/5984) [#5989](https://github.com/rust-lang/cargo/pull/5989) - πŸ”₯ Added the ability to [rename dependencies](https://doc.rust-lang.org/1.31.0/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml) in Cargo.toml. [#6319](https://github.com/rust-lang/cargo/pull/6319) - πŸ”₯ Added support for HTTP/2 pipelining and multiplexing. Set the `http.multiplexing` config value to enable. [#6005](https://github.com/rust-lang/cargo/pull/6005) - Added `http.debug` configuration value to debug HTTP connections. Use `CARGO_HTTP_DEBUG=true RUST_LOG=cargo::ops::registry cargo build` to display the debug information. [#6166](https://github.com/rust-lang/cargo/pull/6166) - `CARGO_PKG_REPOSITORY` environment variable is set with the repository value from `Cargo.toml` when building . [#6096](https://github.com/rust-lang/cargo/pull/6096) ### Changed - `cargo test --doc` now rejects other flags instead of ignoring them. [#6037](https://github.com/rust-lang/cargo/pull/6037) - `cargo install` ignores `~/.cargo/config`. [#6026](https://github.com/rust-lang/cargo/pull/6026) - `cargo version --verbose` is now the same as `cargo -vV`. [#6076](https://github.com/rust-lang/cargo/pull/6076) - Comments at the top of `Cargo.lock` are now preserved. [#6181](https://github.com/rust-lang/cargo/pull/6181) - When building in "very verbose" mode (`cargo build -vv`), build script output is prefixed with the package name and version, such as `[foo 0.0.1]`. [#6164](https://github.com/rust-lang/cargo/pull/6164) - If `cargo fix --broken-code` fails to compile after fixes have been applied, the files are no longer reverted and are left in their broken state. [#6316](https://github.com/rust-lang/cargo/pull/6316) ### Fixed - Windows: Pass Ctrl-C to the process with `cargo run`. [#6004](https://github.com/rust-lang/cargo/pull/6004) - macOS: Fix bash completion. [#6038](https://github.com/rust-lang/cargo/pull/6038) - Support arbitrary toolchain names when completing `+toolchain` in bash completion. [#6038](https://github.com/rust-lang/cargo/pull/6038) - Fixed edge cases in the resolver, when backtracking on failed dependencies. [#5988](https://github.com/rust-lang/cargo/pull/5988) - Fixed `cargo test --all-targets` running lib tests three times. [#6039](https://github.com/rust-lang/cargo/pull/6039) - Fixed publishing renamed dependencies to crates.io. [#5993](https://github.com/rust-lang/cargo/pull/5993) - Fixed `cargo install` on a git repo with multiple binaries. [#6060](https://github.com/rust-lang/cargo/pull/6060) - Fixed deeply nested JSON emitted by rustc being lost. [#6081](https://github.com/rust-lang/cargo/pull/6081) - Windows: Fix locking msys terminals to 60 characters. [#6122](https://github.com/rust-lang/cargo/pull/6122) - Fixed renamed dependencies with dashes. [#6140](https://github.com/rust-lang/cargo/pull/6140) - Fixed linking against the wrong dylib when the dylib existed in both `target/debug` and `target/debug/deps`. [#6167](https://github.com/rust-lang/cargo/pull/6167) - Fixed some unnecessary recompiles when `panic=abort` is used. [#6170](https://github.com/rust-lang/cargo/pull/6170) ### Nightly only - Added `--registry` flag to `cargo install`. [#6128](https://github.com/rust-lang/cargo/pull/6128) - Added `registry.default` configuration value to specify the default registry to use if `--registry` flag is not passed. [#6135](https://github.com/rust-lang/cargo/pull/6135) - Added `--registry` flag to `cargo new` and `cargo init`. [#6135](https://github.com/rust-lang/cargo/pull/6135) ## Cargo 1.30 (2018-10-25) [524a578d...36d96825](https://github.com/rust-lang/cargo/compare/524a578d...36d96825) ### Added - πŸ”₯ Added an animated progress bar shows progress during building. [#5995](https://github.com/rust-lang/cargo/pull/5995/) - Added `resolve.nodes.deps` key to `cargo metadata`, which includes more information about resolved dependencies, and properly handles renamed dependencies. [#5871](https://github.com/rust-lang/cargo/pull/5871) - When creating a package, provide more detail with `-v` when failing to discover if files are dirty in a git repository. Also fix a problem with discovery on Windows. [#5858](https://github.com/rust-lang/cargo/pull/5858) - Filters like `--bin`, `--test`, `--example`, `--bench`, or `--lib` can be used in a workspace without selecting a specific package. [#5873](https://github.com/rust-lang/cargo/pull/5873) - `cargo run` can be used in a workspace without selecting a specific package. [#5877](https://github.com/rust-lang/cargo/pull/5877) - `cargo doc --message-format=json` now outputs JSON messages from rustdoc. [#5878](https://github.com/rust-lang/cargo/pull/5878) - Added `--message-format=short` to show one-line messages. [#5879](https://github.com/rust-lang/cargo/pull/5879) - Added `.cargo_vcs_info.json` file to `.crate` packages that captures the current git hash. [#5886](https://github.com/rust-lang/cargo/pull/5886) - Added `net.git-fetch-with-cli` configuration option to use the `git` executable to fetch repositories instead of using the built-in libgit2 library. [#5914](https://github.com/rust-lang/cargo/pull/5914) - Added `required-features` to `cargo metadata`. [#5902](https://github.com/rust-lang/cargo/pull/5902) - `cargo uninstall` within a package will now uninstall that package. [#5927](https://github.com/rust-lang/cargo/pull/5927) - Added `--allow-staged` flag to `cargo fix` to allow it to run if files are staged in git. [#5943](https://github.com/rust-lang/cargo/pull/5943) - Added `net.low-speed-limit` config value, and also honor `net.timeout` for http operations. [#5957](https://github.com/rust-lang/cargo/pull/5957) - Added `--edition` flag to `cargo new`. [#5984](https://github.com/rust-lang/cargo/pull/5984) - Temporarily stabilized 2018 edition support for the duration of the beta. [#5984](https://github.com/rust-lang/cargo/pull/5984) [#5989](https://github.com/rust-lang/cargo/pull/5989) - Added support for `target.'cfg(…)'.runner` config value to specify the run/test/bench runner for targets that use config expressions. [#5959](https://github.com/rust-lang/cargo/pull/5959) ### Changed - Windows: `cargo run` will not kill child processes when the main process exits. [#5887](https://github.com/rust-lang/cargo/pull/5887) - Switched to the `opener` crate to open a web browser with `cargo doc --open`. This should more reliably select the system-preferred browser on all platforms. [#5888](https://github.com/rust-lang/cargo/pull/5888) - Equal file mtimes now cause a target to be rebuilt. Previously only if files were strictly *newer* than the last build would it cause a rebuild. [#5919](https://github.com/rust-lang/cargo/pull/5919) - Ignore `build.target` config value when running `cargo install`. [#5874](https://github.com/rust-lang/cargo/pull/5874) - Ignore `RUSTC_WRAPPER` for `cargo fix`. [#5983](https://github.com/rust-lang/cargo/pull/5983) - Ignore empty `RUSTC_WRAPPER`. [#5985](https://github.com/rust-lang/cargo/pull/5985) ### Fixed - Fixed error when creating a package with an edition field in `Cargo.toml`. [#5908](https://github.com/rust-lang/cargo/pull/5908) - More consistently use relative paths for path dependencies in a workspace. [#5935](https://github.com/rust-lang/cargo/pull/5935) - `cargo fix` now always runs, even if it was run previously. [#5944](https://github.com/rust-lang/cargo/pull/5944) - Windows: Attempt to more reliably detect terminal width. msys-based terminals are forced to 60 characters wide. [#6010](https://github.com/rust-lang/cargo/pull/6010) - Allow multiple target flags with `cargo doc --document-private-items`. [6022](https://github.com/rust-lang/cargo/pull/6022) ### Nightly only - Added [metabuild](https://doc.rust-lang.org/1.30.0/cargo/reference/unstable.html#metabuild). [#5628](https://github.com/rust-lang/cargo/pull/5628) cargo-0.86.0/CODE_OF_CONDUCT.md000064400000000000000000000002031046102023000136040ustar 00000000000000# The Rust Code of Conduct The Code of Conduct for this repository [can be found online](https://www.rust-lang.org/conduct.html). cargo-0.86.0/CONTRIBUTING.md000064400000000000000000000015031046102023000132420ustar 00000000000000# Contributing to Cargo Contributing documentation has moved to the **[Cargo Contributor Guide]**. [Cargo Contributor Guide]: https://rust-lang.github.io/cargo/contrib/ ## Before hacking on Cargo We encourage people to discuss their design before hacking on code. Typically, you [file an issue] or start a thread on the [internals forum] before submitting a pull request. Please read [the process] of how features and bugs are managed in Cargo. **Only issues that have been explicitly marked as [accepted] will be reviewed.** [internals forum]: https://internals.rust-lang.org/c/tools-and-infrastructure/cargo [file an issue]: https://github.com/rust-lang/cargo/issues [the process]: https://doc.crates.io/contrib/process/index.html [accepted]: https://github.com/rust-lang/cargo/issues?q=is%3Aissue+is%3Aopen+label%3AS-accepted cargo-0.86.0/Cargo.lock0000644000002527070000000000100102120ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "adler2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "once_cell", "version_check", "zerocopy", ] [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "allocator-api2" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "annotate-snippets" version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24e35ed54e5ea7997c14ed4c70ba043478db1112e98263b3b035907aa197d991" dependencies = [ "anstyle", "unicode-width 0.1.13", ] [[package]] name = "anstream" version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-lossy" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f45c79b3b9413932fc255f2c19ca0d48eaab72c4ea1913bafaebf289cbc099f2" dependencies = [ "anstyle", ] [[package]] name = "anstyle-parse" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-svg" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbbf0bf947d663010f0b4132f28ca08da9151f3b9035fa7578a38de521c1d1aa" dependencies = [ "anstream", "anstyle", "anstyle-lossy", "html-escape", "unicode-width 0.1.13", ] [[package]] name = "anstyle-wincon" version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", ] [[package]] name = "anyhow" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arc-swap" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" [[package]] name = "arrayref" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "base16ct" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitmaps" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" dependencies = [ "typenum", ] [[package]] name = "blake3" version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d08263faac5cde2a4d52b513dadb80846023aade56fcd8fc99ba73ba8050e92" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", ] [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] name = "bstr" version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", "regex-automata 0.4.7", "serde", ] [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytes" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "bytesize" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" [[package]] name = "cargo" version = "0.86.0" dependencies = [ "annotate-snippets", "anstream", "anstyle", "anyhow", "base64", "blake3", "bytesize", "cargo-credential", "cargo-credential-libsecret", "cargo-credential-macos-keychain", "cargo-credential-wincred", "cargo-platform", "cargo-test-support", "cargo-util", "cargo-util-schemas", "clap", "clap_complete", "color-print", "crates-io", "curl", "curl-sys", "filetime", "flate2", "git2", "git2-curl", "gix", "glob", "hex", "hmac", "home", "http-auth", "humantime", "ignore", "im-rc", "indexmap", "itertools", "jobserver", "lazycell", "libc", "libgit2-sys", "memchr", "opener", "openssl", "os_info", "pasetors", "pathdiff", "rand", "regex", "rusqlite", "rustc-hash", "rustc-stable-hash", "rustfix", "same-file", "semver", "serde", "serde-untagged", "serde_ignored", "serde_json", "sha1", "shell-escape", "snapbox", "supports-hyperlinks", "supports-unicode", "tar", "tempfile", "thiserror 1.0.63", "time", "toml", "toml_edit", "tracing", "tracing-chrome", "tracing-subscriber", "unicase", "unicode-width 0.2.0", "url", "walkdir", "windows-sys 0.59.0", ] [[package]] name = "cargo-credential" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac1ef5080adde1db190e901884d2c400990856c2a23201c5a181b910a6dbdf2a" dependencies = [ "anyhow", "libc", "serde", "serde_json", "thiserror 1.0.63", "time", "windows-sys 0.59.0", ] [[package]] name = "cargo-credential-libsecret" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2d33572942f4b5f59376b7041198c56b5585404c59172c62fff2372dedba102" dependencies = [ "anyhow", "cargo-credential", "libloading", ] [[package]] name = "cargo-credential-macos-keychain" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41e699cfa3f0a45e8973839768622302a03ab7148c126e96215c2e3e1fc82375" dependencies = [ "cargo-credential", "security-framework", ] [[package]] name = "cargo-credential-wincred" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62219d774bd2d26e803d75d7dfd234022173af157eb9d6f887016839db4d1f19" dependencies = [ "cargo-credential", "windows-sys 0.59.0", ] [[package]] name = "cargo-platform" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84982c6c0ae343635a3a4ee6dedef965513735c8b183caa7289fa6e27399ebd4" dependencies = [ "serde", ] [[package]] name = "cargo-test-macro" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b508b230f753c4c6b032683aca3fe9a5941f78c7ea57527ab66fe0d787231d5" [[package]] name = "cargo-test-support" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a46386869c72a5a9fe1d278a710ca77eb2f9d38e38352f1abbf12e27d50060b" dependencies = [ "anstream", "anstyle", "anyhow", "cargo-test-macro", "cargo-util", "crates-io", "filetime", "flate2", "git2", "glob", "itertools", "pasetors", "regex", "serde", "serde_json", "snapbox", "tar", "time", "toml", "url", "walkdir", "windows-sys 0.59.0", ] [[package]] name = "cargo-util" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "932c5376dc904ef005f0d229a5edc1116f40a78a18d30cdc992ec5acbeffd4d9" dependencies = [ "anyhow", "core-foundation", "filetime", "hex", "ignore", "jobserver", "libc", "miow", "same-file", "sha2", "shell-escape", "tempfile", "tracing", "walkdir", "windows-sys 0.59.0", ] [[package]] name = "cargo-util-schemas" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f905f68f8cb8a8182592d9858a5895360f0a5b08b6901fdb10498fb91829804" dependencies = [ "semver", "serde", "serde-untagged", "serde-value", "thiserror 1.0.63", "toml", "unicode-xid", "url", ] [[package]] name = "cc" version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" dependencies = [ "jobserver", "libc", "shlex", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", "terminal_size", ] [[package]] name = "clap_complete" version = "4.5.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07a13ab5b8cb13dbe35e68b83f6c12f9293b2f601797b71bc9f23befdb329feb" dependencies = [ "clap", "clap_lex", "is_executable", "shlex", ] [[package]] name = "clap_lex" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "clru" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8191fa7302e03607ff0e237d4246cc043ff5b3cb9409d995172ba3bea16b807" [[package]] name = "color-print" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ee543c60ff3888934877a5671f45494dd27ed4ba25c6670b9a7576b7ed7a8c0" dependencies = [ "color-print-proc-macro", ] [[package]] name = "color-print-proc-macro" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ff1a80c5f3cb1ca7c06ffdd71b6a6dd6d8f896c42141fbd43f50ed28dcdb93" dependencies = [ "nom", "proc-macro2", "quote", "syn", ] [[package]] name = "colorchoice" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "const-oid" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "constant_time_eq" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "content_inspector" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38" dependencies = [ "memchr", ] [[package]] name = "core-foundation" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crates-io" version = "0.40.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3278cae111be507cd074ac10cac0ca4638c90911f978a849c1b96086381d347c" dependencies = [ "curl", "percent-encoding", "serde", "serde_json", "thiserror 1.0.63", "url", ] [[package]] name = "crc32fast" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crypto-bigint" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", "rand_core", "subtle", "zeroize", ] [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", ] [[package]] name = "ct-codecs" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3b7eb4404b8195a9abb6356f4ac07d8ba267045c8d6d220ac4dc992e6cc75df" [[package]] name = "curl" version = "0.4.46" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6" dependencies = [ "curl-sys", "libc", "openssl-probe", "openssl-sys", "schannel", "socket2", "windows-sys 0.52.0", ] [[package]] name = "curl-sys" version = "0.4.74+curl-8.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8af10b986114528fcdc4b63b6f5f021b7057618411046a4de2ba0f0149a097bf" dependencies = [ "cc", "libc", "libnghttp2-sys", "libz-sys", "openssl-sys", "pkg-config", "vcpkg", "windows-sys 0.52.0", ] [[package]] name = "dbus" version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" dependencies = [ "libc", "libdbus-sys", "winapi", ] [[package]] name = "der" version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "pem-rfc7468", "zeroize", ] [[package]] name = "deranged" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", "serde", ] [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "const-oid", "crypto-common", "subtle", ] [[package]] name = "dunce" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" [[package]] name = "ecdsa" version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", "digest", "elliptic-curve", "rfc6979", "signature", "spki", ] [[package]] name = "ed25519-compact" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9b3460f44bea8cd47f45a0c70892f1eff856d97cd55358b2f73f663789f6190" dependencies = [ "getrandom", ] [[package]] name = "either" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "elliptic-curve" version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", "digest", "ff", "generic-array", "group", "hkdf", "pem-rfc7468", "pkcs8", "rand_core", "sec1", "subtle", "zeroize", ] [[package]] name = "encoding_rs" version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "erased-serde" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" dependencies = [ "serde", "typeid", ] [[package]] name = "errno" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "fallible-iterator" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fallible-streaming-iterator" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "faster-hex" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" dependencies = [ "serde", ] [[package]] name = "fastrand" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "ff" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ "rand_core", "subtle", ] [[package]] name = "fiat-crypto" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c007b1ae3abe1cb6f85a16305acd418b7ca6343b953633fee2b76d8f108b830f" [[package]] name = "filetime" version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", "redox_syscall", "windows-sys 0.52.0", ] [[package]] name = "flate2" version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "libz-sys", "miniz_oxide", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foreign-types" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ "foreign-types-shared", ] [[package]] name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "generic-array" version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", "zeroize", ] [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", "libc", "wasi", "wasm-bindgen", ] [[package]] name = "git2" version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" dependencies = [ "bitflags 2.6.0", "libc", "libgit2-sys", "log", "openssl-probe", "openssl-sys", "url", ] [[package]] name = "git2-curl" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ff14527a1c242320039b138376f8e0786697a1b7b172bc44f6efda3ab9079f" dependencies = [ "curl", "git2", "log", "url", ] [[package]] name = "gix" version = "0.69.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d0eebdaecdcf405d5433a36f85e4f058cf4de48ee2604388be0dbccbaad353e" dependencies = [ "gix-actor", "gix-attributes", "gix-command", "gix-commitgraph", "gix-config", "gix-credentials", "gix-date", "gix-diff", "gix-dir", "gix-discover", "gix-features", "gix-filter", "gix-fs", "gix-glob", "gix-hash", "gix-hashtable", "gix-ignore", "gix-index", "gix-lock", "gix-negotiate", "gix-object", "gix-odb", "gix-pack", "gix-path", "gix-pathspec", "gix-prompt", "gix-protocol", "gix-ref", "gix-refspec", "gix-revision", "gix-revwalk", "gix-sec", "gix-shallow", "gix-submodule", "gix-tempfile", "gix-trace", "gix-transport", "gix-traverse", "gix-url", "gix-utils", "gix-validate", "gix-worktree", "once_cell", "prodash", "smallvec", "thiserror 2.0.3", ] [[package]] name = "gix-actor" version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b24171f514cef7bb4dfb72a0b06dacf609b33ba8ad2489d4c4559a03b7afb3" dependencies = [ "bstr", "gix-date", "gix-utils", "itoa", "thiserror 2.0.3", "winnow", ] [[package]] name = "gix-attributes" version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddf9bf852194c0edfe699a2d36422d2c1f28f73b7c6d446c3f0ccd3ba232cadc" dependencies = [ "bstr", "gix-glob", "gix-path", "gix-quote", "gix-trace", "kstring", "smallvec", "thiserror 2.0.3", "unicode-bom", ] [[package]] name = "gix-bitmap" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d48b897b4bbc881aea994b4a5bbb340a04979d7be9089791304e04a9fbc66b53" dependencies = [ "thiserror 2.0.3", ] [[package]] name = "gix-chunk" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6ffbeb3a5c0b8b84c3fe4133a6f8c82fa962f4caefe8d0762eced025d3eb4f7" dependencies = [ "thiserror 2.0.3", ] [[package]] name = "gix-command" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9405c0a56e17f8365a46870cd2c7db71323ecc8bda04b50cb746ea37bd091e90" dependencies = [ "bstr", "gix-path", "gix-trace", "shell-words", ] [[package]] name = "gix-commitgraph" version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8da6591a7868fb2b6dabddea6b09988b0b05e0213f938dbaa11a03dd7a48d85" dependencies = [ "bstr", "gix-chunk", "gix-features", "gix-hash", "memmap2", "thiserror 2.0.3", ] [[package]] name = "gix-config" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6649b406ca1f99cb148959cf00468b231f07950f8ec438cc0903cda563606f19" dependencies = [ "bstr", "gix-config-value", "gix-features", "gix-glob", "gix-path", "gix-ref", "gix-sec", "memchr", "once_cell", "smallvec", "thiserror 2.0.3", "unicode-bom", "winnow", ] [[package]] name = "gix-config-value" version = "0.14.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49aaeef5d98390a3bcf9dbc6440b520b793d1bf3ed99317dc407b02be995b28e" dependencies = [ "bitflags 2.6.0", "bstr", "gix-path", "libc", "thiserror 2.0.3", ] [[package]] name = "gix-credentials" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82a50c56b785c29a151ab4ccf74a83fe4e21d2feda0d30549504b4baed353e0a" dependencies = [ "bstr", "gix-command", "gix-config-value", "gix-path", "gix-prompt", "gix-sec", "gix-trace", "gix-url", "thiserror 2.0.3", ] [[package]] name = "gix-date" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c57c477b645ee248b173bb1176b52dd528872f12c50375801a58aaf5ae91113f" dependencies = [ "bstr", "itoa", "jiff", "thiserror 2.0.3", ] [[package]] name = "gix-diff" version = "0.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8e92566eccbca205a0a0f96ffb0327c061e85bc5c95abbcddfe177498aa04f6" dependencies = [ "bstr", "gix-hash", "gix-object", "thiserror 2.0.3", ] [[package]] name = "gix-dir" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fba2ffbcf4bd34438e8a8367ccbc94870549903d1f193a14f47eb6b0967e1293" dependencies = [ "bstr", "gix-discover", "gix-fs", "gix-ignore", "gix-index", "gix-object", "gix-path", "gix-pathspec", "gix-trace", "gix-utils", "gix-worktree", "thiserror 2.0.3", ] [[package]] name = "gix-discover" version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83bf6dfa4e266a4a9becb4d18fc801f92c3f7cc6c433dd86fdadbcf315ffb6ef" dependencies = [ "bstr", "dunce", "gix-fs", "gix-hash", "gix-path", "gix-ref", "gix-sec", "thiserror 2.0.3", ] [[package]] name = "gix-features" version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d85d673f2e022a340dba4713bed77ef2cf4cd737d2f3e0f159d45e0935fd81f" dependencies = [ "bytes", "crc32fast", "crossbeam-channel", "flate2", "gix-hash", "gix-trace", "gix-utils", "libc", "once_cell", "parking_lot", "prodash", "sha1_smol", "thiserror 2.0.3", "walkdir", ] [[package]] name = "gix-filter" version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d0ecdee5667f840ba20c7fe56d63f8e1dc1e6b3bfd296151fe5ef07c874790a" dependencies = [ "bstr", "encoding_rs", "gix-attributes", "gix-command", "gix-hash", "gix-object", "gix-packetline-blocking", "gix-path", "gix-quote", "gix-trace", "gix-utils", "smallvec", "thiserror 2.0.3", ] [[package]] name = "gix-fs" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3d4fac505a621f97e5ce2c69fdc425742af00c0920363ca4074f0eb48b1db9" dependencies = [ "fastrand", "gix-features", "gix-utils", ] [[package]] name = "gix-glob" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aaf69a6bec0a3581567484bf99a4003afcaf6c469fd4214352517ea355cf3435" dependencies = [ "bitflags 2.6.0", "bstr", "gix-features", "gix-path", ] [[package]] name = "gix-hash" version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b5eccc17194ed0e67d49285e4853307e4147e95407f91c1c3e4a13ba9f4e4ce" dependencies = [ "faster-hex", "thiserror 2.0.3", ] [[package]] name = "gix-hashtable" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ef65b256631078ef733bc5530c4e6b1c2e7d5c2830b75d4e9034ab3997d18fe" dependencies = [ "gix-hash", "hashbrown", "parking_lot", ] [[package]] name = "gix-ignore" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6b1fb24d2a4af0aa7438e2771d60c14a80cf2c9bd55c29cf1712b841f05bb8a" dependencies = [ "bstr", "gix-glob", "gix-path", "gix-trace", "unicode-bom", ] [[package]] name = "gix-index" version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "270645fd20556b64c8ffa1540d921b281e6994413a0ca068596f97e9367a257a" dependencies = [ "bitflags 2.6.0", "bstr", "filetime", "fnv", "gix-bitmap", "gix-features", "gix-fs", "gix-hash", "gix-lock", "gix-object", "gix-traverse", "gix-utils", "gix-validate", "hashbrown", "itoa", "libc", "memmap2", "rustix", "smallvec", "thiserror 2.0.3", ] [[package]] name = "gix-lock" version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5102acdf4acae2644e38dbbd18cdfba9597a218f7d85f810fe5430207e03c2de" dependencies = [ "gix-tempfile", "gix-utils", "thiserror 1.0.63", ] [[package]] name = "gix-negotiate" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d27f830a16405386e9c83b9d5be8261fe32bbd6b3caf15bd1b284c6b2b7ef1a8" dependencies = [ "bitflags 2.6.0", "gix-commitgraph", "gix-date", "gix-hash", "gix-object", "gix-revwalk", "smallvec", "thiserror 2.0.3", ] [[package]] name = "gix-object" version = "0.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42d58010183ef033f31088479b4eb92b44fe341b35b62d39eb8b185573d77ea" dependencies = [ "bstr", "gix-actor", "gix-date", "gix-features", "gix-hash", "gix-hashtable", "gix-path", "gix-utils", "gix-validate", "itoa", "smallvec", "thiserror 2.0.3", "winnow", ] [[package]] name = "gix-odb" version = "0.66.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb780eceb3372ee204469478de02eaa34f6ba98247df0186337e0333de97d0ae" dependencies = [ "arc-swap", "gix-date", "gix-features", "gix-fs", "gix-hash", "gix-hashtable", "gix-object", "gix-pack", "gix-path", "gix-quote", "parking_lot", "tempfile", "thiserror 2.0.3", ] [[package]] name = "gix-pack" version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4158928929be29cae7ab97afc8e820a932071a7f39d8ba388eed2380c12c566c" dependencies = [ "clru", "gix-chunk", "gix-features", "gix-hash", "gix-hashtable", "gix-object", "gix-path", "gix-tempfile", "memmap2", "parking_lot", "smallvec", "thiserror 2.0.3", ] [[package]] name = "gix-packetline" version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "911aeea8b2dabeed2f775af9906152a1f0109787074daf9e64224e3892dde453" dependencies = [ "bstr", "faster-hex", "gix-trace", "thiserror 2.0.3", ] [[package]] name = "gix-packetline-blocking" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce9004ce1bc00fd538b11c1ec8141a1558fb3af3d2b7ac1ac5c41881f9e42d2a" dependencies = [ "bstr", "faster-hex", "gix-trace", "thiserror 2.0.3", ] [[package]] name = "gix-path" version = "0.10.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afc292ef1a51e340aeb0e720800338c805975724c1dfbd243185452efd8645b7" dependencies = [ "bstr", "gix-trace", "home", "once_cell", "thiserror 2.0.3", ] [[package]] name = "gix-pathspec" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c472dfbe4a4e96fcf7efddcd4771c9037bb4fdea2faaabf2f4888210c75b81e" dependencies = [ "bitflags 2.6.0", "bstr", "gix-attributes", "gix-config-value", "gix-glob", "gix-path", "thiserror 2.0.3", ] [[package]] name = "gix-prompt" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82433a19aa44688e3bde05c692870eda50b5db053df53ed5ae6d8ea594a6babd" dependencies = [ "gix-command", "gix-config-value", "parking_lot", "rustix", "thiserror 2.0.3", ] [[package]] name = "gix-protocol" version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c84642e8b6fed7035ce9cc449593019c55b0ec1af7a5dce1ab8a0636eaaeb067" dependencies = [ "bstr", "gix-credentials", "gix-date", "gix-features", "gix-hash", "gix-lock", "gix-negotiate", "gix-object", "gix-ref", "gix-refspec", "gix-revwalk", "gix-shallow", "gix-trace", "gix-transport", "gix-utils", "maybe-async", "thiserror 2.0.3", "winnow", ] [[package]] name = "gix-quote" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64a1e282216ec2ab2816cd57e6ed88f8009e634aec47562883c05ac8a7009a63" dependencies = [ "bstr", "gix-utils", "thiserror 2.0.3", ] [[package]] name = "gix-ref" version = "0.49.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a91b61776c839d0f1b7114901179afb0947aa7f4d30793ca1c56d335dfef485f" dependencies = [ "gix-actor", "gix-features", "gix-fs", "gix-hash", "gix-lock", "gix-object", "gix-path", "gix-tempfile", "gix-utils", "gix-validate", "memmap2", "thiserror 2.0.3", "winnow", ] [[package]] name = "gix-refspec" version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00c056bb747868c7eb0aeb352c9f9181ab8ca3d0a2550f16470803500c6c413d" dependencies = [ "bstr", "gix-hash", "gix-revision", "gix-validate", "smallvec", "thiserror 2.0.3", ] [[package]] name = "gix-revision" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61e1ddc474405a68d2ce8485705dd72fe6ce959f2f5fe718601ead5da2c8f9e7" dependencies = [ "bitflags 2.6.0", "bstr", "gix-commitgraph", "gix-date", "gix-hash", "gix-hashtable", "gix-object", "gix-revwalk", "gix-trace", "thiserror 2.0.3", ] [[package]] name = "gix-revwalk" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "510026fc32f456f8f067d8f37c34088b97a36b2229d88a6a5023ef179fcb109d" dependencies = [ "gix-commitgraph", "gix-date", "gix-hash", "gix-hashtable", "gix-object", "smallvec", "thiserror 2.0.3", ] [[package]] name = "gix-sec" version = "0.10.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8b876ef997a955397809a2ec398d6a45b7a55b4918f2446344330f778d14fd6" dependencies = [ "bitflags 2.6.0", "gix-path", "libc", "windows-sys 0.52.0", ] [[package]] name = "gix-shallow" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d2673242e87492cb6ff671f0c01f689061ca306c4020f137197f3abc84ce01" dependencies = [ "bstr", "gix-hash", "gix-lock", "thiserror 2.0.3", ] [[package]] name = "gix-submodule" version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2455f8c0fcb6ebe2a6e83c8f522d30615d763eb2ef7a23c7d929f9476e89f5c" dependencies = [ "bstr", "gix-config", "gix-path", "gix-pathspec", "gix-refspec", "gix-url", "thiserror 2.0.3", ] [[package]] name = "gix-tempfile" version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2feb86ef094cc77a4a9a5afbfe5de626897351bbbd0de3cb9314baf3049adb82" dependencies = [ "gix-fs", "libc", "once_cell", "parking_lot", "tempfile", ] [[package]] name = "gix-trace" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04bdde120c29f1fc23a24d3e115aeeea3d60d8e65bab92cc5f9d90d9302eb952" [[package]] name = "gix-transport" version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd04d91e507a8713cfa2318d5a85d75b36e53a40379cc7eb7634ce400ecacbaf" dependencies = [ "base64", "bstr", "curl", "gix-command", "gix-credentials", "gix-features", "gix-packetline", "gix-quote", "gix-sec", "gix-url", "thiserror 2.0.3", ] [[package]] name = "gix-traverse" version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ed47d648619e23e93f971d2bba0d10c1100e54ef95d2981d609907a8cabac89" dependencies = [ "bitflags 2.6.0", "gix-commitgraph", "gix-date", "gix-hash", "gix-hashtable", "gix-object", "gix-revwalk", "smallvec", "thiserror 2.0.3", ] [[package]] name = "gix-url" version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d096fb733ba6bd3f5403dba8bd72bdd8809fe2b347b57844040b8f49c93492d9" dependencies = [ "bstr", "gix-features", "gix-path", "percent-encoding", "thiserror 2.0.3", "url", ] [[package]] name = "gix-utils" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba427e3e9599508ed98a6ddf8ed05493db114564e338e41f6a996d2e4790335f" dependencies = [ "bstr", "fastrand", "unicode-normalization", ] [[package]] name = "gix-validate" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd520d09f9f585b34b32aba1d0b36ada89ab7fefb54a8ca3fe37fc482a750937" dependencies = [ "bstr", "thiserror 2.0.3", ] [[package]] name = "gix-worktree" version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "756dbbe15188fa22540d5eab941f8f9cf511a5364d5aec34c88083c09f4bea13" dependencies = [ "bstr", "gix-attributes", "gix-features", "gix-fs", "gix-glob", "gix-hash", "gix-ignore", "gix-index", "gix-object", "gix-path", "gix-validate", ] [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" dependencies = [ "aho-corasick", "bstr", "log", "regex-automata 0.4.7", "regex-syntax 0.8.4", ] [[package]] name = "group" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", "rand_core", "subtle", ] [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", ] [[package]] name = "hashlink" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "692eaaf7f7607518dd3cef090f1474b61edc5301d8012f09579920df68b725ee" dependencies = [ "hashbrown", ] [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hkdf" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac", ] [[package]] name = "hmac" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ "digest", ] [[package]] name = "home" version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "html-escape" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" dependencies = [ "utf8-width", ] [[package]] name = "http-auth" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "643c9bbf6a4ea8a656d6b4cd53d34f79e3f841ad5203c1a55fb7d761923bc255" dependencies = [ "memchr", ] [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "idna" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", ] [[package]] name = "ignore" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" dependencies = [ "crossbeam-deque", "globset", "log", "memchr", "regex-automata 0.4.7", "same-file", "walkdir", "winapi-util", ] [[package]] name = "im-rc" version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" dependencies = [ "bitmaps", "rand_core", "rand_xoshiro", "sized-chunks", "typenum", "version_check", ] [[package]] name = "indexmap" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "is_executable" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ba3d8548b8b04dafdf2f4cc6f5e379db766d0a6d9aac233ad4c9a92ea892233" dependencies = [ "winapi", ] [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jiff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a45489186a6123c128fdf6016183fcfab7113e1820eb813127e036e287233fb" dependencies = [ "jiff-tzdb-platform", "windows-sys 0.59.0", ] [[package]] name = "jiff-tzdb" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91335e575850c5c4c673b9bd467b0e025f164ca59d0564f69d0c2ee0ffad4653" [[package]] name = "jiff-tzdb-platform" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9835f0060a626fe59f160437bc725491a6af23133ea906500027d1bd2f8f4329" dependencies = [ "jiff-tzdb", ] [[package]] name = "jobserver" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] [[package]] name = "js-sys" version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] [[package]] name = "kstring" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747" dependencies = [ "static_assertions", ] [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "lazycell" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libdbus-sys" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" dependencies = [ "cc", "pkg-config", ] [[package]] name = "libgit2-sys" version = "0.17.0+1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" dependencies = [ "cc", "libc", "libssh2-sys", "libz-sys", "openssl-sys", "pkg-config", ] [[package]] name = "libloading" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", "windows-targets 0.52.6", ] [[package]] name = "libnghttp2-sys" version = "0.1.10+1.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "959c25552127d2e1fa72f0e52548ec04fc386e827ba71a7bd01db46a447dc135" dependencies = [ "cc", "libc", ] [[package]] name = "libsqlite3-sys" version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", "vcpkg", ] [[package]] name = "libssh2-sys" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" dependencies = [ "cc", "libc", "libz-sys", "openssl-sys", "pkg-config", "vcpkg", ] [[package]] name = "libz-sys" version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" dependencies = [ "cc", "libc", "pkg-config", "vcpkg", ] [[package]] name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "matchers" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ "regex-automata 0.1.10", ] [[package]] name = "maybe-async" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" dependencies = [ "libc", ] [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ "adler2", ] [[package]] name = "miow" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "359f76430b20a79f9e20e115b3428614e654f04fab314482fc0fda0ebd3c6044" dependencies = [ "windows-sys 0.48.0", ] [[package]] name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", ] [[package]] name = "normalize-line-endings" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "normpath" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5831952a9476f2fed74b77d74182fa5ddc4d21c72ec45a333b250e3ed0272804" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "nu-ansi-term" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ "overload", "winapi", ] [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opener" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8df34be653210fbe9ffaff41d3b92721c56ce82dfee58ee684f9afb5e3a90c0" dependencies = [ "bstr", "dbus", "normpath", "windows-sys 0.52.0", ] [[package]] name = "openssl" version = "0.10.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" dependencies = [ "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", "once_cell", "openssl-macros", "openssl-sys", ] [[package]] name = "openssl-macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "openssl-probe" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" version = "111.28.2+1.1.1w" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb1830e20a48a975ca898ca8c1d036a36c3c6c5cb7dabc1c216706587857920f" dependencies = [ "cc", ] [[package]] name = "openssl-sys" version = "0.9.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db7e971c2c2bba161b2d2fdf37080177eff520b3bc044787c7f1f5f9e78d869b" dependencies = [ "cc", "libc", "openssl-src", "pkg-config", "vcpkg", ] [[package]] name = "ordered-float" version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" dependencies = [ "num-traits", ] [[package]] name = "orion" version = "0.17.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abdb10181903c8c4b016ba45d6d6d5af1a1e2a461aa4763a83b87f5df4695e5" dependencies = [ "fiat-crypto", "subtle", "zeroize", ] [[package]] name = "os_info" version = "3.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" dependencies = [ "log", "windows-sys 0.52.0", ] [[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "p384" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" dependencies = [ "ecdsa", "elliptic-curve", "primeorder", "sha2", ] [[package]] name = "parking_lot" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-targets 0.48.5", ] [[package]] name = "pasetors" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b719f62f9b77cfadf01500984ab26c7bda71b3f1e497e9dbb055ff466dbe2a86" dependencies = [ "ct-codecs", "ed25519-compact", "getrandom", "orion", "p384", "rand_core", "regex", "serde", "serde_json", "sha2", "subtle", "time", "zeroize", ] [[package]] name = "pathdiff" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" [[package]] name = "pem-rfc7468" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" dependencies = [ "base64ct", ] [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pkcs8" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der", "spki", ] [[package]] name = "pkg-config" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "powerfmt" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "primeorder" version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" dependencies = [ "elliptic-curve", ] [[package]] name = "proc-macro2" version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "prodash" version = "29.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a266d8d6020c61a437be704c5e618037588e1985c7dbb7bf8d265db84cffe325" dependencies = [ "log", "parking_lot", ] [[package]] name = "quote" version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "rand_xoshiro" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" dependencies = [ "rand_core", ] [[package]] name = "redox_syscall" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "regex" version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", "regex-automata 0.4.7", "regex-syntax 0.8.4", ] [[package]] name = "regex-automata" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ "regex-syntax 0.6.29", ] [[package]] name = "regex-automata" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", "regex-syntax 0.8.4", ] [[package]] name = "regex-syntax" version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rfc6979" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ "hmac", "subtle", ] [[package]] name = "rusqlite" version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" dependencies = [ "bitflags 2.6.0", "fallible-iterator", "fallible-streaming-iterator", "hashlink", "libsqlite3-sys", "smallvec", ] [[package]] name = "rustc-hash" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "rustc-stable-hash" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2febf9acc5ee5e99d1ad0afcdbccc02d87aa3f857a1f01f825b80eacf8edfcd1" [[package]] name = "rustfix" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f66156d7471ff4f12253cd7fd76dfe637a595a9418168154e8570f3947fe9a8" dependencies = [ "serde", "serde_json", "thiserror 1.0.63", "tracing", ] [[package]] name = "rustix" version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", "windows-sys 0.52.0", ] [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "schannel" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sec1" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", "generic-array", "pkcs8", "subtle", "zeroize", ] [[package]] name = "security-framework" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d0283c0a4a22a0f1b0e4edca251aa20b92fc96eaa09b84bec052f9415e9d71" dependencies = [ "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", "security-framework-sys", ] [[package]] name = "security-framework-sys" version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "semver" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ "serde", ] [[package]] name = "serde" version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde-untagged" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2676ba99bd82f75cae5cbd2c8eda6fa0b8760f18978ea840e980dd5567b5c5b6" dependencies = [ "erased-serde", "serde", "typeid", ] [[package]] name = "serde-value" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" dependencies = [ "ordered-float", "serde", ] [[package]] name = "serde_derive" version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_ignored" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8e319a36d1b52126a0d608f24e93b2d81297091818cd70625fcf50a15d84ddf" dependencies = [ "serde", ] [[package]] name = "serde_json" version = "1.0.121" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] [[package]] name = "sha1" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", "digest", ] [[package]] name = "sha1_smol" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" [[package]] name = "sha2" version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", "digest", ] [[package]] name = "sharded-slab" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] [[package]] name = "shell-escape" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" [[package]] name = "shell-words" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signature" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", "rand_core", ] [[package]] name = "similar" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" [[package]] name = "sized-chunks" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" dependencies = [ "bitmaps", "typenum", ] [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "snapbox" version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1373ce406dfad473059bbc31d807715642182bbc952a811952b58d1c9e41dcfa" dependencies = [ "anstream", "anstyle", "anstyle-svg", "content_inspector", "dunce", "filetime", "normalize-line-endings", "regex", "serde", "serde_json", "similar", "snapbox-macros", "tempfile", "walkdir", ] [[package]] name = "snapbox-macros" version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16569f53ca23a41bb6f62e0a5084aa1661f4814a67fa33696a79073e03a664af" dependencies = [ "anstream", ] [[package]] name = "socket2" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "spki" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", ] [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "supports-hyperlinks" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c0a1e5168041f5f3ff68ff7d95dcb9c8749df29f6e7e89ada40dd4c9de404ee" [[package]] name = "supports-unicode" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" [[package]] name = "syn" version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "tar" version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" dependencies = [ "filetime", "libc", ] [[package]] name = "tempfile" version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", "rustix", "windows-sys 0.52.0", ] [[package]] name = "terminal_size" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" dependencies = [ "rustix", "windows-sys 0.59.0", ] [[package]] name = "thiserror" version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl 1.0.63", ] [[package]] name = "thiserror" version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" dependencies = [ "thiserror-impl 2.0.3", ] [[package]] name = "thiserror-impl" version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "thiserror-impl" version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "thread_local" version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", ] [[package]] name = "time" version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", "serde", "time-core", "time-macros", ] [[package]] name = "time-core" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ "num-conv", "time-core", ] [[package]] name = "tinyvec" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toml" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", "toml_edit", ] [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", "winnow", ] [[package]] name = "tracing" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tracing-chrome" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf0a738ed5d6450a9fb96e86a23ad808de2b727fd1394585da5cdd6788ffe724" dependencies = [ "serde_json", "tracing-core", "tracing-subscriber", ] [[package]] name = "tracing-core" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", ] [[package]] name = "tracing-log" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ "log", "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", "once_cell", "regex", "sharded-slab", "smallvec", "thread_local", "tracing", "tracing-core", "tracing-log", ] [[package]] name = "typeid" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "059d83cc991e7a42fc37bd50941885db0888e34209f8cfd9aab07ddec03bc9cf" [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicase" version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" dependencies = [ "version_check", ] [[package]] name = "unicode-bidi" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-bom" version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" [[package]] name = "unicode-ident" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-width" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-width" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "unicode-xid" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "url" version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] [[package]] name = "utf8-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "valuable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" cargo-0.86.0/Cargo.toml0000644000000152460000000000100102300ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.83" name = "cargo" version = "0.86.0" build = "build.rs" autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = """ Cargo, a package manager for Rust. """ homepage = "https://doc.rust-lang.org/cargo/index.html" documentation = "https://docs.rs/cargo" readme = "README.md" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/cargo" [lib] name = "cargo" path = "src/cargo/lib.rs" [[bin]] name = "cargo" path = "src/bin/cargo/main.rs" test = false doc = false [[test]] name = "build-std" path = "tests/build-std/main.rs" [[test]] name = "testsuite" path = "tests/testsuite/main.rs" [dependencies.annotate-snippets] version = "0.11.4" [dependencies.anstream] version = "0.6.15" [dependencies.anstyle] version = "1.0.8" [dependencies.anyhow] version = "1.0.86" [dependencies.base64] version = "0.22.1" [dependencies.blake3] version = "1.5.2" [dependencies.bytesize] version = "1.3" [dependencies.cargo-credential] version = "0.4.2" [dependencies.cargo-platform] version = "0.2.0" [dependencies.cargo-util] version = "0.2.14" [dependencies.cargo-util-schemas] version = "0.7.0" [dependencies.clap] version = "4.5.20" features = ["wrap_help"] [dependencies.clap_complete] version = "4.5.35" features = ["unstable-dynamic"] [dependencies.color-print] version = "0.3.6" [dependencies.crates-io] version = "0.40.4" [dependencies.curl] version = "0.4.46" features = ["http2"] [dependencies.curl-sys] version = "0.4.73" [dependencies.filetime] version = "0.2.23" [dependencies.flate2] version = "1.0.30" features = ["zlib"] default-features = false [dependencies.git2] version = "0.19.0" [dependencies.git2-curl] version = "0.20.0" [dependencies.gix] version = "0.69.1" features = [ "blocking-http-transport-curl", "progress-tree", "parallel", "dirwalk", ] default-features = false [dependencies.glob] version = "0.3.1" [dependencies.hex] version = "0.4.3" [dependencies.hmac] version = "0.12.1" [dependencies.home] version = "0.5.9" [dependencies.http-auth] version = "0.1.9" default-features = false [dependencies.humantime] version = "2.1.0" [dependencies.ignore] version = "0.4.22" [dependencies.im-rc] version = "15.1.0" [dependencies.indexmap] version = "2.2.6" [dependencies.itertools] version = "0.13.0" [dependencies.jobserver] version = "0.1.32" [dependencies.lazycell] version = "1.3.0" [dependencies.libgit2-sys] version = "0.17.0" [dependencies.memchr] version = "2.7.4" [dependencies.opener] version = "0.7.1" [dependencies.os_info] version = "3.8.2" default-features = false [dependencies.pasetors] version = "0.7.0" features = [ "v3", "paserk", "std", "serde", ] [dependencies.pathdiff] version = "0.2.1" [dependencies.rand] version = "0.8.5" [dependencies.regex] version = "1.10.5" [dependencies.rusqlite] version = "0.32.0" features = ["bundled"] [dependencies.rustc-hash] version = "2.0.0" [dependencies.rustc-stable-hash] version = "0.1.1" [dependencies.rustfix] version = "0.9.0" [dependencies.same-file] version = "1.0.6" [dependencies.semver] version = "1.0.23" features = ["serde"] [dependencies.serde] version = "1.0.204" features = ["derive"] [dependencies.serde-untagged] version = "0.1.6" [dependencies.serde_ignored] version = "0.1.10" [dependencies.serde_json] version = "1.0.120" features = ["raw_value"] [dependencies.sha1] version = "0.10.6" [dependencies.shell-escape] version = "0.1.5" [dependencies.supports-hyperlinks] version = "3.0.0" [dependencies.supports-unicode] version = "3.0.0" [dependencies.tar] version = "0.4.42" default-features = false [dependencies.tempfile] version = "3.10.1" [dependencies.thiserror] version = "1.0.63" [dependencies.time] version = "0.3.36" features = [ "parsing", "formatting", "serde", ] [dependencies.toml] version = "0.8.19" [dependencies.toml_edit] version = "0.22.20" features = ["serde"] [dependencies.tracing] version = "0.1.40" features = [ "std", "attributes", ] default-features = false [dependencies.tracing-subscriber] version = "0.3.18" features = ["env-filter"] [dependencies.unicase] version = "2.7.0" [dependencies.unicode-width] version = "0.2.0" [dependencies.url] version = "2.5.2" [dependencies.walkdir] version = "2.5.0" [dev-dependencies.annotate-snippets] version = "0.11.4" features = ["testing-colors"] [dev-dependencies.cargo-test-support] version = "0.7.0" [dev-dependencies.gix] version = "0.69.1" features = [ "blocking-http-transport-curl", "progress-tree", "parallel", "dirwalk", "revision", ] default-features = false [dev-dependencies.same-file] version = "1.0.6" [dev-dependencies.snapbox] version = "0.6.20" features = [ "diff", "dir", "term-svg", "regex", "json", ] [build-dependencies.flate2] version = "1.0.30" features = ["zlib"] default-features = false [build-dependencies.tar] version = "0.4.42" default-features = false [features] all-static = [ "vendored-openssl", "curl/static-curl", "curl/force-system-lib-on-osx", "vendored-libgit2", ] vendored-libgit2 = ["libgit2-sys/vendored"] vendored-openssl = ["openssl/vendored"] [target."cfg(not(windows))".dependencies.openssl] version = "=0.10.57" optional = true [target.'cfg(target_has_atomic = "64")'.dependencies.tracing-chrome] version = "0.7.2" [target.'cfg(target_os = "linux")'.dependencies.cargo-credential-libsecret] version = "0.4.7" [target.'cfg(target_os = "macos")'.dependencies.cargo-credential-macos-keychain] version = "0.4.7" [target."cfg(unix)".dependencies.libc] version = "0.2.155" [target."cfg(windows)".dependencies.cargo-credential-wincred] version = "0.4.7" [target."cfg(windows)".dependencies.windows-sys] version = "0.59" features = [ "Win32_Foundation", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_Console", "Win32_System_JobObjects", "Win32_System_Threading", ] [lints.clippy] dbg_macro = "warn" disallowed_methods = "warn" print_stderr = "warn" print_stdout = "warn" self_named_module_files = "warn" [lints.clippy.all] level = "allow" priority = -2 [lints.clippy.correctness] level = "warn" priority = -1 [lints.rust] rust_2018_idioms = "warn" [lints.rustdoc] private_intra_doc_links = "allow" cargo-0.86.0/Cargo.toml.orig000064400000000000000000000203141046102023000137010ustar 00000000000000[workspace] resolver = "2" members = [ "crates/*", "credential/*", "benches/benchsuite", "benches/capture", ] exclude = [ "target/", # exclude bench testing ] [workspace.package] rust-version = "1.81" # MSRV:3 edition = "2021" license = "MIT OR Apache-2.0" homepage = "https://github.com/rust-lang/cargo" repository = "https://github.com/rust-lang/cargo" [workspace.dependencies] annotate-snippets = "0.11.4" anstream = "0.6.15" anstyle = "1.0.8" anyhow = "1.0.86" base64 = "0.22.1" blake3 = "1.5.2" build-rs = { version = "0.3.0", path = "crates/build-rs" } bytesize = "1.3" cargo = { path = "" } cargo-credential = { version = "0.4.2", path = "credential/cargo-credential" } cargo-credential-libsecret = { version = "0.4.7", path = "credential/cargo-credential-libsecret" } cargo-credential-macos-keychain = { version = "0.4.7", path = "credential/cargo-credential-macos-keychain" } cargo-credential-wincred = { version = "0.4.7", path = "credential/cargo-credential-wincred" } cargo-platform = { path = "crates/cargo-platform", version = "0.2.0" } cargo-test-macro = { version = "0.4.0", path = "crates/cargo-test-macro" } cargo-test-support = { version = "0.7.0", path = "crates/cargo-test-support" } cargo-util = { version = "0.2.14", path = "crates/cargo-util" } cargo-util-schemas = { version = "0.7.0", path = "crates/cargo-util-schemas" } cargo_metadata = "0.19.0" clap = "4.5.20" clap_complete = { version = "4.5.35", features = ["unstable-dynamic"] } color-print = "0.3.6" core-foundation = { version = "0.10.0", features = ["mac_os_10_7_support"] } crates-io = { version = "0.40.4", path = "crates/crates-io" } criterion = { version = "0.5.1", features = ["html_reports"] } curl = "0.4.46" curl-sys = "0.4.73" filetime = "0.2.23" flate2 = { version = "1.0.30", default-features = false, features = ["zlib"] } git2 = "0.19.0" git2-curl = "0.20.0" gix = { version = "0.69.1", default-features = false, features = ["blocking-http-transport-curl", "progress-tree", "parallel", "dirwalk"] } glob = "0.3.1" handlebars = { version = "6.0.0", features = ["dir_source"] } hex = "0.4.3" hmac = "0.12.1" home = "0.5.9" http-auth = { version = "0.1.9", default-features = false } humantime = "2.1.0" ignore = "0.4.22" im-rc = "15.1.0" indexmap = "2.2.6" itertools = "0.13.0" jobserver = "0.1.32" lazycell = "1.3.0" libc = "0.2.155" libgit2-sys = "0.17.0" libloading = "0.8.5" memchr = "2.7.4" miow = "0.6.0" opener = "0.7.1" openssl = "=0.10.57" # See rust-lang/cargo#13546 and openssl/openssl#23376 for pinning openssl-sys = "=0.9.92" # See rust-lang/cargo#13546 and openssl/openssl#23376 for pinning os_info = { version = "3.8.2", default-features = false } pasetors = { version = "0.7.0", features = ["v3", "paserk", "std", "serde"] } pathdiff = "0.2.1" percent-encoding = "2.3.1" pkg-config = "0.3.30" proptest = "1.5.0" pulldown-cmark = { version = "0.12.0", default-features = false, features = ["html"] } rand = "0.8.5" regex = "1.10.5" rusqlite = { version = "0.32.0", features = ["bundled"] } rustc-hash = "2.0.0" rustc-stable-hash = "0.1.1" rustfix = { version = "0.9.0", path = "crates/rustfix" } same-file = "1.0.6" schemars = "0.8.21" security-framework = "3.0.0" semver = { version = "1.0.23", features = ["serde"] } serde = "1.0.204" serde-untagged = "0.1.6" serde-value = "0.7.0" serde_ignored = "0.1.10" serde_json = "1.0.120" sha1 = "0.10.6" sha2 = "0.10.8" shell-escape = "0.1.5" similar = "2.6.0" supports-hyperlinks = "3.0.0" supports-unicode = "3.0.0" snapbox = { version = "0.6.20", features = ["diff", "dir", "term-svg", "regex", "json"] } tar = { version = "0.4.42", default-features = false } tempfile = "3.10.1" thiserror = "1.0.63" time = { version = "0.3.36", features = ["parsing", "formatting", "serde"] } toml = "0.8.19" toml_edit = { version = "0.22.20", features = ["serde"] } tracing = { version = "0.1.40", default-features = false, features = ["std"] } # be compatible with rustc_log: https://github.com/rust-lang/rust/blob/e51e98dde6a/compiler/rustc_log/Cargo.toml#L9 tracing-chrome = "0.7.2" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } unicase = "2.7.0" unicode-ident = "1.0.13" unicode-width = "0.2.0" unicode-xid = "0.2.4" url = "2.5.2" varisat = "0.2.2" walkdir = "2.5.0" windows-sys = "0.59" [workspace.lints.rust] rust_2018_idioms = "warn" # TODO: could this be removed? [workspace.lints.rustdoc] private_intra_doc_links = "allow" [workspace.lints.clippy] all = { level = "allow", priority = -2 } correctness = { level = "warn", priority = -1 } dbg_macro = "warn" disallowed_methods = "warn" print_stderr = "warn" print_stdout = "warn" self_named_module_files = "warn" [package] name = "cargo" version = "0.86.0" edition.workspace = true license.workspace = true rust-version = "1.83" # MSRV:1 homepage = "https://doc.rust-lang.org/cargo/index.html" repository.workspace = true documentation = "https://docs.rs/cargo" description = """ Cargo, a package manager for Rust. """ [lib] name = "cargo" path = "src/cargo/lib.rs" [dependencies] annotate-snippets.workspace = true anstream.workspace = true anstyle.workspace = true anyhow.workspace = true base64.workspace = true blake3.workspace = true bytesize.workspace = true cargo-credential.workspace = true cargo-platform.workspace = true cargo-util-schemas.workspace = true cargo-util.workspace = true clap = { workspace = true, features = ["wrap_help"] } clap_complete.workspace = true color-print.workspace = true crates-io.workspace = true curl = { workspace = true, features = ["http2"] } curl-sys.workspace = true filetime.workspace = true flate2.workspace = true git2.workspace = true git2-curl.workspace = true gix.workspace = true glob.workspace = true hex.workspace = true hmac.workspace = true home.workspace = true http-auth.workspace = true humantime.workspace = true ignore.workspace = true im-rc.workspace = true indexmap.workspace = true itertools.workspace = true jobserver.workspace = true lazycell.workspace = true libgit2-sys.workspace = true memchr.workspace = true opener.workspace = true os_info.workspace = true pasetors.workspace = true pathdiff.workspace = true rand.workspace = true regex.workspace = true rusqlite.workspace = true rustc-hash.workspace = true rustc-stable-hash.workspace = true rustfix.workspace = true same-file.workspace = true semver.workspace = true serde = { workspace = true, features = ["derive"] } serde-untagged.workspace = true serde_ignored.workspace = true serde_json = { workspace = true, features = ["raw_value"] } sha1.workspace = true shell-escape.workspace = true supports-hyperlinks.workspace = true supports-unicode.workspace = true tar.workspace = true tempfile.workspace = true thiserror.workspace = true time.workspace = true toml.workspace = true toml_edit.workspace = true tracing = { workspace = true, features = ["attributes"] } tracing-subscriber.workspace = true unicase.workspace = true unicode-width.workspace = true url.workspace = true walkdir.workspace = true [target.'cfg(target_has_atomic = "64")'.dependencies] tracing-chrome.workspace = true [target.'cfg(unix)'.dependencies] libc.workspace = true [target.'cfg(target_os = "linux")'.dependencies] cargo-credential-libsecret.workspace = true [target.'cfg(target_os = "macos")'.dependencies] cargo-credential-macos-keychain.workspace = true [target.'cfg(not(windows))'.dependencies] openssl = { workspace = true, optional = true } [target.'cfg(windows)'.dependencies] cargo-credential-wincred.workspace = true [target.'cfg(windows)'.dependencies.windows-sys] workspace = true features = [ "Win32_Foundation", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_Console", "Win32_System_JobObjects", "Win32_System_Threading", ] [dev-dependencies] annotate-snippets = { workspace = true, features = ["testing-colors"] } cargo-test-support.workspace = true gix = { workspace = true, features = ["revision"] } same-file.workspace = true snapbox.workspace = true [build-dependencies] flate2.workspace = true tar.workspace = true [[bin]] name = "cargo" test = false doc = false [features] vendored-openssl = ["openssl/vendored"] vendored-libgit2 = ["libgit2-sys/vendored"] # This is primarily used by rust-lang/rust distributing cargo the executable. all-static = ['vendored-openssl', 'curl/static-curl', 'curl/force-system-lib-on-osx', 'vendored-libgit2'] [lints] workspace = true cargo-0.86.0/LICENSE-APACHE000064400000000000000000000251541046102023000127450ustar 00000000000000 Apache License Version 2.0, January 2004 https://www.apache.org/licenses/LICENSE-2.0 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. cargo-0.86.0/LICENSE-MIT000064400000000000000000000017771046102023000124620ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cargo-0.86.0/LICENSE-THIRD-PARTY000064400000000000000000002055161046102023000135750ustar 00000000000000The Cargo source code itself does not bundle any third party libraries, but it depends on a number of libraries which carry their own copyright notices and license terms. These libraries are normally all linked static into the binary distributions of Cargo: * OpenSSL - https://www.openssl.org/source/license.html Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. All advertising materials mentioning features or use of this software must display the following acknowledgment: "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (https://www.openssl.org/)" 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact openssl-core@openssl.org. 5. Products derived from this software may not be called "OpenSSL" nor may "OpenSSL" appear in their names without prior written permission of the OpenSSL Project. 6. Redistributions of any form whatsoever must retain the following acknowledgment: "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (https://www.openssl.org/)" THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================== This product includes cryptographic software written by Eric Young (eay@cryptsoft.com). This product includes software written by Tim Hudson (tjh@cryptsoft.com). --- Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved. This package is an SSL implementation written by Eric Young (eay@cryptsoft.com). The implementation was written so as to conform with Netscapes SSL. This library is free for commercial and non-commercial use as long as the following conditions are aheared to. The following conditions apply to all code found in this distribution, be it the RC4, RSA, lhash, DES, etc., code; not just the SSL code. The SSL documentation included with this distribution is covered by the same copyright terms except that the holder is Tim Hudson (tjh@cryptsoft.com). Copyright remains Eric Young's, and as such any Copyright notices in the code are not to be removed. If this package is used in a product, Eric Young should be given attribution as the author of the parts of the library used. This can be in the form of a textual message at program startup or in documentation (online or textual) provided with the package. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: "This product includes cryptographic software written by Eric Young (eay@cryptsoft.com)" The word 'cryptographic' can be left out if the rouines from the library being used are not cryptographic related :-). 4. If you include any Windows specific code (or a derivative thereof) from the apps directory (application code) you must include an acknowledgement: "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The licence and distribution terms for any publically available version or derivative of this code cannot be changed. i.e. this code cannot simply be copied and put under another distribution licence [including the GNU Public Licence.] * libgit2 - https://github.com/libgit2/libgit2/blob/master/COPYING libgit2 is Copyright (C) the libgit2 contributors, unless otherwise stated. See the AUTHORS file for details. Note that the only valid version of the GPL as far as this project is concerned is _this_ particular version of the license (ie v2, not v2.2 or v3.x or whatever), unless explicitly otherwise stated. ---------------------------------------------------------------------- LINKING EXCEPTION In addition to the permissions in the GNU General Public License, the authors give you unlimited permission to link the compiled version of this library into combinations with other programs, and to distribute those combinations without any restriction coming from the use of this file. (The General Public License restrictions do apply in other respects; for example, they cover modification of the file, and distribution when not linked into a combined executable.) ---------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ---------------------------------------------------------------------- The bundled ZLib code is licensed under the ZLib license: Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu ---------------------------------------------------------------------- The Clar framework is licensed under the MIT license: Copyright (C) 2011 by Vicent Marti Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------- The regex library (deps/regex/) is licensed under the GNU LGPL GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ---------------------------------------------------------------------- * libssh2 - https://www.libssh2.org/license.html Copyright (c) 2004-2007 Sara Golemon Copyright (c) 2005,2006 Mikhail Gusarov Copyright (c) 2006-2007 The Written Word, Inc. Copyright (c) 2007 Eli Fant Copyright (c) 2009 Daniel Stenberg Copyright (C) 2008, 2009 Simon Josefsson All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the copyright holder nor the names of any other contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * libcurl - https://curl.haxx.se/docs/copyright.html COPYRIGHT AND PERMISSION NOTICE Copyright (c) 1996 - 2014, Daniel Stenberg, daniel@haxx.se. All rights reserved. Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. * flate2-rs - https://github.com/alexcrichton/flate2-rs/blob/master/LICENSE-MIT * link-config - https://github.com/alexcrichton/link-config/blob/master/LICENSE-MIT * openssl-static-sys - https://github.com/alexcrichton/openssl-static-sys/blob/master/LICENSE-MIT * toml-rs - https://github.com/alexcrichton/toml-rs/blob/master/LICENSE-MIT * libssh2-static-sys - https://github.com/alexcrichton/libssh2-static-sys/blob/master/LICENSE-MIT * git2-rs - https://github.com/alexcrichton/git2-rs/blob/master/LICENSE-MIT * tar-rs - https://github.com/alexcrichton/tar-rs/blob/master/LICENSE-MIT Copyright (c) 2014 Alex Crichton Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * glob - https://github.com/rust-lang/glob/blob/master/LICENSE-MIT * semver - https://github.com/rust-lang/semver/blob/master/LICENSE-MIT Copyright (c) 2014 The Rust Project Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * rust-url - https://github.com/servo/rust-url/blob/master/LICENSE-MIT Copyright (c) 2006-2009 Graydon Hoare Copyright (c) 2009-2013 Mozilla Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * rust-encoding - https://github.com/lifthrasiir/rust-encoding/blob/master/LICENSE.txt The MIT License (MIT) Copyright (c) 2013, Kang Seonghoon. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * curl-rust - https://github.com/carllerche/curl-rust/blob/master/LICENSE Copyright (c) 2014 Carl Lerche Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * docopt.rs - https://github.com/docopt/docopt.rs/blob/master/UNLICENSE This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to cargo-0.86.0/README.md000064400000000000000000000111521046102023000122710ustar 00000000000000# Cargo Cargo downloads your Rust project’s dependencies and compiles your project. **To start using Cargo**, learn more at [The Cargo Book]. **To start developing Cargo itself**, read the [Cargo Contributor Guide]. [The Cargo Book]: https://doc.rust-lang.org/cargo/ [Cargo Contributor Guide]: https://rust-lang.github.io/cargo/contrib/ > The Cargo binary distributed through with Rust is maintained by the Cargo > team for use by the wider ecosystem. > For all other uses of this crate (as a binary or library) this is maintained > by the Cargo team, primarily for use by Cargo and not intended for external > use (except as a transitive dependency). This crate may make major changes to > its APIs. ## Code Status [![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: ## Compiling from Source ### Requirements Cargo requires the following tools and packages to build: * `cargo` and `rustc` * A C compiler [for your platform](https://github.com/rust-lang/cc-rs#compile-time-requirements) * `git` (to clone this repository) **Other requirements:** The following are optional based on your platform and needs. * `pkg-config` β€” This is used to help locate system packages, such as `libssl` headers/libraries. This may not be required in all cases, such as using vendored OpenSSL, or on Windows. * OpenSSL β€” Only needed on Unix-like systems and only if the `vendored-openssl` Cargo feature is not used. This requires the development headers, which can be obtained from the `libssl-dev` package on Ubuntu or `openssl-devel` with apk or yum or the `openssl` package from Homebrew on macOS. If using the `vendored-openssl` Cargo feature, then a static copy of OpenSSL will be built from source instead of using the system OpenSSL. This may require additional tools such as `perl` and `make`. On macOS, common installation directories from Homebrew, MacPorts, or pkgsrc will be checked. Otherwise it will fall back to `pkg-config`. On Windows, the system-provided Schannel will be used instead. LibreSSL is also supported. **Optional system libraries:** The build will automatically use vendored versions of the following libraries. However, if they are provided by the system and can be found with `pkg-config`, then the system libraries will be used instead: * [`libcurl`](https://curl.se/libcurl/) β€” Used for network transfers. * [`libgit2`](https://libgit2.org/) β€” Used for fetching git dependencies. * [`libssh2`](https://www.libssh2.org/) β€” Used for SSH access to git repositories. * [`libz`](https://zlib.net/) (aka zlib) β€” Used for data compression. It is recommended to use the vendored versions as they are the versions that are tested to work with Cargo. ### Compiling First, you'll want to check out this repository ``` git clone https://github.com/rust-lang/cargo.git cd cargo ``` With `cargo` already installed, you can simply run: ``` cargo build --release ``` ## Adding new subcommands to Cargo Cargo is designed to be extensible with new subcommands without having to modify Cargo itself. See [the Wiki page][third-party-subcommands] for more details and a list of known community-developed subcommands. [third-party-subcommands]: https://github.com/rust-lang/cargo/wiki/Third-party-cargo-subcommands ## Releases Cargo releases coincide with Rust releases. High level release notes are available as part of [Rust's release notes][rel]. Detailed release notes are available in this repo at [CHANGELOG.md]. [rel]: https://github.com/rust-lang/rust/blob/master/RELEASES.md [CHANGELOG.md]: CHANGELOG.md ## Reporting issues Found a bug? We'd love to know about it! Please report all issues on the GitHub [issue tracker][issues]. [issues]: https://github.com/rust-lang/cargo/issues ## Contributing See the **[Cargo Contributor Guide]** for a complete introduction to contributing to Cargo. ## License Cargo is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0). See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) for details. ### Third party software This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (https://www.openssl.org/). In binary form, this product includes software that is licensed under the terms of the GNU General Public License, version 2, with a linking exception, which can be obtained from the [upstream repository][1]. See [LICENSE-THIRD-PARTY](LICENSE-THIRD-PARTY) for details. [1]: https://github.com/libgit2/libgit2 cargo-0.86.0/benches/README.md000064400000000000000000000143601046102023000137040ustar 00000000000000# Cargo Benchmarking This directory contains some benchmarks for cargo itself. This uses [Criterion] for running benchmarks. It is recommended to read the Criterion book to get familiar with how to use it. A basic usage would be: ```sh cd benches/benchsuite cargo bench ``` However, running all benchmarks would take many minutes, so in most cases it is recommended to just run the benchmarks relevant to whatever section of code you are working on. ## Benchmarks There are several different kinds of benchmarks in the `benchsuite/benches` directory: * `global_cache_tracker` β€” Benchmarks saving data to the global cache tracker database using samples of real-world data. * `resolve` β€” Benchmarks the resolver against simulations of real-world workspaces. * `workspace_initialization` β€” Benchmarks initialization of a workspace against simulations of real-world workspaces. ### Resolve benchmarks The resolve benchmarks involve downloading the index and benchmarking against some real-world and artificial workspaces located in the [`workspaces`](workspaces) directory. **Beware** that the initial download can take a fairly long amount of time (10 minutes minimum on an extremely fast network) and require significant disk space (around 4.5GB). The benchsuite will cache the index and downloaded crates in the `target/tmp/bench` directory, so subsequent runs should be faster. You can (and probably should) specify individual benchmarks to run to narrow it down to a more reasonable set, for example: ```sh cargo bench -p benchsuite --bench resolve -- resolve_ws/rust ``` This will only download what's necessary for the rust-lang/rust workspace (which is about 330MB) and run the benchmarks against it (which should take about a minute). To get a list of all the benchmarks, run: ```sh cargo bench -p benchsuite --bench resolve -- --list ``` ### Global cache tracker The `global_cache_tracker` benchmark tests saving data to the global cache tracker database using samples of real-world data. This benchmark should run relatively quickly. The real-world data is based on a capture of my personal development environment which has accumulated a large cache. So it is somewhat arbitrary, but hopefully representative of a challenging environment. Capturing of the data is done with the `capture-last-use` binary, which you can run if you need to rebuild the database. Just try to run on a system with a relatively full cache in your cargo home directory. ```sh cargo bench -p benchsuite --bench global_cache_tracker ``` ## Viewing reports The benchmarks display some basic information on the command-line while they run. A more complete HTML report can be found at `target/criterion/report/index.html` which contains links to all the benchmarks and summaries. Check out the Criterion book for more information on the extensive reporting capabilities. ## Comparing implementations Knowing the raw numbers can be useful, but what you're probably most interested in is checking if your changes help or hurt performance. To do that, you need to run the benchmarks multiple times. First, run the benchmarks from the master branch of cargo without any changes. To make it easier to compare, Criterion supports naming the baseline so that you can iterate on your code and compare against it multiple times. ```sh cargo bench -- --save-baseline master ``` Now you can switch to your branch with your changes. Re-run the benchmarks compared against the baseline: ```sh cargo bench -- --baseline master ``` You can repeat the last command as you make changes to re-compare against the master baseline. Without the baseline arguments, it will compare against the last run, which can be helpful for comparing incremental changes. ## Capturing workspaces The [`workspaces`](workspaces) directory contains several workspaces that provide a variety of different workspaces intended to provide good exercises for benchmarks. Some of these are shadow copies of real-world workspaces. This is done with the tool in the [`capture`](capture) directory. The tool will copy `Cargo.lock` and all of the `Cargo.toml` files of the workspace members. It also adds an empty `lib.rs` so Cargo won't error, and sanitizes the `Cargo.toml` to some degree, removing unwanted elements. Finally, it compresses everything into a `tgz`. To run it, do: ```sh cd benches/capture cargo run -- /path/to/workspace/foo ``` The resolver benchmarks also support the `CARGO_BENCH_WORKSPACES` environment variable, which you can point to a Cargo workspace if you want to try different workspaces. For example: ```sh CARGO_BENCH_WORKSPACES=/path/to/some/workspace cargo bench ``` ## TODO This is just a start for establishing a benchmarking suite for Cargo. There's a lot that can be added. Some ideas: * Fix the benchmarks so that the resolver setup doesn't run every iteration. * Benchmark [this section of code](https://github.com/rust-lang/cargo/blob/a821e2cb24d7b6013433f069ab3bad53d160e100/src/cargo/ops/cargo_compile.rs#L470-L549) which builds the unit graph. The performance there isn't great, and it would be good to keep an eye on it. Unfortunately that would mean doing a bit of work to make `generate_targets` publicly visible, and there is a bunch of setup code that may need to be duplicated. * Benchmark the fingerprinting code. * Benchmark running the `cargo` executable. Running something like `cargo build` or `cargo check` with everything "Fresh" would be a good end-to-end exercise to measure the overall overhead of Cargo. * Benchmark pathological resolver scenarios. There might be some cases where the resolver can spend a significant amount of time. It would be good to identify if these exist, and create benchmarks for them. This may require creating an artificial index, similar to the `resolver-tests`. This should also consider scenarios where the resolver ultimately fails. * Benchmark without `Cargo.lock`. I'm not sure if this is particularly valuable, since we are mostly concerned with incremental builds which will always have a lock file. * Benchmark just [`resolve::resolve`](https://github.com/rust-lang/cargo/blob/a821e2cb24d7b6013433f069ab3bad53d160e100/src/cargo/core/resolver/mod.rs#L122) without anything else. This can help focus on just the resolver. [Criterion]: https://bheisler.github.io/criterion.rs/book/ cargo-0.86.0/benches/workspaces/cargo.tgz000064400000000000000000000233571046102023000164350ustar 00000000000000‹cargo.tarν}ko#K’έ|ξ_!h?ΨΖ½ΤΝχc16fΌ»€Χ끍Α|1fB>"%NS€–€ϊqύο{’ψ_Eͺϋ–ϊΞΒβL_U%‹ΕŠΜȈs""“%Νοf?έώsϋ±,nΗΣ6»ωλb6ύΝ`/—3ζd;Ώ”8φΚy㌲8–΄ύζ;ΌžΛ4ΏΊϊΝ§―χξκκϊnΌΌώϋ+>ΔΙβ>Iœ]›$«bkΩ‡”p5)EV4“m6…¬nΩ₯λ»Ο]]ΟιaΆ$ώθύrωΈψϋŸ~Β}οŸςM™=ό4G?&izχS§j7ό•ψάΏρ‡―ΣςŠΗϊΗΏ~χoο~σφϊ.―n4~ϊ‡nL–³‡Ιk|Η…ωo₯6σ_xkάΫό―?η§ρ€Ž*=΄΄ŒiqΣ&iIκύ»J-=M–£Fiω4§ΕΥ½ji² w; Ύώy2ΞΧοί}€ωb<›’ιZވ}ύξέ©{£³Οάxη&βΖά(ΗwΩύόϋwiϊε~φiύ5ΧοrωeuΉΊ~—Ώ,i1ώ™Άο–Izδu£%_Pζ³Ε"Sz=-Η“ΕκƒνOσΙhρe±ωbƒ6š~ΌΜξξhΎj|Γ6žΠrό@λ―Ό‰Χο`ΙΤκTκιV #ΎγΊΥάH4Nfyuω>χτyύ]8žmξgqςτ¦›oPθH\<Ύ›Ξζ΄y6†‡ΡΌtBΪυKš/g³D²kόλ,/hώqσόθ|Ω$ύόε*Ώ―nΔͺ΅Πd²Ϋ4ΞeΫ±8ι€Ϊv‘T7}„ώΩ< ‡r?_=Έd ˜>=ά–Η§Εv\i>ώxβΣRυ|ώ–ΡΑMζιΣνΗ4y:υΗ£ϊUF^c’ΰγG'τŠ΄=$˜νm}Ύ`υύwY<=>ΞζΛsχY_ΒwΪ<4‹1ύ2ϊ”ζSΨ§/p‡n”a΅>ŽΆβΟΧGcίuΥ΄²E­•ͺ»p}όΣζM\χξΟ0sΖ.=-οgσU―_Ίͺικ_ςη«ί~ϊRrρ»»‡4ž0€ώoΧ?^]ΈMώΜθ=]ύφ~i&“ξt{Ιο'π50—ϋ%:ύ· §Ώγ”uΣκBt¦N[Ή{:HψγUΊZ?ΩόRbYahώ|σ—ιυ»:+O0αiσ± τΗ‹›ωΊ{αLλxs…μ9Ψι=ςmw>³‘Ά“1Γ’{χό§«ύΗ«ίγ9ξiΤYΠiZωΗυΝη”κͺατϋόΓ?έ-ώΛυΝ>"iŸ*{’΅sXΉΛŸ»AszΜ³œ΄\T·ϋ4­Β%|_Ύw€ψώβ­ΫΖSώ"j|2]nΨΧ?-ψψq>+΄X@AwΞ–χά{‹υM7‹/ΣrΏ>Ζmi>ŸΝΧΗόˆλΓ2›¦ΛC‹ γςΖώ£πΏΕΌόχˆ ϋ+π?~σ?aήψίw“hr°¨ΐ₯ρwΪΖ΄7φmόΏfό:rq·ό h€Sž«3Ÿύ•Κςκι#M|ζ‹€ρŸWπΨψΞ-˜˜5€•½Ϊ¨δΝKΗ%zτ8‡ Ύ‹μ|ν/Δwϋ•ηP^αλν?ζΏPoσΧgN5Έ4ώ֍Ώ‘^Ώχ°' ψ$π‚ΩΥ'ϊΪwυΫΏvηΏƒUX¦ιψseό4…Ώbf±ŸŽ+nΜ;«ΥβiΌ€sFόœ}ό†|7°π‹MΉψΫεBηη0ΰμΏιrBoσWu,lpaό₯tζhό|Λwό]»Ρζ(γu*ίυœΪκΙD%8‡C³t[ΗσΫ4™lSBΟθ핇ι~ˆΓΜ^JεdΚγT(ωζ¦'Œ|!a²ύά*Y2|Zβ—EΤeθef/ ωΪ―φΫ`ϊ_ψfνΰ[όΏ5ώΝώ:γΟFmЊ Kώί¨#―ΕϋΫπeώεq9έ§Εύ¦~Ež¬ƒy.ia|\|"χjJnΒQωΘNd΄)Όΰ―w½υϋ%SΩ«£Π«Š…‚“/Έ0&Miφ΄ΈZ[Ε+κΈzZP½Κ_V7»ωΞόt…<~13•9ΞΥρ팻κ/Χ@D³Ε_3—e6Η@͞¦΅γορb|ŸΏ•βΦίn@ΐAn0Ύ8·ϊ0^i#«ϋ%‰Υ2›.fΫtκs²τ0kɚόf'ƒfΏ%ώ+τ›ύώγΏ)έΆ ψbώΟΘΓρW^Ύί†ί²š3›'hϋ–“‹_R¦φ‹™μΙυ’‹L§Kš§²dA>Αg^m Έ΄ι[)πsωγ/τΞ«‚Ι_gώZς φ_9ϋ6ΏŸύ_™ϋΙ¬|xο8?ώήx{jύ‡|οπϊ»«?ݏa™Lα/,μμγ΄i2ωrυ»;.Χ‡MΨα9οώξκŸ—|ιtΆμ,(¬zνΜιCš>₯ΙUg7§w7;ΖLÈo­ψϋ­©LuBσλΓΊΗΕμ ~†ζt7^,η_~8o=7v{Δ ώ3œΦ=•‹§ΎESφΫ S‚Ο’„ΜUΧZ¨ΆΖZΙ9HK‘PΝFΆVJ¦lr³Q'm]χ<όύl"”γςαΐpϋ.;¨’΄/­ZςΞϊT“±ΝUΕX’υ!Ψ ²-VΕZ|h©II…NL©kΧοv0;Πw]ύhΉŸ_ψξ}ˆΣΕψ–£ο‡΄q΅΄bHωˆLΜ©Ή’τ9XR¨Qηf”¨Yι [ΚΖU- ͺ$„ΞFTΫ*EσIωVDπœ| vŽИ…s¬}Π΄ΰΙj‹V*ΆZ1N! U\¨₯yL1Y@ §]•J‘RRFΩ§σyϊς‘Κaεςΰ3HιμT+ΞV dΘ7«¬6-[•EΣT…αNϋme$j*€ ‚.δΎη_.Ώ<»Ί‘Cw~YΗL2x/ͺ”FΙR³Μ1YT«nΪSΤ"ͺ’q蝄‚…€e„r…“šuI1^ŽRfνΊΊζΈVwpQγ`^K»;R99°ΠQhΙ*F*x_­+%΄FUQ;Μ!Wth€*y!¬Ρδ”o!Α§žΛγe›€»ΕΑσλΑ5.SΣ‘+.ͺAΡ$_[ΥΊ˜f[’ŠΒB ΠL«E†*\ΛR`e8σόιqρΥΝπΦ }/ŒΖΌ1bjΤ€α0FΉ%£LVΉ„\]¬Qee£S΅TRΈ@Η”Ρϋκ€Ξ-Ώ ιι‘_Ή2žϊx>ω‘‡NΡE ¦Π€Α˜Ψ$δδάή”Ϊgγ½YΦGΤdLM― Ÿ>)ΫN‚Έ›G[ΟΤ=2}­qI:#ύzνηn?ΈΨ@E»” ¬›ƒXIB3­Μθ‘|lΦy‘Ό’B5λ-μŠ'_‚u©6ψγέμ_„r’ΏΦž‹ϋ§³’|°ν>9¨F}nΪΙt4nb΅ΟΝ]ŒΉ;€ΗΥΑ–άΞφVΣΪ@ϋ·Ό^΄;ΩYK»Šώrγ&‡°:ι’ζ«ΓΥzšξ˜‹ Ά£νΝΉδ ;ΰ€C·ˆlu6[ίνyνjzsΫjqθκΧώ6ε έΩ6i±²κJΉY$»oςw–ΖΞgw‡*ΌY۝¬–ΐn‹Υύ#+«Ζ£%e݌8±8vϋFξŽWλΧ‡Όzp{΄Y%»ΣΒq›ΥιNΊeΥp΄PΆkeZύ]ηaΦ'λ:ΥΩμa%ΩήβΨ½–ΟγΥClFuΒy‘'½ΌπυΔ΄ΩτΔΩ{ξΦ‚Χ.\ϊΰ™²‡σσψΜτάΞΓΎσΩΪέh܎δƒγ ΰ=2ZG@qB.Uθ‚©‘ Šrφ&[0@jΉω(Α«+†μ}S”]Ψ>ξӚ Φ}xP ΈυΊαƒX«T5ˆ–πW–bZΔƒ+<Έ‰Axe­ϊ†lBυL ίχχ0ΎΆΣ‹ρΓZy?/?ΝΧϋΨψ‚0ή>tοφσμαa6]MΊ#89Έ2 ΐ’`ƒΛIΩ$ΙT'Kd"€ΎBoηtΫΪ†7RV-Ș.ρ';lW‚΅_~¬έ•―-―lTAσ ŸΙλŠIi}@Τ5;V@_ΐ2„;S*E₯ρΝ ξΣ ²Άs½2ξ›ΤΓTόΠάS€I%2ΚQ ZZ[AΩ€(˜.Kγ45 ζV²1…Hd₯ fnΐ»F$§z†tOˆg΄υ5’Ÿα08u₯€”ΜVεΙ‘uΖ„wi¨o0T.‰Z(ΊVWͺς):·e_°δόœκ`™‡πp‹Ξ;ω9Ψ\K‹εCPƒλSΊF…Π£πy±©Τ*˜~,€YNVY*tΈ‘T©Ζ˜«χΝa6ΑCΘtZŸVΞμŒxϋΤζPkμΠv0¨Š”…|SE·DΝ‡’ƒTΖw‘N‘ktAρgͺ€R±su(¦ζσB"ΐ^‘ŸΦaYΜΠaΉΌ—Ž£œ­F―L¨2&λ ώYΚΦι€›*λΰΘH€—¬»rΎΦZEΓΏƒ9>uΘ·."9Φώ£­Jβΐ½R9Ώ5­ ‡Ήš„7pUY!…C[5ΐz& ˜ΣΔ†ΒR(ο}…%‰9žξ…]ζ½ΕΐkαGσY¦½–Ν₯‹rŸ¦SZσYω@kVρ’Ύ:a[͍‰?tοω?ΌŸ!ь‰]“ΰ@Πkθ (|AX$ηJ.7 αYLu\&υMΪ/ΟXmQ|;™•ΤW'΄)‘ιλΩήkΟΨW(]Π §Ρzς² “”€ξH2L_°π„ΪͺπR*%ΐi«ΛA³«ι ΊljV»—Ήε€ζΫgωάφyΆΈ―k†Έ°ŽΚύΣτΓΊXk[8ΚΩ n»Η>ΣaΫς‘γ]ο‡Ζ<’q¨N„Ό‘ƒB&y£Λ\{ ΄E†ΐ<ΐ.R‚{£tΊΣΦΡτ3ςΝ«γΘ쁂/,Δ`­€¦,μ ΐΎΐ\ LY`A‹ΗEΣ[^ `―jŸ±|.Υ9*z:I—š² Œ=Ζδ4τŽc«Ϊ&Η…Μ€ρΑ)œ/ͺΊβU1]f²XW‡ζΏνΪ‰}m†_t’€Ό-£²/mͺ)Ο%Ν )ΐK`$ΰ$¦Ιͺ6 “f¬…ΠΒ⌻ξ‘«}mΔ4ϘB²ΚΚλ-\ΦΒΫ0NœB5ΚVA>aέ1}‡ DPπΣ™€hΦφ=?ΠQ^ ν+ )?%ι”Jί΄’Τx?Πκt Θeε©5§Bj¦Κμ\†}T›λϊmΌΰ`‚(̐^ϊΥ\ΐΓγιω‘―+>ΧE₯ ¨mM%ΐΪΪΐ …―°πΏUI@Γ—¦"‹ϋoΙCΎον©έάζ‘5ρθ*cο+N7b4s†Μ:€’4‘r”^€Μΐ τTˆX2ΡKUβ«SΡύσσQΟΘΥΟ8 ;WΘm1L,U^7R2uΝ d}ihmŒ7¦I&»JTtI¬ η^Τ1_)ϋμξuνK-xQΞδ ˜‘•­h’@8Πξθ,hR6Εiΰ‘‚‡Ch„—ATν°ίTΖ΄‘'‡s{π: `“p’šϊ—m`~pIIfςΞ FΎΥgθ>ϋY1ΔβB ]Ίρτγ―ΘΑ>«>@«αD /ή0Ž>(8Qn«k VΑ«“ΐ–WΩͺ„ͺ0U³ΌοιwςŸG•1C@δτ-Αe ί•Σci„βtaI°<π?ΊΊm‘ΦS[˜\Ί ™Συc«υΩ]ΡρzέbΏ’rάnπ₯g±Α d‘l©)xל£ft’ ΄QR.±™R¨iΓUοBHΐ ”3&•!%Ώ)€΄]Όs`‡G&16PηΌ,\ϋΞ P#Wv­k­qώ£(Ό‡Η„±tΎ6ιdσΐEϊ+VͺφΘ:›Ί=]Γπ‹θ’j%ε9“₯·A¨ˆΡŠŽΘip  Μ"TΩΓVxΰΦ N 2MΆ9`۞)·^\uΙϊι ΑΰεR=&Ό·Εӌ»ζ^rU'π‘ζ1Œ4:Ϊ"2&„φt‰σ6!pI#7eŒGԜ‹›†%5ΆTjφ\+r·¦ΑΑ+Ϋ †` Wd¨o7.—ΰ* ₯5썬3ιršo'ΓΉ_N±_»ΈΥΛc sΎ“ΦιΑC7΄ωβ‘θϊJD(ΉTΠcΆœπwž—†jϊΦΘIQ’ςΝj κ€Λ―Ο ±8Œ^I w#~`€&'CΗSVλζΐ)]išŠTVΤΎ”’¦ƒgŒό!Θ―΅ύπΟ…up!πωQf‘©˜o«b€Tpͺ^[Ρr<lΨ[NξׁπUF‘om“δDρe§b,Ο€[*΄ΆΐΫY’‚ΣΞ1•’π 9AP―%˜n*€}–υ΄Μϋ‹¦{ΔάMΛšΘ'6p5(ώ”­Θ$Ισ πΨ9}TΙΚ Β›\l2ڛ欨ϊRΡϊ4[Ρ =D4/Gol-μۚΎ£WΕΦ)WŠlΌi™’6₯~TΈr€„«πf 0„8ο©ΉrξάTŒS ηχ›4Τ}Rn½»k»/ηϋas“C0x0ΞΨE§“hI+eU&aV ¨,v2§Έ ±p ΄8₯ 9‘έAœpΊ;vάΑιN8+ψq¦Χ.vΉ’UΡ΅ΒΖV€K~"€:‘©…8Z³@z"΅+ŒŽjr5ΡW ΰ†0K^j!/όπQ²j`ϋ9s0ΐdπeP,ΈHri₯՜“~C§gιsMθω!Ί/―—ΥJ‚―ΰxŒ¨˜ŒΙΑΰCdH2#DΥ\2{ΕUX nΏ6}|_§ˆ›Μρkγ€Π—’ΰ6xK§¨#―jσ d]t)Μ’]ςπ,p(-'/ΑE„0E]εΓϋDέ[¨ρκθ-π~u::ΐ οPW9Ρ₯UΩ…"ŒΧΪ«ˆYgxύ¦ ΉVΝuR-΄v‰7χJywP‚&Ρ-ƒo¨&| NEm#g1UΛΑ¨fw©ΰλU >'¬qI¬j•u^Γ8ω²ςΘ£ _¦Λτω‚πΟϋDΥFΏ ”’‚&g_QDΦHΟr?€6k_mi²dga]=:γ|}NŒ΅°‡φU ½RŠΝψP\~Rΐν”i­ΐ `JΎe`@RjφGΛδ€lsj.› 1χ ±·ΏΜkB―ͺ„‚9 ‹‘4W3Ux9ΕΑ{ͺ©ŠfE »"1.d4L’₯zΜθ₯(άΙ]˜^{s”V<BKI‚wR+ Δ «-i" 3jƒ„cԊ“; ώ…“I&hβuΏ,ΌqΤ‘Ύ >g8θ_Ξ£λM3`<±ḍs ŠΩ„βP%WfŒ±θζ]τΰλιF›’²ž- ϊFςΛΣΡΐΩΑkξ`ΰe52‚xπΊ2°£ζNPR―0TΡ‹λFDΑεΦgζΨ…β½ν²τW/wM€;1‘ 9θ*/’5ΎQ4ఞb]ΧU–θάΑ6ΌQcττφE[^²+λΫŽ6₯:Ν™WrΚ†sY€ΦπTAΆ΄I•ΣσΕ5_’qΌ>-‚> Qh s7ωMϋ«­ή>Zi§·’RUπΫnΛd₯q <¨$NO§[ldš`ω€΄­χ ΜΒVηr…£“Ί_ΆΫυ―œqsΥλKŠyVΨ΄gΘi(πVΞKS² ”TΦͺ"•R&*γ,680q‰A~Ac‘ι¬ι—ι%Ρ7› žΨoΨE:E_u¬pΡ₯ ΞΘK`œŸβvd*Πk_8$μjί¬Ώ+grdn‡.ΝE¬Ž ·0΄6W–*+LΕψzC|WΡ”Ξ– ΩQΑΉ^γέΑιΚ^;H —χγ ήέοpD‡v‘Ζζμΐύ`c’TΞ•βƒπcηT‹σf8@=-U_»’`ΓΡ-`πl„ ¦―†d―ϊΰ -ƒ؊JΑk“O\5ͺmη2<@Ώ |ΦVN’¨½ˆLξ‹²΅Βƒͺ ΏB+ΐ/nΌΩ·εΟ=ΈO4rΕg’`ΆZEƒͺYήΎœ˜Ξ{ΡDWAΨn.|΄•ξ|„ρ’“<ή–τΥΧ‘KΈΜHΥVΙΐU} 4Θι³ΰ₯œœ/4 χŽD—T2EΌs=ςγ’Ξ Ι{ϊƊV“ΌΘ«ΗŠ…w°ώ ΞJπWžLπ`ΈΠS`"ΜJŸ€`jeβDw_ξš}ΕΡΖC[ɏW‡wΑεN3―VQ1c`dΩγ‹**MŒ‚ό_ζ}ΓUΒυμ…Ωο^”ƒα­S–ΕY+yνu­f?ηΚ;Yδ ‹zκrςΩ[Sk‚wΰεͺκΰŒΐ8'{ΊβxocΥσ•BΫRw%Υ―±Ad*²€K)Z‰8ƒΖ™'€κο¬-³ΔόT1at„?¨Α ΚJ½|/Ξ˜ήΤεΔvΉ— Τσή‡υ΄ƒ8C €΅‚7K& Ε%‘ΐ1sHžν/xнΆN‚z§Ϊ¬!“ŠmζΫ‰Ωv£ΡWuͺ0φέ^‰Χ4+ ΰ½ΦΌK(¨&ΠDα ͺ8ξc`œ©πD‘7Ωgͺ›­Qϋ€ά]}φΪΕс5W€ψΫZ‚@@Ό–7ψ o[L YΣΒ&Ρ€u“8£ΆŒΡμYzΎ[=Υ'δxzτK"ς ηZΠ]I-oweΠQΟωαΪ•8gιyρ―Ξx?0šUς+kšŽ²ŽΤ­ώΆ3Ω‹‹Bn;±CχΐΏΑ‘ΌΑ?ψI^ήη#π­l`έΠM.£ƒ KBY΅Š$§DλZπ`c}Z ήƒϋ0’:Έ_ΥόK)‘7δυx\c$ΈΥ~I—ζψΪi*&!ΑΝΕ€6λTΐ΄Σ·°« ΄=˜cΓ§’²< I9ΛΫ9ήa“ͺ‘Ρ-Zϋ耴>’w¦ΰO…λ€vR*^φL}³·όχ0sθ_Kοšι'ΆˆΊΐ>ΊΦ:kQ…σΥH 8Η{ˆ¬p‘ΆžŒ Ό£¬εφW,Ώzΰ­‚EΏ‚Sqˆ°φMŽm—§g¦ΏŠ`Ι$m‘m:j.·¬Ι-ž3 ύ ·ο^{‰„¦ΚΏΨΐͺr•;RΪI―Έμ$¦Ÿl‚ΓXCΝ*r™¨εͺθγ½Ύ0b I5 νJΙ x@Aΐ¦ij$9ώ₯Λ\ JZΓ&ΈT΄³πΚN—+|†§κα`υ žΈΐG³χΟ.0eœœΌηe“κdαZk²$ ‡ΰ€X5ΧͺϋιΫ=mo±ξ‡x+ƒΏyo§e iΎ Wί‰Υf{<Όeΐ‹ΐ„―“ςAςΛ'τ½£+ψs3z=ΝΧ8yI/Μ³λ½Π“ΐ € γhU?Ž™ ΏάθP7:š‘?∞PtœhΒ˜ΩΫ==ξ< Xαέόα!Όύ€;οa₯ 9‚_>€›]€–ζoGψτnΰα—Oπ1¦~ΛgΩωšάΜϊ*£gTd&ΰ'™ε«hYΦΓ§£›ΉH3~‡«χd Όœ|² γš7ύcEˆTo¬νXŸσšωAύIή7£ΰςΎ@IίΤkvŽςώίγχi{Ύ›‘πίbxŽ4Ύ&ψXιΐόοπ£ŸεΘ^[πν|ˆoθχpκ30ρ]Enˆ·ψπιr=~Šθδ)¨>hτhΰˆ+ΣΔ[ώα1IGΓπ‡•φZΛ©Φ?Νβ-ΏλyΧπΈπOz_V;‡^Νf»ΡλΏύϊ‰λ›nΕ–­)Ωi­‘Bΰik/y»d1­ΘΦόώ@ε«N X ‡  ¬» σΛ'ψ/Ό;7€3dΙΠΊtΝΧ€ΕψΚa „ D1|~άp•^ν1Υ4ωιϊΫoP?΄>½bΤ/ŸŽΰδ^tƒ“‘ρxβΎ3*g\η(6γ'ΌΊŸy¨Ž…ΠΒKόK‘gρΈŠ`y`•π9Αžm)LΗbΖv]šΦΣί€>άυV›g–>| Dώ+ΠϋτfcΩZώO½ώψα_/ω?¦ψjP@Λϊ;Ϋ5£₯νEθ7}‹<3ƒ +D£cΣndΘΗΠ0MΘH)>΄--MΡ¨› =‡½φ&|-άp€Ÿ$‹γ ˜kΣθ>y—k:6h[yΰΙA@6ξΡ\ό.^©‹·Œ.Nΐ39c~‰Ψ˜~BήξbΜZΜ)Τ^•gιθ@¦oόβΗΠ"N€–Οmςηφρ³ΕΡΙζz-Ў. JGωT~Pt@μ*Ήßγοπ龝 *5CΌ°3Ρϋω³ρσ3λυΉ_ΩΟ›Ύ.&\ztŽ,ρ½”39jU=J.AxA£ΕSΡœ6γΣ[Θ9Ύ4΅σCFυx‘ΉŽz8ΩΚ ΎΒg ηldG«β αhβΕ9ƒΰα‹ͺ%¦ΝΠpΑ‚π&δQ~}ΕΘ?GΠf‰τXƒζδΣ―;Ω°ΗΜV㣫Ž'κ~ΘP"žΰκ·ΙΐLΕc\}Ÿ9VuΘγFM_:xτ#Ψ=:ΆΡ«›\ ©ΚwζΨ>Β›Oέx}Wƒe%#py‹ ΎΏΎ’οŽ>R8'ϊϊ€,ΌκGIΝ#ψ΄ϊ}JΤάύ^΅»υY58Ι-(΄$ΥŠwT«νDiό―Δ μγ΅·Ϊώ›yύsA;άlYϋzλλΏ΅Χ[½ώΛ‹Κum%ωažΉΖ*M !†‡ΨΨΘ7Ϋέν„9ΐ~Q…Πw(U5ΪλjŽ„ξh3δ©Ω 9±χ’»ο‘γBdΌgˆV"| Σ– cΐψok9:ώ;oώΗ!ŽŸ}`’—J«!(°-ώ—^½Χλ??ώΫ ύE Y5q¬9­ŒΉ*§0Ί†ΕŸ"Χ²μ­:E/·?Ό·˜Υζ2Φ=RωΖρΣ~δ&oζ)NB7㦠֎й<ΔΪΡ)ͺ4 βx[‘¬ΖΏbΙjδ’υ‘sVb]2ΛN”–P@ύΏ³m^β$‰_ΝηΔ½œΥeΆ­?YσzώΗv§υ ϊΏsΆ_Ο$ΌiΣΈ«―u‹ΈΔ7ͺΏτύ+Λλ“΅΅υχ?ΩϊηŸι!ΎΒϋhαCU mύχ;6ώί½ώΣΛŽ‘ΦQκ·X3< Ž,LI—οœΛΏγž£ΨJ}ƒc;AΏE Oόw­ύ?sϋrηΖψρίν~ΗΖŸAώσάz>vΐY[’Β₯Θg禨$κ^@†Ag‘Kk‰Όt΄[X™κβκW_›ΜΊ;i½†ξκΰ/ΎψΏauΓ‰ΨY£:ύΔΜb“λΐ$s\ό~ουΓ΄Rθ†L€{4_ψ!˜)Θekθ YՏ\ƒ’Šn6oC\Ε­’ ›?Cš!\ΰ>J²k·*ΌCο%ijάί^Ε¨¬œχ£…€%τ<ρί½₯υ¬λΣvPl u΄ςΏμοn­σύάΤΥlUΰ·œjPt΅„f•W”IlJ\`dvRƒwέB3ΉF™ξΘ[ΈΚwƒXΖΕ'Η8/δ;!‘“Γ @ύΏίμ΄ό_Μϊη)Χ=a@+˞YύΖΪλυ_‚ώOΟMDΦœ;uv7ş¬χΙ ΨΫ­υΕ<Ίx‘/<βœi,΄±φ¦&2O>¬ν₯ή₯5<8φΌβτ9‚ϊ]Υ¦kΈ%.»Λ>ͺ]ψ)Η€žΡ νyΊξœ§"3θ;κ”μΏ|Ίnlώlp‡x’κN8ΗΞΜΡt1υλX‚Ξ6 Πψqωήɞ0 ‡ώίΫ[­³ώs§Whμυ‚mϊίήΠυ6ͺ Τλ?ώWμKζ ֚I’κ¬!&:Οxt˜ΡcΞzόΜ$άuΌΨCύ˜eΨΔw9ς-©Ψ%ϋ@€>ϊΏΣώίιΧΏ —_/‘fθ^ϊΪυ?ΓΆΫmtώΗ"μzύs4ΰ[π΅ϋIΓ`?išΎ…‡80/P?σ5ώ}Ώ’‚}MμlXΰ.M4xwςΏw OύΧVηΞ°ώL›’€VύΟƝ­ΖΛЍaœ΄MΩΝΖμLeόξ-°a f`kͺϋΡΝ ό£^σΗwŸ€Ω5’Ζζ–2δ»qΟp'k’B«]ή™όWQ§ώckλόΏ%¬?³…ψ‚:α‚6ύΏΩΣύmk£νΉό₯Ξ‘ςmςόsk*&ρυ7¨[yΰh\ΎwΒ R,o"4ΑGtπBπΙάΨӍάΕ… –£Γ3?Λ‘]pAwύoC›Pχ[Βϊg‰₯GXό{θ~™υί1ώ{­νμΥκΈO–7ϋΒ‘4υˆ-ΠD» CνNw%6cδϋ.2ُh)ώο>ίW›°‡ό_kώ— εώA{g~1Κ֟RφŸe3φΏmο΄ώ_„W’FΠtͺ­Οl½‘_½σŒˆχ»₯Νθgς―R΅•UN«­ͺoήώ£δΏΒ֟}ύΏΆmλϊŸΙ֞ާ¬ηg‡υw¬Γc[{m-BSω_η$Žβ’λη έΓ3Ί†„+<dc> PόΣx~θeHyCΆΏ‘μk΄ρ3ρ5sKΘ_έΰεθγN36&~’ΜBλz&Ϋ…™Έι’ˆθΘ^Λκ1‚6"&O-=Ύ¬Θž.ύB»7 •h“ η Ψ$|DυΓZf17eΡ•`ΊΥ~όσͺΣ΅—©d#S~' ώm€dzA˜H²¦n>xmxH’>oH·¦T»š•`τέ’7W?8²W†^MΞa:5΅9‚λ*_CeγxωΟ ‰›σΌρ?©UυΞy›υΜω¦Ξ‚sAP,ΒΜu ™’ΚlE@Žν°J%‚Ε}O{υš“_ͺΕh‹Ω'ΘγήjΩ8Υ(\q θΑU€qŠ+6γ9GΠjE±₯¨;f~Sψ_΅ωΧΛώ³΄ύ7ΟϊΓη‘y•‚-λΏΫΪ;–w§λΏa ϊ?΅™…ΌΖ 5K‘Λφr=δ1Β­•3‰=y—k‘sΌΡΙ ŸiœΕOP―Ζ©ηe•’³Γέ‘Θ^”bΓٜnx {–lεSΣ’­on—bνΆ+Όχ°D7ΫΗΗv… 9J―)f—»Wԁ,’‡λ³ΈGgŽ’©£ή»9;‚!Ь„Τ‡O5™’φEθFπŒ!|@«|Α‚ψΰθyA‰e©Θ\‘[œέ\ήnίΗ$²ΗCnαΏ Ώξρ―"5α>τϊψlν?»VⱂsqΈ•Λό!Ω'nYς^U&y$²Δ.gΎ—?~ߜO^p,πΰΥ›y;QΙΫ!ƒŠ€‚‰_έ$¬ Όoδ+ φCP΄?MP9dRK7v―Κ)p3`ΛςaaOοθ‰ς Ψ¬‡β'Ου玷(wξΌ|NΡ7Ή_φ^nΦ“΅εψFΨ›(T l@ςfΔ~ΐZ&Sy|ΧςεΊ¨‘Ž9mτψ|³θpΡKœο^‰^^ά}³#w”g'ϊUΑ¨qL_8šmŸό‰Α;Ε9RΉg,Eis&†ή7‹m¬^μ\Վξ_« ΉzsT#πy€άbŽ„ΒF΅[λnκ~»ώ­&ϋ_•#¨WKΫΣη–υJsΪςvLύ—eο5γΟGŠχ £Δ]―q B:uμioΧ£ ύŠϊι k £ͺ{Ž’Φ9ύ™pΠΰπB¨–Γί³AγŒrή%b όWκΩλώίSζξdεΉRρŸ-Γb9ΊώŐKK{φαΣΙυƒJ N0ˆΕ჋μμΓIœ”#‡‹ β;'δxΞ„<ύΉ¦“κ™Ρ aš(Ξ μπ8EηkX>ΎΔςΫ †·Gƒ„7YvΏi B3γ2AA$’B*w4 xΙ~2™~΄Γ»Ίμnm“ZΞCΝ―†uΎΥ]ηυ Ψ-μŒ”%{'άΰ+ήο»ΰ e§ΗMŠ‘ΧβΤxYϊ Κ#Vάc3Rn?zŽ――ΨΑYv΄ΰ{lϊF„_HB—υΣYΌ|@†ΰKV† 0 ί²Π±| Mβ•½ GlίSΞeg!Iι 3*‘©%{ξϜ;HέΘήΜδT_ŸκVv43Bχx Ύ(,kVΕNE$’υ) ±•™gπ =\ΐρkγK$$”7@Εz§I…μ½πR,ΖH>EBϋδ“:χΝ£-ΘG•Wη-Α>–η%ΏšΎ=xXΌ™JΥΪ>UMγRsέΕ!Κq>ƒΰy«θ¬˝΅ώ!΅DŸΩο‹šνVf}πΥ'IίΏ%šs1ρ€κަTcˆ€/1ός \έ·=ˆs‘©wƒΙGΞƒYΜf~φrΎ–-YΝί՟κκώΠΗqΨδw¨ήcSNόαΓB”ύ―<χ·§ΗΪ8:w²υοn’*εsΆ,“£ωŸfρπ½=ŽŒ[¦!SΞyΐΝs’ί$m½*€Κ9ΐ”“^ΰϊa‘M±ξΓΨ’€Tώ|FU%R7ΠΨ 2°L1Πλd δμρ•5ν/ΠKcΚ±ωœφΟ€h«AI<¨eύΩ/‡_γΏζp«v”q}₯_°a|~ΜHΛΫd–4x’»8“Υzt8FGυ76Ί%|uόhγμεγoMέ-3} 'ΖΥ¨Ϋ7} ϊ_‰?¨W¦\–Ha*PΫϊο·{zύ7ΞZχ˜‘2­,Av|ξκΩξ>‘w Vθ!•§Ρ” ΡΕsxaΝ‘τ‘%χ—b‡FXld7†ψϋW θ!7ΊΛ„ςnYζ!Ž3ˆ£έΛE•hσo7,Ηv­ωhΛTzLMϋ0¬Τ»£™Oε©H§“v ‰¨”ŸJ ΩΫ%«-ξšŸΣ–’£^Σώα_Ν­Θ£GΥΚ–’wί^Τ EώΟf9ŽΆ¦Ά( ©ψΏ,ΥzPψo·ΧυΏΛΠTiΗ«›\ εΏVb ŽΩBΔ‘ϋcŸš3.{IΜή0ΖFE1+V™4W˜΄Pω?#ΓfηθώO“­έ„ΙiΙO¦ͺf­ύ· ƒ_½ώοΨώoηbμLΑȚή,ni£›€>γ#ΐ_I±·+W—`‘KσD₯°αϋ?ύΡ8%1όΡΡ8Ε‰‘ρΌΔ’ηπύυγ_‘7πyώ½XΊRŽ0N¦ζ_ˆόWϊΨΝ0έϊ»ζ©υ·χ{fύQ@―τ+‘χ*°$—³Ξ£Σ”XE«hψήέΥ#Φgec˜rΧΓ]sΤqtͺŸ\ ί€Y;›Ί Q5‰mέ„ΪςςΠV**ο@\‰TL‚ΎQΪ}³αZόΒψΌ(zyQŽ` ζ•'ηMή•€Ό…}œ›γ(MGΑ-Ε2Αˆ"Zνi•Ό(— ¦X‚ΏA½Σν/φΣΟΖοό£r,œ Γ±Πp©G©όμΰιϊΏIρŸΒzώŸν~ΟΦZ-ΥΑž<Ά›£~’…b“A[Rt›ƒιΦ»΅ƒŠέ$PZG„$¨DςœΥλ_¨zŸΙγG‹κz«aŒ,—&Γ`;Ϊ3]όχoZΉi ²ΤΌ$q|R‰Zω6lώ‡­ωιΝ]k!&ηy(Σ/:χλJ*ZT‘ƒ>ϊ\`χ„Pκ•ρH‚˜πΏίc‰b|§‘μβŠΐα"΅ς_!θ“aλϊ ןˆ†ƒŸέ€§ήНɲ-½ώsθ’ίK7NqάͺΞΒΌ3 p΄fθΜ4PLYςF4ΜΐΟ\νΥ±‹ ΤΐGO·ί:VΣ”·Λ»½;ϋp `Ο@έΦ ‚qx%€Ad‹α‡—G#\IsP@Ξ€α@oωΏˆώολ½ΞœlύοφΤ(€–υί@°Ηι‘λ?hΛD@ΩrŽΪ 0)©ΝŸ ]™\<Ύ)^μ- pΉ9›\­3δI3­0Δb‡ϊ—4s-Ω ωήވΦ[α·XΝ«aoOΠfuXcΤ<3D~5i~hα­βχ>…'1³kτœf ς³6<Ιi'―αWY?~˜‡EΑεΙ‚΄ν’·ŽbNϊΎ$WόχG‘wκŽb17-ι(MήIτΜπRΑ‹+|…x?zψh'ώ–jμ[x΄³Zάw{Οχ εΎΰad+}ΖόΧUu|ΕSYNP?[.ΚKΎ]#αξόιΏώlώεΗοΒU:Ψ.¦ΎƒνΏ!ψ šxYDΗΰ«τ7¨šŸAφψΰžρՏŽρkϊOυWnw/~!QΏθDοAψoŒ`/ώχΖΪ8Wp¬πΆόοݚ‰­wΪ7ώ―£}†H΄JJ%Ε[ΰΝ-¨Β Ϊc‰D+ΟϋΔ7@ δπMˆ²*v^ΡϋT6©Λ»b™ξρAjΒ}θbύj?ίJφψπχܚnpj=„Oώι =ιώ_[ŽWŠΎψ…¦’Φο”NŸx’©τm‰:?εί•Dη'ϊs“`―mjT'²ύεSž₯>^ηJΘ8X7ŸϊC9–«ϊ¬π>ωί۽Κnύ«Ÿώδρ_.=γ·5ο,ώ_hΈ?{aα |jσΣ΅RG9χ?­Ώ  ¨jΑ—γ©Ϊ; bςšDWagΑβnr:/D±Σ³k†+:£χ„²^’κ©±ΣL·Buφvk}1n^d@šjτDζΙGi¬θKμΫκιǞ7ƒΪώε`©rW΅ιdoi@³α)θΥzBΞqY ΉΓΑνGoζ π<χ…€gwSŸΓζγWοδWΩΕcR H Ÿτω©Λζμ•ΦλΌeπ‘άWΗρ]SkZY:ώ@x΄vλβƒΆ„Ι©π±UΚ’·ΓΥŽΕ!Ž5ͺΛΙσ/uXzoΈ’ιqrNΏ‘ζ_ωŸ΅#ΙΎͺο―|+ΰ?ΔΣJ ŽΪσtέ9OˆΗή ϊ4kί!χˆ―ˆϋUpRIψwηΈnlώ%Γβ«₯v~νƒσοΑόMO£ιAԟΑxKnoa°δSγœΧΎσŠ‘cιώ_3­.Ν§λa­Χέc―ΧϋͺtΟ ]/‰νͺεσλ5Ξ@±α ‹yί"IΔ»δ-°Vζβ‹\<ψζĈmέiŠiΣώOEνώŸUziΣiΝΖ’σφq4λ”ώΒ‹Έubυ@­όολλέiοώ_Fs}°ΰ™8u­J0f¨B:¨τύ.3§xYΕέc‹€K‰;–Ρ€C.+²‡3O5d‰₯.~&φi©oF†5” Χ²fιꚏ,U;ϊΨΆ­υdλΟγ60‘s7…ϋΈoPA[ώίzΛΤμtΏ…θ ώχW7x9ϊI^›Β©§@ />挟—d, LΉ$π“Uε°vωfRωΖ5©*‡Νΰ¦`€/ΎV³όD™Ϊ ’j7|χ/Ή_Ϊpš΄6ώΌ?„/Gΐ‰χπέB3ΉF¨Ζ‡;ςςέΒαβ †ƒΛΛU ά~o ρjdg73€KΡ•b‚}"iSGA=Δ‹hωCLΗOΊς―αňOΖΏΩfδkΪ΅“;~iιϋΉkύί’ϋ£Βψogλϊοyןˆ‰4ϋRσ2(Fzwnνc3ό―ϋ΅Y"ώkνΠ™ ŽAmδn\₯=„[VxρK‘ί]“ΐ ~:”Ρσа0EΫ5€υ/^efάkOFq*ΥE‹v(½ωίτΠϋ΅ξ3‘Τώ’zχΙσνυzΛζXšuϊΏμιPΎs¨OΏ`ΉJ8Τ°γρΛ.”ΤΚΞ€k¨ͺ‡΄Ά–翝ŒXEΎεQΙ³pZ8Q]œx£ό>9¨” XΣϋγδύ W4™qΝόΐΟή ψnŒCDŸ•h΄€FΣΛΰΫjό7ώΏw&S„ΫψlΆ£³ΦύŸ—ˆΌΐ½δqΎ ‚|U‰ψ›owΪ²5[…BνœWŒY»G™x’{π!ΞͺιϋjψμG!α1ώΙ§'³wΎΦΚπκ1φšžΩΝց&Iθ^š–Gt(Κ‡ΓΪfΰG䏘s1œƒ:'₯"“H4²£ΠVώρδ ‰žLš‘Ύeǐν‚1oα!Μ ξΙ Όομ:ν7e‚¦uΫ‚MT+²©vœ#Wε‘]»€CbύΣ©’tΨΑ‘‚ϋMm,ρέ_#?3Iνrυ†ξmβΛΊ«Π,*£tηοΩφΚ=C›,ο)²ϊτ_λόΏωΧΏΪ™xΌό?ΛΩμΩό?K―ρΏyΑυžrxŽ(0Φ|Ψ/ž‡AθαΑ_…νEBάZφθ²(€ΩΎ!q­υˆβί bό₯ll>&Ί0ούΣ5ΜIώOœεθϊοΙΦηω]ύ¬x ΅ν.τ`Ϋϊο7LύŸ³ΣώΏ9τ?όΐΙκ›)& zψ—άp–UρdtUσ¨NΙR―­Θ5γΖQSxb΅Š©|!Θ\δω哇ΎU|Ά‚ςlψχ―Βμcν,-g–Κς€ZΦλμ˜όŸΝn―λΏhΥσΪψ97CF»žw ―qKkε„ζ«ΚHn“ΚΆ\v8dα¨lJύ«lYyΌx¦NUiε¨5ΎΩμ–›»έ;\ρ·Τef’—t\zxsO/ΙΙ‹Γω“… d"%ΘΊ&›ωcJvΓ3. I!8ϊ°α5‡M‡ψ…-Rηεžzμ…g1βˆJΘ_2ˆC~…—.υ“Γαw»* gμ΄μΌ‚o­½.³΄³‡hJ]t½α[ΗΞgh £ήΒ“ γŠyO ΙI󣻡#ζh)ςa9a. 1D$x­^†Μ‚šξΒi’k |θ¨yLuφ$ˆsΜ;_άcΗ/ώ>ΣχΒ5-Ω;ςΘiœΒΑ&κ»fή,ρ­ηB‡½Βbτͺ6η4ψVHIϋ Dα½ͺο(ΧP(ΏΏr• έ~ϊδA\°9?~ΣώΝτΦΥEύμ?ey }ψίvΆζšlύσΪ…J·)”s“ϊ©@kηΓβ8–^Ϊ2?R½3h»—γνfγςŠG:F‘%L_6βΘ™G&œΦΉžYέύ;nχΓΛt‘»cgέηxfi‡t5k΄k'ΊŒ>ΜzŽΜξSXΠμ“΅–™‘–qSe[cIΫ8½οΪ°u'x΄—|kΐΟΜxh»ζκ°ιέ ‰žχcΪΚάd ¦z¦(ΫyθνizμΜEqΞ `”7:nΟηΦd“3γ?%6@ŸψίΖΩjό7ΥϊS>bς!M³μ½ΕΪk9ώqΛvqV„.IόυM<ο†DΊTΖOδž;@³7±BzjSΛρPηkϋ‡Τψ Δ§k`ό‡ŸύΟλΑψ>§ZC‰c9bdNZ‹Ώ/ω?«o«ϋ?LŽhοΒDυίλ­ΓΤ8–˜F‘bΘ‹d/’[ύ3¦±%s Ϋ,'Δ”sεqPΗϊ‘Ozρb†\ˆ"#„jΧΏ€L3’½Ι8ΦΎmΥψύΟYηhώΟ ΧŸbJRΛΧ*m–e―ω_¦·ztΦ©+n•΄kq_ώΫ6KίΏR¨>όO{[σ?Ng 2s©6ώΟ½ΓΖ7k­gπ΅ΕΛτωJr|θ'oΊQ“a)Ωg­QjYt σœΘ"E`C6fpP–Om Ι£€=½y™jM/Η—]WyΣt€‘δ₯¨g‰ο‰²Μσ½Λ‘–ς3ΰ§ldΥjJ›ύεSŒA€•kέ3nf$ΪΊΡ±eΨgNρG/’UΪΩ[\}εώ¨ͺ\7•t# ,,σΰΝΩ«nA‚Ϋ¨ΈYδ+G·‡ώ₯@‘€›ί׊Κݝ„©TˆFQͺ2eλa&„€Νϊ_ μcΫŽΞ› ΕSκ©ί%ΦίZΫp΅ώ–eλϊΟβΏ“λEθZ’Μ ιœ)Θr%£\$ˆIΛΝ‚£·ŠΎ$[Σ,nX\{ypvžΣ D~Ω¨Ψρuv4D¨¨½Άf5œ΄Τ*‘ΉŠž”Ϊ?Uj%m!Uξψ«η»ή«νΈŸ‘ »rzH4 ΰΥ6ςΠΈ g‹F^žn€e2lϋŒ]ΣbϋΩ έςY›>"ΩΜΦ†9zTvšΝl(nπΛφ­lΈu‘l·J ·—ΝŒI3ςAr’ν$^‰=έ*γI²UΖ½ W£aΗm‘'ΓfyσΑ+%d¨<_κΠΖΚH‰7Ώ©r¬΄¦ζ$λ.ιΥ‡R«e^{6ɚšu›alsόδpΉkβj€Θ―ϊw ―ΰmƐΡέW6|`M/4ΥΩζw4’ΰ S¦θy“WS©GΘ-& ‹OQͺαvBM;σζj€ghΤ¬ΌΩθNBe!S„W—ΒU½άΡ,Ε5σ"pŽQࣩ( ΞύΚ[?υυZλφM—Aϊεn«±vLύ½Ωλψ ώ_ŽC—}”λεέκν²g‹<&Έ&―ΦDsυ:ό?ϊ―?εΗο oΌͺςι꺝oUώ+†}ς6ŽΞ›‘œ ΥQΰ6ύΏ[3υ?6 ΦλΏ΄ψo=ΊΫ!Ήo`a±V¨)›΅ˆ‘ΎΝΦδ‚“r‚Τ%x§wPμeμΊςBξ/o…:ςσ•GΆL3†‘χΏΐ›ρΑ₯£˜xάϋΝy»Eψ_₯ Ψ‡imiό?ΩϊΧu Iβ)Ύ ¨Ύ‡ƒmώίυ–ιΉΕκυŸΪώ«ϋwιœ³»)ϊXκΉΥ{Πu/€‹θχ€A·t ~φ†ˆ’‹,Cγߎφvk}1ΰχd\\žρ^Zs$Οƒ·ϊGόzθνFχž0ώ_υ­HDO‘Έmύw[9–^τ%‰=hxIlW½ΉΏ^cR.‹6|飋ۼ_oe[ƒ―YβζdΦΩ΅s†+ρ΄.ό‚J–˜χ‘yΕίΏ: °ύ·ΡόsΙε$mφŸ³aϊΫ–ΞšCώ{η$ŽβΒ΄ ¨‡L Ž&O”!Δμ§Y!ϋπ6~pPχ“Έq6’ΐβάd¦Χ²­m„ύh±-yPπ£΄/Ÿ)ΨμDnΠΖjpρχaMΔ`Ψ4ιΚμdgp•ηΨ²y`»σUDκYD ΗQΌΟΊΟ§ω―Ό¨OώΟZΧLΉώtΠvJώg{»ΩpψŸuύΧ ϊΏ[ώ/Qξon^bk? )¨ χfʌΉ<™¦™j;fi—)G €σpFlhΩΉεΠή‘Kj‰ΗύPκΓO —τ’ΌBΛ’Pυ!WvMΘβ<s|‡}στΎIτ(ΠσσΏ[ΪώŸlύ FŒqθ?[σΏ{ΗΦ;Ϊ·@όΧΞYƒWiΏ)β%(AχνNg ½J|ήOΪw_αοG“›™cϊ6Ÿύ oΌ±ωω@‡ΡvφeΨ\aζ€4—ΰΥ¦ ίoδ{δ§2ŒΫTϊy+œg ί(s#€k9CΩͺ@"‘ϋ€;˜G‰Κ y€‘«|ί\D“}*ι) ŒE/ΜW$xλ[;`4²Δβˆ’!‡¬QMΐ(ΗΕΕ–€θ>}ψMdήΉΠΫ‡N4ˆ²ζLMHR3•ο`ϋ,΅W³=]\ž »π’6Ν\f„ ¬|φhΞκ Ώ}Um)βγ˜~%•γΦ[1·vό+ΐγΠυ±Φϋύ^γ‰γ?9P›œΓ±YώΝFΫ‹°8&ž|œ_Ύ0,L›Vw¨½γΆ­ͺθi1Nά~`Α\Λ.Jφδ^ΰ}}Ώζ67ξ(ίϊ7σBΣz€ΈiŽςΉ5P&Α‘ωζZΒ*€΄ζ³ρ­σ?§Χσe¬«yrŒ0žϊΙOπuπϋW¨ϊδΫΦFσΕΕΩ+=C›ύ·έΣύμ΅­ωΏη°n vN.„°UPI§q΅ρΙ%Z‰»*ŠguεE$eΙζeMYΧ<§C €T[)m Έ°‰ υ'ͺ—Ξ…’‘ ₯‘›χ>ž‘Ω]ώwέυ?”ΊώsΊυ'ο}|γd΅¬vk1ώ_ΤB― ϊP·_š/„›.—€ΥΙυΒMH.bδUύH6Q (ς―tfJΎU||ΏT Απ|˜rd˜ΰp}$#δP‡πq†{ρkcαί±±βΦ†γ΄I­“Ύ³&ΘM\ }λ†1ΘW0tI£HωŒ£5TξΠ@yάά΄NύUτz¬Μρw+φHώRνΛΎ$ρΙςl—ktIΐΙ ŽOdΐS=₯ΧΛ%N2ΈνΈ΄0Β”mφjΟ”‹'WW@u^ΑM‘Ώ'ͺ²Ή_¨y³D·P;H˜ΡΖkiKeG (—GΛ­?—ξžβE‚­ζ%ρoy[Q ΰ=Γuw‘π―ίMΨ:β‘sβX‰>¨νΕGDm¦θCΩ}e§ΜΪΪϋPΟOΓ‘UωC&ώΖγΖ”ύ7JXŸώΦ^ηΜθί')ΑsT΅¬f»Άώ7[σΏ-#«-"ΠκΰўnφΨ(εεj:Hτm"‘ž5u9–»ψh―ή—© ΏγWEEτλθ₯­Πφ*x%…𓄐Ϊ_ αKΑ+("υ)+ͺœͺjΏa qs".`jd Ίmg‡’Η#ΰγ^ϋΠη8ρΌ ”Α@*Ϊ Ά ϊπښ}Ίυ§=—«‹›@©‚²zΠڝείYŽΞYώ‡bψŠCΤAΫβ4=74½‚k•Υ„z—kQߏν^Ή§H΄¬κw”]7‘l9u*ΡOx;»ι9t/υ I±uœΜΥβγ3*πΠ(>Δ"!fUΙ|φZWjωOδΠCﬡφMˆΈΌͺ²zπ;–C—š½Π·λŽΊzpζϊ΄Έώ’.f ΥΙpΌ?ώζϋW κ!KηM.Q«*3πCψ'¬³μ₯λ–!9ќ‹!ιφwΰ•`«šQΏ! @5 ΐτ`υΪΟ/φι‘‘ΘŠ[είω(Κ°*H΄ ω>εμυŸΪ;“ύ_ι—χhΎ" ™‚ή]ZυšΡ»ύNγΏEψ…£Ωχ}³€;ωoγΐεμόK.w Όώϊ3Dτψ;©£\‡NΏΒΣpzb)ΐ«X‘γI+^βqL[ϊ΅>VεOLΠΗ»ίθώ?Σ―mι‰p2o>xζhξ˜ϊΟέf§ύI«Tθ?rL_ΊW§ΧŽP j_Fm8΅o“Ύ8‰Qœd₯O݈ΦϊίΆόΰθ£7šazς’ŽΠΈmύχΆΕαΥω_“λ^ώx΅ξuT’-p―OγΗί@Š:•9°c™Υψk›Y³ςΎEπΏξ5ίdςΥ’ŒΤϋKΖώΫYLώοΪΪκυŸΑώ»Χφ‘΄Ϋ'dJ»Ή€NΨΚ¦,“«I«΅pΎVςΉyšλ°ψΕW’3‹XBZ‡7™ž% g ΠΦi;χx4διCNr―9"Λ\)9"Λ^£1x(7*Vθ?Ÿρ_§“‡Δ1ώΣώΧ(ŠJΛͺ†·„§©ιΗπͺz+oΌ¬3Κ‘zΏτΤ¨€–“­?©Š@6 h: »εθϊŸ9τ?―VGΊΆžΟ΄+O³{Ή¦gnzWuΗ;·΄Ί£/¬ΰΠSnάώCjό„ν[γΟ9mξOΧCš!U5ŽV$kιρ»–cΐ€>ό?ΞZΫS―UΜN™½ήo™όΏΝZλεψ;υ€6y¬œ#γirψ2*«Θιb΅‹ †…fw€΄bߎ•šοeˆ©λΨIkfύ#'ηΞv΄ύ?υϊ$©ΗνΝΦfγΏΆΦsψ[ΨώΌsGqΑξg}yΆ—bψ“§νγ2δΙΠγaUΖ°“Ν]Ήπu’P"ζΉaδη]ψΟo1ΡO o]ΊγEͺM‘ΐ9“Ώ]T‘_Α”Φϊ‰ηΜ δηȏiγo#C¦γoϋ‡Τψ=ζ4ƒοΒwΖOXG?Μ‰γ!Φ’œQƒΥyτ2ϊZZOΆώ%;>ͺE ŸJ1`«gΓ࿍eιϊπŸ\ώo4ΖΝ·ο]5 ‘’Po @λT|ζŠJΓΙƒΏ)œ©?ŽΞ,?Y­/υ:ω―τρ¬w:ώ3ωϊϋQzήPΊΧΞϊίq8λ―ωŸ–‘ων@x9ωΈ©Ρά""~kKzPˆ,ZzjΨߟ3 άik'h 'Υw«ήok<ώW™K.‚”Θ₯.€^ϊ­νΙΦΉΣ«Ÿε²1}u“P!h‹XˆλZg§νEθzόGͺΓ³DPΗΛ’ΐ“kn²gώά©rΗ&ΘJ‘σώ7€—11HΧΖέ»Ο΅š"β„j…·pˆ~}…ΟΆG³°:ްHΕΞΎ%$¨Ηq+‘™5–ϊvυΏ:Ψ9ΊΟtλOIjΥ @mλΏέ³ό[=ώ«·ξδ€O,ŒΫΏ@FΡ„χΙ?€2δ~ŠϊΔGΫ“―%=lΚϊέ–­Πω³ΘQ6§t’fΟύI„ςŽ,ύDMδ’VΤΠJgƒΖαό–<φ’ΠE tP9I’™!4}3;#U΄)§6jqlλ¬(ΓΉ’ϋ5Z υTΝ Uε…wΧ7Z/σΈjϋjн½™/ΐσάΩ.=»›ϊϋfߟ٠\€<“/ΣΚέτάOh8C²$=rŸN“*ςΖM>ΰ15O™“@’JΙύŒΊΙΜ:γΰCβΏΡ:€φιιθώίσΖE‘ΗfBkύηžΖ6ϊS―ςόΏMύΏYGκρ₯lύ-OΩB²4W€ώ#ΛS€­½σΕ=6=»ς ŽŒ‘τ(珀Α8ωΔzεRγ²W"#;L aD1d ›Zrύ£‡d`ο R\“qό“ά”%:&»Λξ0‘‡ώ§γΏ“ιͺnχ3!γΖή±όO[]3ƒώgϋ±Ώξ2ΙVϋq/ˆΡσK.:\Ϊζg\ θd}K"ύMl­“Ž(xΟ:υέj­T»ͺ”Kδnbί‡nλΟ›³oόŸίδ«κYβ^rΉƒL4VΟ―ΏΐSžρWμϋ>‡ο£@€{«9΄]žώŸ™Ρω3ωn‘βPp[όwΝςΩ[Kϋθ9Ή~P`Αu―πξΫ]­―…1q=’Iξn¬f!l­EKβ`o’μΌ­Ά`dٟ½›Ηk»kd𕇕|† 7ά,•Ν—fG¨ΐΨqd{§ ις ώ•ήΛ*E™@α– Žεύι}DαV(b.±eω4πΟΥ}[N½/TuoS³/•½±]‰Pσβ‰!rγjϊƒQΎOclMΰϊα?΅‘ΰ^όΏ[7]όΏδ‡ζ8y ^έ Šœΐ­ρ_‡©vœ΅ΖΛΐoˆ!HI*ΉcυΟsθzeΦ Υb\/Η“Mίs8ζ1 ͺΑτμζΗAtvΛϊηdΪ :έ°ΝnVK‹;ƒ£½έZ_Μ£ωlΔ 3ž ΆyΊξœ§œN‰ŸCθBj3›θXtXVSf"έFA]ΕΤοy΅Θ%@ Λf£σΏ&Σ\’Ξ ΨΈώͺeτf»Χψoύ?‚p-^#ƒh’1„,₯μΤ ΫΏΑ7βd_?οžvŽι^.€κ-yυ£GLUχ€ό1:Έk*Γν‡Υ gΰήή^|ΖξooOΘiη{˜l₯ζsΊΖa`ΣνZ~£.©mδΛ )κχ«Bꝉη:λξg-O@Ψ=ΥμR'~φΓΐ7Σ·πώo„ΆΟόߞβ―ώŠnr―·¦ΨυΈZ?»ΎΤ ˆρbΈPΰ‘eizRp}Ύžύ ŠΜΓ±(uκ+h^ΰΓδ4όςΨg½¬αe彝&”qθfn}IΠ/Φύ73ŠsȘs|/>ϊ’νG«Ο³+,ρ₯ϋ–ύYπf;€ƒUχS¦βΣ‰ίΝΌλω N Α•(n‚ΰZΐ^Γnίγ"ς9N%\ύ«€ΐΏ!qpΔNLϊ‰MCΰΏπTξΕUuΌΎΐ½Π_o”ϊOHBςgoθ_/β„ωαιρQιυωU;Cϋύ %ΒSθ^θΪ«Ν¦Οkƒήy¨ž0qNœ Šji‹«ςiω.ŽXύrtCŸ—+‰Στ\hŸ‘uθ>²χύ„=ͺUn‡]ΕόzΒk€OΞ;γeμzYŸ‡]Ό(ζ²JνΠ|ζΝ°3η΄^’r™{η=^VBι">ν5OωΆλs―e³&ξELχΥυ3κaƒ―ΐƒΞω$fu1μήW(ψDxοA1"υ#, ΛΉ—΄pIq½p^¦MԘ'COoŽ›DߞδkYωΣΔ³°”"ο‹ΰέ¨μ½?Υκ_ε<τΫD A΅r^tκ‘£‰ιSίAŽ΅·0pJ<Ήlγ°‹‘Α=ΎΜσΫ…Syφ ύΠό€Ο6ώ_hόYΕ/xKs%Z6‡PΠΤ}™c(1zρ.Œκ…˜₯‡ΰσαo_C„[z>4”?ΣιW ›δ{ωͺs…}αΨο~ςΨν$:œΗp‘PρYΐWψΊ>ΑχIξχmό…qPΗ»e«‡™OδAσ³­¦MR·Ίž2Ί†ΈθYήpZcΘΟβ8ύ,e›=NzΩsβ^ΞβSβέΘx@’ΪΝλήD.±pε«ΐΟ— Ξ2œΑ.·.fOȚ ½ΑΝϋŠήΩO³^VH,ΉT*Ξa¦7œ)©Δ~xΤο‘ΤXΆψ©ήbΏ™MΏ“’*‰†ΣΥ¨ΈπΊΗi½Ζθs—`χ@σH7Kΰ§R‹Wνx΄ε Bψ_ωη™Ψ!œδ)!ySwή’Β!gΖψVς­.ξ©v#ͺlTμς’Ÿβ9FάM}ΖRAg 9šr^—Onω»NQόg€΄΄Tέ&ΈλκY­ϊΡξsνΟTςΥΏ=7­ν†·ζfΥ-πΤ΅Δ‘_ΫžC―Txκ^Dρχ@Žƒ;sΏ uΗ—Ύη'σ6`‘εncˆt’γη¨ 0 ϋλ! @οΣφΔP–˜›ν~ <Λή}>¬λ³Ε:Ν#`ϊα…q[ήίl ˜w₯°^/.Ό@ς^ΌΛίKΌΒΰ»―ύΤΟκy9πϊθΰζΆκF7z<œƒϋl\πε‹…,f½Ρβ3ΌΆά5z›χ=nΊΖέ&4³ΔlmΟΖiƎcO΄k£φδ „Νρό 9°ͺ`ξήΛύOBβMŠž ZSOή劏)kuςA*’"b]ά^Π>υŸ£ΑΰίΜs£ƒghe$8ƒ{Ί#ω\΄§¨†‡ˆΊΈ_2/\dυ‹u’©9ξ=€z=' /n&πά‘'ζsΠωΎΟ΅„ΰmb`ληΣ“²)ZAeΠ"=\Ω—)ˆ«p>lVgp—½λ}Q<οu§Ψ†υhυx$―nrŸΏΕπm'ΐΘ.ςΎ €Qύ;»FΟi"ŸH‘Wp C%°β7Δώo2ΐ"?ς‰_Œo·%―,#meκ„•χ’ͺ2O’Κάι)ο-1e””ι’Q–›²δ܏₯e}̝ﱸL9r<ζΛξ˜&―cΙ‹Κε˜>‹c’όι37tΞFΏG5MΆΖ;ΝӘ>Cc¦άŒ±³2&Οǘ)cŒy³/&Ξ»XLΖΕϋΞ΅˜<αα½ε,&λ@η(Μ7˜/ΣΰΘ1ψ˜Ωσε,)£`ΉsdL?0UlYG•Gˆ*/#ž―ΚH΄ΤI'αF»’™Γγr9{€\ξ2g šΛ]Ϊ$ρσŽ—2i(½γ΅©Žͺw<ύ8v©‹Pk—:αόaχ.—9eΎΫu)Ζw:Ή’Έ|§3ͺΡw:ΉŽΦwyj£ξ₯ΞΎθΎΤŒΞ—;ω˜‘}Ι+Pδ—:ΥHρ~Ήsϊ—Ί‚²€Ξ;EB€τ…(Ο :σΔirΧτ2δnd ŠΩ3‘Ά unΕd Rη\fΦ„τ₯O˜@!wM:—’k.…όs1­’ΓE|€ Ι»}ΏΙr78rή…ΤELŸ‚!YΣdcΘ]Οh‰r§%GCξΤ…θAϊn?ۃԝ«MΛ‘;₯ΞΠι›‘#|'JΦ‘Ό Ay;rη˜#…§Λ•”Ν#u ‹Hμ‘Ίis|”έ3K^Ο»Κθ™1—gY<ο2gϊ̝‰svž#³ψμ˜EζΕ,"#f™Ή0³eΑ̜2aζΛβs^–—ν2SžΛ”.3εΆθ¬–ΟkΒ|–χœΙ2S˜Ω+“δ­Μ“±2gΚτY* ΘO™#3eY9) ežlw™“±¬l ‡‘:cζ Œo%χβg]̜o±ΈL‹εδXΜ–]1K^Ε€‘vc+ΖΎ θϊΈqυ%FΤg₯Ώ‡(ϊxρσί}ԟ£ΒόLΓ8Z½B`^\`α*MΌ”xI:πkψ³sξφόώΎ·w{gηΨ[ψ»΅ΩΪΦοΦS<ψFΊ‰aόξύΑλΈΡσΒτϊΛΔΎΏΥk?ΚdΘ…₯‡‚ˆ›C++‹“ΥχπSŒ±ΨΌώ{³§ΦίΆœυ^―?«ΚΜ_>‘t›Θn f8xi©₯>!L ΐΑMπΖ Τ¦Πΐ*Nαs†ή‘u‰ŠΈ5K^_²B¬ΫΦΓ§ „—“2£MD=“»€ν<(˜ύ“\ŠVœΡ€ΗΗό9€™ΏΩ^ςvΙbz0όμΘi›»šΪ¦(9Όrn+…;’ χƒψ“T₯D.ϋV›Œέ-˜ΪΝ)η2πvώ›ψG$“°Ώ99α΄­Κ’ƒ³…άηy ω‡ΧU&ο΅ΰ©Vξ\(ΝZψψΙΜΈ0Ύσ}‚ΝϊΠΝθ9Ψ#ψ“ ΙϊεnΑ"ΰύHƒp’ό!·ΠΜcj܁·pU„άDΓKs'Νp?B<‰πžΡxξη~ ‘ΙL{&lGΘΣΦ‘Œ½fη8!pτp]ί§υϊ8MΗψo1ΌNx±™Ί<%v}GΏm―ζ?Η!Έδ‰τ(Μ™ώσjUœςαSΰ{πBπΞί_ΦΔ’9‚rm#oJ\ππιr=~z.Κ_J}Έλ­zžg?;_θLψ”ψθ"†»ί;ώλbtΗΆ΅q6M΅ώu-Σ Ϋ+° ΩzuϋΟΆ·Ž^%ΰ7ρΜτΥ½Tœ!u“ LeDΆΚ’2©Žk˜γβύoΘF€―Fέ…EM§fgnLβ€ΨJm½~ΐσα5pq1CEΙWΆ π~|Ӑ­]¬ ӏ ͺ„Β4μι0zΌΐŸΰοπI½ Φ5CΌPΣΠ;ωSρσ3kWεη';ωC%Ύ— Fζ{ωC/ ΄B;ƒΰ‚Σb p\΄μΠRό9ιaKZ•hΈδ€ΕαΜ’›€Ω,³ Z`y©³Ϋπ9ϊΒnnβ»Q&Z₯κ!Μψβq³’ΒΉkαΠjn˜‘tςΦ‘6ž‘K™FΕFφh’Η† ³—ŒΏ™uX\tεΆ¨ϋ¨\.J›¨elΠσ‰>КSϊtύν7R ΣϊέςfgΏ£ί oΒϋ·#ρ­p' olϋMV?£βθ²BΓΰpΒτ’?ςIπ„Εύδq΄κ a?οΡ”;Κ{(6δrΊΈΚb3½ ΜψςWχ›Slθαq…υ―ή„C³j‹ν[·(ό―,πΣ?ώcΫ–φΟ΄ώζŠςsθ&/Š,Α–υ'k]_ΗΆΦzύ—`ωΡΡχ Κ:•Τ"kAgf+ ω¦R?Εξ+ z ΐƒδ:Vw/ι*Ÿd43««!Α†#κΎΊ~q‰ήA A’(¦£ΟCΆC|°*ΛνDCοB§}’ϋ±Μt•Ϊχ|αšnGΐk―Np0*h ΜX]?°ώWƒ{ΰ?Ηr4ώ›eύ‘©­:Π²ώΦf½aπΏ³·υϊ/±nχ©=JήNΨΥS]Ιgς z@‰±όGΖΡΝ\ΓυPΒΉ@Ξ #7xƒΈΧ€ΞWˆ‡ œ|>x@ΟMc†…ΛΕ >ώg³Σςςό’ϊqτS7MAx@’ ΄ιgΛβΏύN―"τ?fΐΗ’ώJωS&δ eb F_|τ†qŽ-XQΎ¦ΚΌΛͺΫ#*b! ZDn&sά(‰œόŸ£ΚΰΪώ8?i8©Ÿ΄Fω†Β©΄b‘»ŒcΙ·2ZεΏ,ΠΗώίΫΪώŸ~ύρΧzIΠ—Ύ:Ζή3ˆ¦Π‡Ιsv{Yˆώ'D”UΪH–œ²Ί—›όΔΟUώ’'tΰ?Χόt?L7Q#Λΰ‚šΎ)6Ž―ϋCx–€«λπQΙU1Λ+7-λΨΜ$dͺγdΒTΦο K¨¨ΤœΚΧ]½τΆcEuυβŠ‰Υ7Nί²βžJώΟ€wνwύA­–‹ Π¦mΈZ­cιϊEθz²?₯ΖΗV³K³ŽgQϋΝhK Ί!€iυw)\΄ _Ύό zθνf«ε„ρT܏X€V8‰Dθ%ŽPBΈΑ5£8σO8 0ŽΞx -soΡρ{½έλϊΏ9τ?ζ(Ηy%σ.Tϋ9eW•_¦ψ$Βa€‚ίΌcYœ|e\> EψEQ&b/ͺ4Λ·DŠeΣ«χ3mόBaG/pύ° a[‹‹‡Ί°΄t©^κRΐΔζέ So9Γ₯©<¨±e‚kS5?%Ά΅°«ώΆVRΣέΚ„kΙ2―κ H˜α>…ς¬—ŸΟΐ¨κ,ΡvBDjΔ¨U8‡7+=Ι;œG¨Ϋ‚Xγ₯ͺs_8zty0}τW<Ψƒa½ΥώŸιπ-OΥόώΰeπϋL‡:€ΪψίΰΚ3ψΏΡψoώ)Τe…Χ΄Π4BτΒTγq+j†ωK‹‚ψΰ茈§™WFλˆθΓFb{θMՐΒoκ0Ω*dΟ ‘7Μ!Œ`tΎ·Žaϊ…9«¦Έ΅PνεO< ˆ;/σθ께‘€υ…œΙς™˜Uh±>MΜΫFΩ*y7§ΞfOƒΝΓΒ]y™&†[DΧ*Κŝμό₯δM¦ΎV’kˆU˜ΓpƒcVj₯Η—η°žΦ‘πΫΈ'1yω}Uh¨%QX¬ΧΩKΞCcj=ζRψo Έw·Ϋjό7ώ₯%`mόo;†ΩΪ؎ζ^ ώ?Ή~Π’ΈΕ/k³†™³1―ΝA›6Ζ ™ž₯ižί!ΥψξUΈ `KQŸ)ο|qΒ/P“Ό K³΅Σ―U&Β§_ЎΌ»Aμv’φϊ—ΠΔΨ>#„Μ§ΦΰGW”„VδC)œ[Κ*λτΎΧ",‚‡G‘@Ε}‰ασK„ξΫJ6»[XέZ7—DvQ ƒsp•·y#3ιέ1ŠΓ;εΌο¬ΆY„U–χιcιϊ9ν?₯p­ω?¦ώgkνtόoϋΟC¬I…’Χa@VβΎΈοζ‚›ΟrЍ>%]{“œΎ™y¬ΖΩƒ‚©ς šΆ‰ςΓΊPβ±xy89.JGGe8 rlΧΓ‘`Ώekό7'ώ«Α#η؎΅eγ?ŽζY„ŸBνΝ?Φ–»2\λΦZa™(“Σlfp·D₯Β?8"ZΒΞωq:`ͺ{g5“ΰϊŽό΅Ξ˜uύ±™5Ikλ0ωίΞf―ωŸήiώχ08Χ?»a~`φQ‹ϋa‰΄‡f˜ς|IΗΒdφoX4Λωψ7ΊώkΊυΟe]°˜˜½έrψ7šaύOλχΚ“Υ—γΠΩ›ΥψšZUpŸχPάοόο›½Ξžlύ‘±Ÿ^ύ ¬Nqς<΅όίX;Vώom];ƒό?Έ)Ψ9ΉΠΒŽ9Τ/gˆ Dυυlώ‚@ΘΦ¬ }ΕΉ!\*Ψ—λ!§)ΫZœ$^τηJ‡&Ϋv˜ –Κ9‘Ιa“kgqe”³Γ‡ε›o0σέ€³Ό€œ­iVΫΪ‘ε '@BˆiτΙ`lH_“€PκΫθ/Ίi=ΆΒ)ωκΡ,A–}Ν*ipΈ>‹mΒ\άSG© δ¨L|nŽυ κτΞΏIPm†pdΎWΰΫ8Ύpb?c•\«πoΰš‰ΤAύ„_ΆσΘ:'^>§&‚uξΕ—-˜½YOΦ–™œχŽ'ΰΧW\QH‚Ψ{Ι}θsεLe+/tΘ9‘ZRΙ“€;RΨGόχυPΝ―5γ{ΐKθ€σg[”U¨hεήΪlύ―ξ4ώηv"ηbίqAmW₯ΰο‘64W‰4€_Η`έr뷐Ѱα]Λ… Oύ—­ϋ?M·ώχ„1’0‰œλ‰»:]#œγt ήι ­ώΏ5£χΆ­ύΏ3θχ#*7υ½"{χΈΡ›"ξ;pτ1ΙjδJΣΘ3ρΧ­‰ΏŽ 3B?q}Ӎ’8#D£Ή»l&ε1 ΏΪSκJ Βχ΅Ι$­¨j0Ω‰¦«WJ΄\MιU£‡Χχφuαuφά½€·gq§)š–Gu%/Κ_5Sz@‚΄4π,D² l@€o=[ΉΨϊm΄&Εώ~Ybš1ΝHN4œζu’ηQO“>}Χ²FΎ’Š9₯Εu΄ώι‰zΪ=πήώŸ9μ?$ι€B‰bPγl«³˜ώ/–γθώ/³ΔkΩήTdΗΙ $<ΐΛ*%ιί›ΕρΦ^Ž’dϊ₯#un;§  *^u…rWӎμΙ>“(ΗηnjZG¨ΒΙΚ€C©‹’ζΟ‹@Ζ3„ςΝ*’ΑκAα(9ξ”pΧ@P΄ι%^ΰ>ωŽ£ω&[’E±ψ/ΰmΒψοzΏηψ-ν_ώλY緁U‘'μP―¨‹oΖ€ίΜhϊΟ=޲~3Η¬­Άfπ`g‘e‹άθ@A+€Φϊo›ε±·ZΟ.₯©GAΣ Kΰό-¬ΝΗ;`iύ_UΖaυ¬Ώ…„Μγšω†±Θ²ρ‘±Γ"ωδF±ΊκUλ]Δ}Γ–°„όŒϊπΏΨkνŸ~ύ™$‡•έάΐ?šα5λΩύ½]―‹ιjΫΊώ{ύΟι±ρρt€€φd -–>Fωω¨VdΜχ©½ΊϊgTωίτι­ϋ?Μ±ώ>!ώ#±eΰΆψzΝΔ7šo2ύOχΩκ’λΛι[ԜI+H£νΡA«WΧ¬6Ž8ޘή!nj2:Š)g^qηCkl΄6[ΡΤlU?†;M !0ή,ΖuSπΖϋ‰h΄Ÿ΄MίΒC˜š€ήω>“8«‚Y#<ύ3…ώWκΑœpZOΌώ½1 Άωv»=Λ¬ύ?sψXμ‡Φ›ΘDJ&Ι/,aRψ/ˆŸ‹².T&•e|ˆ“8-x‘ΊV_ε!Π½πQγ}¨Ž©ϊλαC”Ή_ﳑΏΏ10γc3Y\&€fSϊζ#‹;6VΨͺΘ{‘˜MNώƒ}β?Ϋ­ζYŽώ'o€ϊoΛΪ[lύΟFη-BΧ ·{ιάώ…ΜTƒ΄Υ`…΅4e@dLΥe'Ρ^‡o]ώOYΉΦρŸΙΦ1ešΙΕ[!2Ψη‹₯a”/τΏm±ύvk»ύ_Ο­£>-2#oG17€bΞΟφ–Gf*δXb"Ϊ\ω?5³SΘ2ΤΓjΊN΄xŒxΠo]ώ«τ©Ϋ::ώ?ύϊ“O—$Ξb…€νό―ŒύΏq4ί4ϊ76™,Π4#mˆ‹ς?&4?ͺ²_ !6#‰₯U€τkο§ήgπŸ?ύןςγχƏθ³6~ƒY ψ‘šX~hhπΞεΏΊΠ>ρέiΟŠsθB±6%ϋnη°υ{aCu’€ΒφδTΆ™ήεjf~*Ž]Sk{YI―¬ΡΡȈΊ§CI…€Η’Ο‘…Ά "Ω jNΦ#ή.¬ MZ:vά-\εϋΊV”J”“–3πŸ \<₯Pθ8»Q:γ.θTC‘’Έ΅zŠε†N„ς_σΏƒϊΏž…^’ ›·ΩlΩόΏ­£λθŽxlΡίΠ"ς¨ΤΕ¦œ€°@λ6Φ‘"DΙΡξx{ΪF•̍iΩ—Δ¬^.Ε¨mΔϊΘ1™ΪαkΊΈ¨‚x’Ψ%'α ηΘα”—Kδ„'s!읂ΜΜٚβ€aιΛƒ«Ο¨ψ %° ΰnΔ+ΰk ΖώόZU+fξG³|½,ύχΧ=δ?<\ΧO&‰Ρ—ΎE€ AžψK([… DefgΠ:χzq·εm6 ―eY:ώ;Gό½Θpς³Bμ8PpΤ‚ ­Λ»LΐM‘Ε/~L΅}ϋΜ'>όε“Έ~HžΡΆHqγ Κ§Ώ+Υ~?ŸQύŒ ό­Ÿΰγ3 { 2° @U垁‚πωΗ―\UςdŠ6aί‘όο†zπZλΞžlύσV˜h±‘Ty™Κμo ώ‹­Zkώ—Yβ?oQσX!r?/Ώ‹§ΔύŠq($ p±ίPκ§°±δŽ_ςG‘Ι0OKω% ;‹‰΅ΎΤ?cΙ…ΩίύόΏπo-'χ“heθCϋΟD€ο§ ~5έΘ ήRΏx«ώgϋνΧνA{ι-Oμ~ψD^7‚ΠŸΐώ|j žIjˆ% ‚aέΖSXϊ2=ΫΥύρ/Ώ£ρ‡όk1Š―ΕΘΖ°œω_¦Ζϊgωίτροχš{†υ―e…ρρ€"O Šˆž M;,Λ~£γ?sθζΪ«ζLNUuΪ=YΪEaά8KlΤϋ!IΦΙc3ˆ(1ξ’D92’e•ΖD#Θ~ λf­ετλΟJ:‘€Vώ— ‡UσΏΜ‘Ωϊo‘‡x±€œLΟ½—‰μ 4uߍ²'/ΎFY₯p|T—žiλE•Λ/ŸβKήΡν_Œ,Ή2ιkαΠΌ€½q†ΌΦ—FΠ©X^\ΣΦ ―½δBΎur%ΈςP\+"Έ₯m’cΌ„|Lψς―~ό{ŽΪTcΎ7ΠΡ*DϊπΏξ΄w>~ SΣ8 ‚­ώ=›m[Z/B_@φœΈ—s‘ΧfjΟdŒ+U<ς (Κן7ρΞtίΉ¨©ƒ5uk’CCDΉ)ή§¨‡Vΐ}Ό˜ Ω£<Οƒι Πή DoτEζ;£πλΥπζ5w"¨½oyRΑ?3₯‘GAΗ¬v‚kδg& ζΡw_ξZ_lά#!3SPΏζϊ.ΞΘά<"`ZΫ§¬Jš[’|Qλƒ υ”A,εώΥοτGγ”ΔQOŽ]¬Ωja5ββεΏώ0ŠC⒏δEmΔŠͺ€ϊΤμw:ώ3ύϊ‹τη0K •iΟφΨοtόwψŸ‹ι[ψTυY ιΩMΐΡΘ_l½ΨXE`»ΛΌqTˆ.LuH~ƒ4Aώ|Oώv"Pkώη–υΨ–^ϊκŒΰέsCλε%œTQβ*i(°giې€)4[†goφ™Ί’Φ9‚‰Υ­R[(St λk`Ѝς<Πο‘83°8ΓΖ"#iϋΒ›TUς{πd›~ /m@ d{;±Yώ«1ϋδκόΉνά‡©΄¬Ώ½vXϋo½ΥρΏEΖ‚™RΝαNΞ¨ ‹°κΌa "ήΕ„Pί όίH₯!I±¬w”$»¬JΏΠH?x5a,vBόυgϋήƒC£€brθ«”θᰏsBjύ?ίϊƒ―—ΐυ£)κ­υ†Α{έaόWG{2 M9°™“L άCœdΰ/.*Ψ°Gω'­±ώ‘—sΥnuύΗLρŸΒΚͺ«emΆΧ^ϋα©G|dΙΏΥ‚A>…!Y„xE ·‚Ϊ–΅°…ρΗΏŒ‚ ―‹ZώWε¬ύ7ΊγLλώRΪ€-ώco8όοYdό§sύO;€ΰ„‹˜δe₯Aq’Δ―&>_½}eGηΘ”κrεΑό§ŠΘO;—χT#m‘‰8aΆκƒo ΒIΉ…”ψ„ϊ©΄ςQh—ς >Ω[QŒΓœͺ,Ή™‘²›*5–sγμ1ΜζΥ*ΐτΐφ~―σ?η\Σ5ςH–#i?&‹r½ώ™ χέΠZ‹SO"Τc£Ξ•₯–‚$q ά·η$ΎζΔ•DΖYl\STγcf$σΞPξ¦hΧϘγ2‰`\χ:XλΊώŸΌΟZΗ§_JύW.'¨΅m^_Ν2?ώsΦLώοx/ι5Μslsͺ1–†Η3ˆσ½€ΕdŸ%ς|έƒίBOŽx_Ν‰b―ε¦Θͺ{ |\Β™„ϊΨ=Β“{«f,B›š™½—S―l< έzο@ΟU­ω_ζςζκ@]Έ­ŽυSώ_ΗΦυ‹πΉι[δa30+³ ›eoΉλt½ΐ½δhlƒ|έΓΖ§k‘ή0΄Άan\Ή=|I@y­ΟMΙ'ΖMύπ€2lύ…B[ §`Ζρ³Α”―pγύπϊv!.­ u•°‡„ΡύW£Ι•#²)€*KΕ(KΓxtl›$θ࢚ΰ6‹v n―€ve|Ώψ15ώt zτg~x» ι¦g(Π«}L+μΩ€γθ³Ξ‹&]b럞ψO]@Ÿψf―ύσ]† 5Zσ­-ΓΉέjϋoψŸΐgΔμPΑΩ-Ι™Kγ„œM›U °H],υύT}ψ·šuυ'όΣωlkΗΣΊγ ςŸJΣOΟ]ψ?6ψΟMρ'²©B7nΐ#Š`‡6Ϊ°-Φ;¦$ φώ|]}œ¦Π­‘”ϋwQζ΄PfΌ~bήΛ9‘‘Tl"SŸίHΊ-©΅“ΎsHη5ŠγqH\>#d„SλL°oSΟlotύί\λΟEPΫψΦs6ΊχψO Ώ³‚λ-`•σ=tnjΨMΨδιχPΓήwΖsάώ™ΰDn„(ι›Ηλ4]K [¨’J@@ŸόŸΝFΧMΏώ’œ*aA›gΏ₯ωl ΠλΏΏ\ΗΟΔ}+Tο– X_z—ύ5g²°)ΜMΉ-EΦΆ(›ϋ΄μ, [Ί_wIΤxΨ²Κj @NQεGΙβ.Θ‘kθ3όν’6Ymzw“›¬‹§ŒOηPυ˜Υ’R$έm|[e(|v€ψαζƒWK~¨ƒΊ&οpyεU·Z©*;£pά•…ΊγφŽo`/ΝχΣέ`awόυΏ₯ρί ψγΡξjΓΞ–ρlmKη,υΒz#»w‡ΣδαΩ·Z-§œ}Llυ Υ†*dj$U Δj?¨ύ?ΨΨ'ΛΪjό7“Š#€nŸό±oΡsΆLώοΞΆuόwψ―έI·Lό5ŸKI <ι‰Iz‘ς9(U8ζωΧŒ?ή…‰ρ3α@AρΓc€–ΖΚδδόO;mΟ·ώΉπQ”ή¦χh­©ψ―½Ρυ?3θ“λ•:ŸΠO\ίt£(Ξ°0Θkg­΅¨_ΧΕM^ ΅χΔY΅ΆŸJΟΧ»W?Ϊ»ŽŒμͺHΩί,iVί2ύΧκœ —$Ύ _I‹ζ€YΙ…NešŽ10J …ήΓK ΥP^\έ·A¬qΊώφ[žYύP{2«|Οƒς,―οαڐD.πxWΌ9ˆŸ}o,όθx-§^,Žαϊ‡·³›žCχ’΄­žνν8{5ƒώα“wΉŠ~#&Ug4L±Ι$J«ˆ.Xp§><ξ―?₯λW±*Ύ«Εθ Άο_…θγs6ZώO&σΖ’θ_ŒmΥQ?JΩϋ½C―Ώ½ΥωΏ³Ψo( ςωM9.~„ͺ²ώΌRϊo;4lνέ­U!ϊ/€cU+°Š£xάΧ7Α©ρ>‘έ–UfΕ~c<|ΚϊΠcq¬†š%η@—κŽ±{dOM‚ΪQ6κιΒ£[Β«ΔΟΟάT τˆΘNΎwχΎ2’•0QΛγKkΪͺχ·­b£VΈ+£ξUdc ‡\€ͺ† ε΄κAWώ«£ώλ«mg«εδϊ_±ή—\ν~Ητ΅Φšyύ/έ«ξ(ζΐ„|ΦL]zz‰‹Ή¨ƒπ• §oE½²³w$qRlDš˜¨ΟdΙ[Εb%[Σ,nXή5›€μg7ΰ!u†υξs…4ΩώPUsΉz,φp²ΣφήV9&£yΞnQ5Φωις]|΄εΕΡΙ¦†‘M‚Γ“·KΧΗ›ςšFε.ρΰόώ~•TGΰέγ}/4p° =*„/„ο₯Όaω.ώΈ rΑ\# ½ΓΚΪώΜ‰›3πC?γίMuΏŽϋ!0αkuƒ`ƒzΩπGώΐ›Ά:Hεχƒψκπ}ΌΟNεΔ«\Ρ‡^Cσζ&Ύeάχ ΊΏ!Δ± πΥvŽQώ΅ΖS.Ζh:υ¬K‘{J0 Μiλ‚Ζ?‘ΗΧxξ‡5V•”BŒŽ>’―H0σV€vΐ€F΄AP1Š'΄Άθ΄ΰwZY-x\θ^ΏΤn6ιS‰Ÿwε±Βηθ»ΑSα{Ν{«‹l5VɊήlω—N=ΑΒή’)HατηJ ΙΑ©yΈϊΑ±&ϋVω&ξ°φ/Ε ¦)Ώ:ώWFσγΫ1πΟ3–žυλζμ–4 €`lί\™6›ΔΕVfΑΛΓ+²Ύ4”…s±6υw₯₯Z=T¦ž&l/9e²W0 {-‚ mΌ€Ρ-τ–Ž`ω“iΗ Τμ?ΕvϋίZΫΊΣδφ.O'φۻ͎υ[:ώ3{ώΗ¬§zgKΨ’ύΝΡξ©œQ*0(Ω”ύΝJIΛ²€Aξρ—$5α>t‹>K —+ΝЍ Φ A”­ΔcωηJΧ’θ8ΑZ²>?Ω»Κχͺ°5‡™›γ•ΐ >E3Š3δ{$’y((ΟέD·FΈ  ί%ŽΠΣηŒ–°K S²šυ+eύΤCŠυ VΉuα,υ`μΏ vύΘψCq—ƏIœΕb_Ÿ™₯%ςήR Ήϊ ρg§υΤψ―” j`Λϊo,›ΙΫ¬χΊώkρŸVDΘ­ΐ˜77 ¬hνί)XΤX―ΦΣ°NΎš€žwίPVΒ…|«;$ν)ΝYN;Έ9v"Ο₯\|ΘRLΟΥο›λŸα½„ωn‘—™πvοv—«‡&Kjό@rΗ―cΑ֊ kb4ώ»γ?₯@ŸϊŸ΅Ξnύ9m•@Ϋϊ;ŽΓφ]kο ψ’ΔžΊ^ΫΥ,©_―qŠ ¨ΕΗΥg΅@S]ΓΣ• ‘žΉ±4F†…| 5@ωo;šo²υO/«ψtΒNΣ’€Ϋκ6έۚaŽψŸ›‚“Λ>h·€wήΨ…!·¦Σw)+NXβfβZΕVha$ω™ΙΉΧ$(κQ}Θα›[U-{Œ³ΝλΥ?Ά'ζ’Ϋ·Εvpύ‘$ι=yΛ₯ ρq¨7J Ω`ΐΗm„ρρ(/q)N‘ ΡΉεΏϊ$ >ω?»˜lύλ~ΘΌε^ΰ&βί9[–y―γ‹ˆxη$ŽβBη[ΠψσχBΤςfƒ΄>Κ|†(2‘€N²;±?ζωk«χA:ΰVzπ‹wR?Ό ˆŸ z)xδoΤH$x"h#PӝΕΖQΙ¨ΰ•ΚΰψD…ɧۈˆ.Aœe8{\—ηŠΞ9ΈΤ:ŸσIΏEΟ3ϋύ/ΒkγmϊϋŸΨώΓ0|•χhΎ"†3ΩψφίΦaψ·ΦV―"μΏwAΨ_vƒe=g(=δΊΪfe?U­Ρ’Eκnr¦ΛαΉΠb­½τροΪ_Xύš7ΌRΥΤ>εjύ/πzWψz x½†@/ άϋ·Š”?².•·Λ«?²o HΘYμ?k­γ YΑΝ€ΪτΏ΅fςw›΅ŽΏ_ύ―(iΫΓWβΚ{ΨGpς#’™φJ–¦ΪtύΣSώ@}ϊΩΊχŒλ_Cόƒmϊίή±φΏ£ϋΏ.CΧλλ‘[^ι7/^<ΈhŸ¦ΑŸz/ϊ3ˆ@κ§Fa«Ζ”Η@Íw-‡:ϊ؎φO_s”^!ΚsO {3“k0]ί \y&o­υϊŸ§Ρ4Τ²h֟β]γ¨Pj;6qΣ3ΔΡ1RςԎ™=θ9ˆn€Ξ_3šHώΞίCΆ4ήΚNm Ίv6Θˆ" Ψ‡"‘uδε W\@·”OQ=d4€.τ3Cωn˜Ρ |eΝ»Β‡ŽΗ’4 ε5iH C5Ι§›νΛU)ΓΖΟιpŠVπδ“,ΓΝ£-(έd\;£WξIΣ%q§” KjlΠ§?ύ I‘:±_– >υΐX>|"V,τ||ύ|ύ†2ΘwM ­Β2΅y‘MψoΞώίϋ½φM†‹<…/^θŠs@[ωφŒΟήιϊeψd}|έAυ̚*O{/ιρΠ€;jŠ/ψΝ‘Λ!¬=;ώ»15Ή…½¬$’€Q½S±ͺέ‰χy΅q"ω―6ΈOώοVϋζXΔΝΌσΕ=*Emύ_ΦlώΟΖr4ώ›C'ž™Ύ’ϊN‹˜ΈάςΜΔ}+μκ-―Ζ2οŒΪΨ&Πϊςθ,­³Λ4Τ]( fΐ»ϊL%ύ’ΝnŒΖΞΉŒ11φΙ₯¨Β™½uGξ”Wi€W³θyςΔmλ*ΓΖA…Uƒξ3k €ΖΥ*`΅ΦυŸ3?ιMΊΙ‹$Ψ†μ-§ώKΗ—ααy$ΪΟ:L!xρ2¨f ψa[σbIΖ“‰l§vΥή*ω$K‹ΞΞZΡDΘVλ)‡6 ŽΌ ΘϋNΆGΛWΰ]‘xβί$Ω‹H*κΗ1Σ”FŒlΈΡβΕ+ος±v!«*4£‡t‡½κAiρpŒΚs œVΧRΓΤ ‡#Α>ωšcΚυ?Ύ ±“π?›Άίz·΅9ύ_4ΟΌψNύ₯ŠΣs€Ϊηc:W¬/fνR¨ώΦγ©?Αχ?w'{ΏΣρŸΙδnι€Ν Ά– ˆ%Š -cΟαuvΊώφCύ%ώω]_Ήή™LqbπηrΉ‡ φ^ΈY†HΒα©d=Ki#;iVq/=¬2l$Θύ%R₯€QJ;εV1+P—f·Ι@ ·£ωΏ§ΣuώΧZύμ ±ϋΊ[Ξ™Ϋ§*¬M―™ώπΫΫkϋ"ύOηp2ΚdyR―L‘:wο]ΥμfζΡ6SeίνZ₯Mͺœ—ό>Γ8š¦ψ„ ό ©W3υOT;^υΟxςΏ;"θmΤDΛιμ,‹S(ξP=ΤWΪl ]ΐ­ϊΟτΪ8–ŽΟ`‡~βϊ¦E1!O °pΞmσžάΚ„κN\)kΠwβ₯Ϊ³ξΓΰVW¨ΗΈU J"p+μpjœaΔ'N”η­TΏi τ΄όWθ“·q΄w²υOΟΧΣ)ΘC:BϋΆυw,‹©°Ά{οη…„­ΊΈA€Έˆlα™^έΰεθ'yχ‘G6gΠ=ψΟ ’} άζEδΠΩ³O TΓΦ/Ί~XΛ,fবK_0έκ?ώyUŒ‘Ι‹”‰ΦάL.?κPμm ?Dt[ΆφŸ…{jό?νϊ#U1}GΛ²ΨυΧω3Ψ*–[Ψ<όއ›‡Β"Όοω™IκςΫ^yπβ’λ-GΗG­ϋυ@ώ/’§΅Χω_Σ―n©†mόίpΉ™όGχY’7ˆŸ ―ε° ΰƒ²xι 7A™OAœ–υΘ© ΞZΪϊΡ¨FΨί/‹_ό˜©/ D™ω!ύ,b圠Цc MΏ§3MEζδΠυhTd‘Λ t€ψ§Ι /+dm°–«ZεΏ,Π§ώsΏΡύ&[\Ψsυ3°JΓψΰ@Ζtυ»υŽι·ΩΪΪ·@ύΟΡj­ώ=Δ,γ ΁βU~=pQ–š'Aɟ4;ΥH 3μ½zώ¦σœU”Τ‘ϋ&σ€ΩQΜμ§8‘²κπ–©=Z$‡λ³€IσώΦRG54Σ“uσ«η“εžeHϋPή„Ijy“>Q, }€|,7Λ x3ΙSLέ+Gˆ§‘¦δα Ύ―bίΥΟ]VΒ5τ~U&½k£`ςW7 Ζ_²Ή‘γ4΄αu%7ί7OTVedΓό-iΗ9a”0ϋΈξHΆFήΔ5π(ή jB΄ΒΫt’j·X)J&qΩ1d2ΤΎ$™D§ςTΚQΥekLιξS™\ΙSμζ(9,?]νy띭φOΆώΘ°u Ψ  ˜ϋkΡiβ?{–ΩΩoΆzύ§χpμD Žη S―ήU“Œ„δ“ͺ /·2ΗΓο_ E xθ7Ε›xͺΈΞΖ‡~’yΈHYX”ΧΥ…A5―™O>„’]9Κ`χh_ʎ΄‘αΥ"Ν3 "•C5VςNƒΩZεLρŸζ˜0ώ—! '}‹ΌΚ―ζΝRjYύq}RλoYšeύ_φœ\?(|Δ|'²„Ϋ˜Λ Fd|š%ΐ ‹²εεήٍ"”oΎ—o‚‚6J―©Ε™ς=Β¬U›ϋLpΏ†8Bž2Α˜ΩαΞ|MΕ JΉp’ΗσΝ’1Yβ{©ΰlω^ώΠ27ζ ‚ Τ]l3\ξœτ°dˆΟYψXd–7?»–Lsmψvπ ₯Β Ώ$ΞhaS·φvn ύΰ:Ό,Ό6qM/Ν’šΞε_\aΖΡdœ4?½JΨ-ό­ wΨΰ>Ω ¨#k”%r<ΑΧI‘-vjXω.Ή]•™W·2xΩΆπT‘σ}  κό–΄|„ŸΌΐυΓ‚ίk-`Ϊd|ςtΎς ΚΌŒω‚Ζ₯ζ–ŠσΤ:o:V3wΠΔ$Ί'W­E ¨ͺͺ‰ΞζεΊ•Δ’Z]203ίΗΤζ±’…<RΡβwΩ΄h…-_³fIΫτNUε₯ΤΥ(6ιΤΘΊΔPΰηSΓ?Wχmυ•α.><τ;‚;*vΛͺ²:UyΑlΗ«ΞleΎsΈ£|ίΖn€€`§`η9‰#άPαfxί ό'εΉͺGδΓR›ύ?jb€}όΊλόλoOγ[oν-λ[kο ώ?―*­©€Ί]—κφ¨Rέώ†ΣcšΏεΏ£λ'\:&‰‚Κ*€Ϊς?p­7•³w΄ώŸAώ·Υ`GZ“›μ½†;ς,θˆ5ͺσDΨdΛI,iv%rύ‡SvV%η7І»ͺ5wUHιΜΦρδΏͺ Π>ωŸ{KηΞΆώ₯ΰPΪτΞαυΥωŸ ΤeH³°”δψxTϊ+mbζά|πJiΞbσ‚’H1›@=νfήωβλ·\nV5yΈ+lŽ{y\$RABγ€‘Κ ήi‘J @ϋ³Χς6ύŸ‡ΓT9ZΦίήΩlύ‡΅ΡωŸ ԜΠχZ2 Yρ}9 8 ‚ΜΏV(ι·qΏ|¨nq6&$Ρvp—ˆZ >4–ΚyꞀ*ΘQiΟOhΘW‘Χ’ρΩK Όjb9m5™½0#£Ύ2«cΜWNž=Pϊ_‘¨WόGγΏ™βΤ+   Έ Y» ½ώ;ψ§^ιρί@ŸΝΠ(| ‡ €†`)ωΨ‹‚\ςΆLπNΙΰΤ'Λy4ΒόΝvΐO'qwΛ»–O½–XΟni¬]3Y―‰Rσσ<,cό#ΘfκΑ?Œl&-DΦ?KΦƒ`ό·[λώ_‹Xβ₯ζl‹AH―voιόŸΙρίph71,cSUΥφγΖg6πΕριp4oF&ΠΞcλγό)ju¬¦•ΓA=τv·Σς²υ/ς½^ύ45_"€Ά xώ?k­γ3ψšΊύΠΝ>1ύ7βl.Ό;GΠTiΐohyο‡Κι!Ύ¨ZΨ‡4’ΓV₯#J­›"Žγ'FN“λGΟί!0仁γ@ψ§οϊ§οŒ³›žΡŸθ JύηύŽΟYY₯τΡψύ‘ΐ'7ήΎ3Ό8Κ\?J UC§)ͺ‰U㬻ΰϋΦΠ•Hώ«lΨ'w­λ?¦[{Ε:ωΎ‡>qρ_ƒ6b(θ‹ Ϊβ?φ–‰μΧ:wύο%qš€ υ3aZ©ΈώŸ’ΦΗ8Ψ,Bΰ¦@„~βϊ&œ,ΞQHζˆ‰α“wΉΫp― N9.Κ€Wη‘ά‚_vε&3½ή:€€Έv€3(eŠψk±¨ ₯ΈςYXΑ0jœ)ŒΧTΎΏ:‰,½—1~δ&o&ԝ‘Λ$+±Gt*mψοG…;νθ{§©εήw Νδ!–ξΠ[ΈΚw ‡c‘‡¨gSΡ χ#Δ“Ο6V$_‚;πu% γ$ΖΰL€κ+£FQϊB;ͺ>˜ώο‹ ϋΔφ{έq²υΏχ@ΏyˆΔL₯¨Νƒ}=t]7ώcΣA$θϋ]wθU¨Βν"ΫY°c.°REMHξ±ͺNΗPΠ‘(TΨεX«ζ(:€ϊψ6[νŸq€—-ΤΖςX›Γψ,KγΏEθ:"δ½”>AKΨΒdωΈ/HK’= 8ΐΛJε±)9e˜>²|ψš½&ξ₯lmλ,-;ΈΓ„ΞbA₯>'?ΐΟή7n²}φ=<ƒr²'ζsα†#φΥލڑ°ω?‘ύΏ_ouώη λO1OΒ²Y[;Άώ§ρίυΏDlf€¨ Ώ€ΌWUΉ\žIIξO―οm,μ$ΠΪ@@’²†Li!°iOžQ’?Σ΅EΞ€Ξ8έ ™’€XωΚ²‘"ΞώQ‚j B]RQ*rJΪKNx’{T φu¦Ν}%ϊQ !’ϊ꽏Μ=t ’χ_-XvΠΘXŒˆζγ²uώΧdλόζώq—―?ώ·¦ώΛΪοuόoψŸκΪ‰LQ“6Υ«·@ΗΑ­%kώά‰Ε6p(ΚΠ‰ŠόiθΕ±΄šjρΫΩ€d‹σyΤD²ΌD­6GΧf\Ε Σ~{βjωw©7ΣR‡a΅q’&˜»‹υj-Φ`šτ’Sΰ5ΰκΫ}‹w-cυΨj耕4Τζ »ΥhφD©€G°(*sφήl·‘,Ϋ|Ο―pψ}¬dΔ™‡~jt‘Έ@£ϋ₯^Βέy]•$ኯƒŒ6Ρ(#«ΠUy]43Qv¦½ΧžΦώΫ¦ψ3ώ[²ςγΓψŸ[ωwόχ/[Hέƒύyτ?§ώ³WΑ•ύΫώϋŸ§π΄~ޜ―Π쐇§²α(θΫ ιί΅9 άγΚζ0!―ςΊΦVΥH.€ΉψZ’7§φόϋΓ!]°rΏ=nβμOίj ι°]ŸΜΧ¬ρώ?ŸYόΣπΤ?ηMj½4Ύφό ŠBo§Ύ¦΄e0a^m+•Σϊ5%ί^_^ή:hqχϊτ„”έe:!;–ΔτšdlPΫφυω™€3Τξ5-Ό:gΨοτ΄³.dΙKΒΈb•7Ε‘˜‘ΒטΣΖιΰΛ¦ΏsΥk ~Έ4πδγΊΓ:zΈτυ.hŠf;iΆσ—}ΨύςΣ^ΑM?ϋ`ι1Τ•ΛkιΏϋό[Φ`Φ- ς?©^O‘ΔίόŸύ?’™5ΦVRΊΟim;”4)½‰›νζ˜\ΰιΪ΄*=‘.%ύΔϋΊ¨Ÿ‡p@ sU±ΠΔn²…Ž£ω₯Α\ ΌΔλξ@IυσΚ먈Χ`·Έό_|@ iώŽό;֟χ_¬™α²―ξϋοΠ=kΏ―ω»ΦχvŸΦδw5*UΉ7NΓ—ςόmύ\ώ‘iΩƒϋ?©–<ΘΕώΞώΛΦNίΩλΟ­]ωΟ¬ό»ώ―‘ηΜ‡ίώYΌyόύΰ}₯£§ςΛA‚ώγ ώϋ^Φ_yώρύ=^8rˆ…έμw”ίΉ©[5Ό¦²ο\$λjϋ’:—ΫŒl§;‡|ƒΈή^Rχβζ•œy«sΔόςφ‘Λhψκ―Oαωmυ£ΌνV°« ώμ‘iΡε³Ϋ°ϋΎΒ/δΗύφ\βλ·VκFη.Ε†7έ>7·ΈΌάκzqyγXE?tρΧ£κΌΌwκ_6xυ ,/o=ΏRp» ΏΌΥKΑνέώωΦΉFεΠ%OΔΥ½EοΠ»Ίƒ¦?π“‘sοœbΉΌ~zΟΈΌΥIη9ίl*.>Κ› ν€ξ­ΗM Tyq1-Νmμ'jˆ5vγΧSVΒθΟeί” „œ›½ˆCιDŸ3ϊ;ΐ.F–πΨyhWp^ΚEράϋ;ΰ”Χ]οΒ―ηŸV—'ϊόΐ.Τ²[m_[w/R‡†..7ζ;Θθ_ΉΨ4rΎL‘ηM>?χžί’γ*n6{μœπςςΎ΅Ί 0”\„?΄-iUٍ=ΆΩŽίYE,Πχ§°ύ1ρΜΠYz¬=Ω]9xϊό+Ι•o‡ε^H!ΊO ~Ο‘Έgσ}uΞI3ηAμϊ·0?›?Vψ‹/ίϋ7{₯:WŸθ_ΉΕΔoŸ›€„ΥΣλ‘8nΖο΄ςΘpr‡1l¬^ώtγύ{Βκ)ΌŒ?ΌΖˆ6璏ΉΟύΊ{{ή‡Ÿ½Η;ΕEΣ·/«†Ÿ=œ€\©uίδτcωβe·Βa‡³½ϊ8$&ΔΜΥΗΆ%δΥΫ5QŒΏλΡΗΟ™(}•:τ;E”Γ:γοΌ<†·©gaͺB½RB" ΊΙρ΅σ―o38Œν"Υ±';ΏΩΞx?§\Δ‘λΏ>ύNάΊCττΔKΨbΠε±ŽΞOž§(@zwΧΫ‰›SΧωυΔ<* ކOPz™”ΐαΓζyμΑs*βΰύυvκnΓB8zηΧϊϊ<-Nޝ#|š§Ÿ ‡oA`>°5[χ~ q=tμڏ@~[cΦ~Κsž~tLp΅€½φ'ΛKϋrν©ζHΏlΛώΚ[Οu Ζ΅Η―mΦγo<†8y€t&jqA>vδͺΎχφ7«αptGuοΙS±ίΨύkoJΜέ½ηςΐξέKφΐ”;~)ωΆΎF~ϋ,“ή§M~ΎKiyειώhi;ύίk«Η#Κ  ‰‰GwdZ?ΕΗΡGŽΆΖτχΈF)ŠXσ`T<Ύ΅ ”ξΣΥ¬sžœ~…Ffΐ‘φm:_Έ6υLω ½Ό~žzδθ žzδυy½Ώ°ψ;]A/Cγ£s–»•Πή{`Š£γττLζ–d9Z™Ώž*-:—±Χšωλήΐ·ξ6P)ϋξ όΫΆΰN—ΰΝ©™ΰρβω{ρΘ@q₯αΑ[ΗυγzΦΎ±©5}o­ϋXωΘιφ‘#;°κκ`Bwο<Ώηxεεuχ}Υq oK†―“ρFnώN•η{ί_k},ΏΆŽΑιRgέO—i³v―M ϋ½₯O£ @½lžΙ}πnξ?oφ0›₯u5ρ›}pσoχβΥί{qυ;Ώr_ ήj]8γΑ‹γzZλΣλcϋPn¬z}9ώΣ–dΓt\TΊ Α«}7Cϋώξυ©{yύΌ{)iΰ]«<>ΎΥu³‘·?{o±ƒ₯χϊοΡ*i½3ώ–­’Ώή‹Nς#w{–ίXΙΠρφ;ak5..tνd ν‡xݝ°cξΑθ~ύσΟχέ4x³)ybχGΨ>υοψG‡/―ΗrφW^š[ομž6?ΚΘHή @O·Ϊ[’ θŸψνψ/Οϋ?ώΟνΛ©Ωρ)"°ή5=πθŒc>Λ—ΗυneSΏ4fήΊΠέ°§ˆιSσάWΰεόzΰ}kB±"ήγλ/_ώΗwXΞ_N_ΌϋΎy}Μψ»Ο…λg¬LΖ’Ώu[ώυΊή–/§j­sωΨζ|ατέ7o{ψ’?Κ—?Βσώ Μύ—? ²ΏΟ²X֏ς{:4οκπ›c΄ΜAυ½HEγάΉ°eΆhJ[·b§όεθx¦€™ψJ ΏϋνkiέoΠAχξ|ω?ht_yE‰TNCώ°/»ΝAΎόrtόνΙ]iζ_ήΏ6—ί9Ϊu§ς|ΗκkM9GςοlΥζ<ΒZϋλσ?΄΅ZεόσWόχI@s έ,ώ ―ϋ Pεšβ$o_ώχ hRΜ»'ψ?χτ(ΜΉ/„Σ›**‚;8³―@AM‚άσ·_ZnR᜘χΫ95ξ?Ÿ6`*9ΏΜ†γΔλ{p“Π•mω|Ή}ϋoEo[¬ίΑϋ~€wΏ¬7«¦ΚKϊyF_Q‹’.©΄³Μ&•υJ «d ‘˜δœΠFyWŒ’ά2WMI „Ρ\gI5‹οˆLαύηΫ™:λ&lϋ΅©"< Ɂαύφ™ί}(ΔlΎ6Ό_£―_ιΚξ%4Zk³mΊ#eςπ5XοwL'ω:ΐ…\§yj~xά~y*ός΅Cρ~νΥψځFνΟ«KOτ‘€£ωιΔz<1-“όζYlQ7Ό~ΑΨάτΊ—5WO1‡e'V–C΅κψ«ηΌ4“έoRhέκAλκDŽw$[3œ ηLUάψ˜ KΪy•­.Φ—m\·Ea«λ’t΅ƒωmύΤΰ…ΡαΞμζξŠ₯±0‚qΓTr6ςΒxΜ2{W]ΦΩWSŒŽλβRΙQρZSŠ%ͺX΅—AκΪ€½|!ޞ‹e‘‹Ώ»­ΙλŒ7ސ1ψ/Š(Έ•Μ•R"σUdc…Λœ©Xd‘άs“’U™k%˜”|xUH<―Σ*l·ανK³›ΤΔ"UΛΕ0 ›E‡ιœ’ž—Κ™1!… x±,G{H_½)^¦"UυAΙb³ΐ±ΐ° ™6ΓΓΔ‹―v›z8mψπΌ>HΎυΛԏwυ-u9IάβcΦΒΊ¨kˆ1β|)*¬GMΤ\‚Ι{ζ\aΑkό/β€ag\ΠΦu9ŒŒωΰykVνb΄ψρ!χυ…ώRτ5ξ‘ΐEΓΡ59!ΝΏψ±2$›$uψ0V[œwΨwFŠL.\λˆ'2 V¨Ί€‘πN©ζλmΰ|yΑQ”‘š„Sa£Σ2`Λy+τ~ŽB: Ν’L–\)ΐΊ “Q±¬‘]ΌυqpώX?‡—u#'όνΛΔΕβ 4kέmI,UεTš;‰-—а1c¨@ΒΑK²ͺ²ιg³ψΤ(  NΥβ[ΡE‘²9κ³U§‡ ‡ )lΞ6Ι<Γζ,ͺŠΐ½ΌK.Χh|‚I*‡’œuΤvΚ*ΪΖ5ΩΎέ] bd"_Jι βΈΝڊXΖ –‰₯,#ηΐΌb'xΞΎΚh΄Μ"*mόΨaΫ& ½t–H,~Τ2¬žl€$‡£Ζƒ/Ϊ²˜’ ΗB#3œΑ •–•g6Te ²>gœI+Gίθϋ|Ό_h–…ΧΥ₯¨³γͺD£LpF&l'€‘j…•ΗμoBv)‘X…ΘsV ΟΆ!ŸΑΆΤf0KΫ¦8ψ‚4O‘6U«!‹«u!˜N(5<€”΄ΤΙ;€ I2ΓrΦJM½?U]ΎΏ^܊ΨΞ’&£3N·*Άj‘aΚD-"«²d ¬JΖjξ1œτ°v3.޽nWΆϋ‡πB₯4ε_}΄Ό‘‰ D%Χ€±hΞ•±6JY#t(ν(X(8ΎŽ;nEΦ>x OΦͺZσθ8(9ƒͺ¨ΒSo/->cY–₯H§VψꐢJΞYœ(“tc»+s˜’.H-±½NΓfWk«υΣΛΑŸU_›€ς©Jε·λ£?όξ½§ H­\t₯&_]q@@ŒπKYNi8 ξ)υΑzΟL_.BχϋΜ°Σκ)€νF|iΌ8™ƒ½nφ₯Ήΰ&ηΫsσΙͺk3BιφϋžΓNΉΕχ¬Mc•+œAβ%#K%₯ΑΰΊ•t­Rg Α —ΡKm!0λέ'cΏyZ§Cδπξ;#+BWΙ@ξ‹LYh‚βLζ.c…ΖΈSP€&U©–dΠ/ΠηΓ`δyύ³λ© Βφϋ.> 7Π²£φQϊXΈ³ h‚§ γΖ{eƒ9KXkΕ‡  ZΓUγΰpΊ78κοDˆ΄_…xπ:=cΊeΰ―ϋMͺίzΘ`i€HΦqYW>Ο°`‘&Wb`ΕVi`;˜$]-"˘V²a« Κ¨0"ΡίρgwΗκ₯±ΗŠYΓXUEn‘ T¬’θ‹φ°»-ΰMuBBΘ•¨½„R- !D©`4ŒΘσ³ί½qœΥo«uύrθZs±˜OληυŸ›Ÿλc0b«€£{―ŸVΉiΗϋΝaŠΆΘόη?ΞίΥΚw»ˆmΆΗœΟζS+”ρ^λ:ωΈ¬4>\ΚόΪκπύώy¨"ψp理°κ¦Π~½ΰ‘ ΐ Fƒ1ο)“_ΫΕL_G+/Ώφ‹-OΚόω:H4Κ₯j’4ΎiNθβσλΣCz9Μ~=³œβ?λgšƒσ½Gι§ύqzθ=ξυΞ5zψ8”ωυzτΘ;ΪΘajSώώΣ x½_ 0ΫργΣα‡?ΒφεκΖ=σ±&RyΓ^μξΫχΝτ^ΉXρ·—“GυbEGΦfp1ήηύΪtξΚκgOνΉΕ*-8¬™‘€…Ε5Ήb±Di2ΙΗμΐ;L©d8L’κmΖοΐfŒ_ΗߞXo(j}}И‡`7Y”ΘJvx¦•”—δt00k-Ζ¨Š\Βζ^Ζt1Ζ {ΞΫ²ρ·[Ζ·<#Οx-!iXˆ F:,ΘͺmΝ)ηhuUΎdΓ₯2@–<,¬’5@ŒcbΤΦ:Ό~ΪχQΥδθ<%Η!lΡPΓ^Ό)9€¬΄“<±L‘Νˆg‚&‹Θΐ»0ŒΉXIVtΜζzp&Dςbs€)ΌŽ"S«V@DdΚ›B'E— €n¬ΑDŸUJ™kΟΓ0€he,|_γΓv3΅ΙJϊ.ΕέCXXΒήΔ$4ΆVΡ)zΓͺŒέ€ N»Oΐό![1DT΅–k–₯u2ωUβϊΉ) ½―rq·VδUQδŒ[ΐV!l²„(Κςd3 φI š’Š°adY­*U˜39'ŠήO¬Σo£cΛύtν??JKΨ’–EH·hdŒ2WCq`nΈsΚ$‡%‰Ά† a³²lMρ8C G`βz_Γ·chΈό|9F†ιuV»·Γυn~}~‡0₯ό μσ}ψQώψ~2ηfΌ-PΣΐγχHτχΗςσΛΑg51χϋ¦˜ξήξ:S`οsΓ$N8ώkΧ{ QBΗjͺ‘Β f… "d ήEúꐡΟelκW’‰Ρυ‘fρS#•'Λ=pKϊƒYΙ΄†…”ƒώW!³ x(°l­w¬½€`X4^{WGυώikuέρ‹›¬•η"jq8Τ1q₯”Ύ΅0ΩΌζ•β­Π4QY―3ΉU GΠ Η%ύ—γο^.__άΑ‡ŠΉd ˜KQΠ/EήF•C…QBAΣ$ρ¦Ω oD&<:I…ααΪηΧ§ΙΝΥί[ά²tάΨy%’ƒι-`‚;ι’Ο9°ΘNJ„1n ώ«RΑΈ²XΛ( >E%Εp"O}}>ΤrΒFΚλΧ£©rΰψϊΗ۟Γ~„˜κλΡ₯·€W‰’XbS&]Ng‘‘3λŠeΐp֐‚rBψˆ=P™€0w^J6ŠEu} G‚ŒύBv΄VΎQιaLωb*Ήπ09ρa·~Κ=™ΚΟ/¬œ¬8!ΛXœ€B+V8N›ϋZU©1UgνBυΧΨ#:Υ‘§Τ?Ρ ηόσ”žχΔo@±‘‰iΨ€«ψ τΌν%V,-|A ¨“‚%™ Dl|α &€,§lx–z€άe’1κhσΖΒ3΍D{›Ό@Ra!b}Ά§[;θρΣKSI€“΄|v†β°LΉ©x&‡@5€IMΌ$©­†ΪΚN%αΩ[ηYUQ©(žc‹š5IβxbnK†Όψ–ž!²΄4Ε‘œΘΐPz»P–L€:Ηβ!j θBΥ€)ڝγ5κP­¬ϊΊ\ωΐ0—ΧθϊΞ$ i5Kž$Ε ¬ ψ=ΜΰH‘EXΎΞd/9¬ΌO"…±Œ©›Νη}ͺ-Κ›sώόd2ύˆ©νXt!^$Τχh’>g€π…s>{.Κmٟ•νˆCrΤ ‰±„ WΧΨφj³Ε]Kγ(X—[νGj‡νsގ˜³ŠΧΖKδ”½S€wθQΐ.ΰtO‘EXLβ.`h„\ΥR y lͺ QγΤ)\)Aσ™g«œsψŽbu,ύ ³"―υa[ςλΟ"[<•Ψk 0­QβΈKj#yΌf¬Fθ” T €&¬Ÿ!,₯*P»²†Ω:Ώˆ†Zπqj¨O/αqs1P kniΩIyI†\mšBVUsR0€mζ˜5B(QaΉRΉυΩλΟͺU‚“οJ’Α[zEΰ PH~SΖυ,iα΄RΊV­ηΞϋyΔΘrΖβ¨F”νΔz^¨yαˆ—ε• ͺ₯Κ©Φ»¦Ο ωoΡ΅W2ςiuBeΈGΗΡΎ™Ρ/‡ή@¦?j½Λˆ‚ωmz₯Wm–ΈΫW½=γC_َ?-±άC‹:½˜ŸY―ߟV-²·Ξš΅#W½€α ³~š’›'?½n/BkξW9<–«Ί>}lϊJ||χ=ˆΣςΖ—gόπζYuˆ oΪ׏μΌσΨ£CΈ6 -ΊΪΗno„ΐ·nτυΆ{₯C„xzτdψηυΒθΡb ) ½a"ztξP‡σ<¬μnκ'u‘1„,”3αύ­'tŠ­qβ}ž—KηΈZάΏΔ ?¬e™™w^i9Χ`KJΨ¦*3QJ)’δ"訴ΣΩe eΨάlLν-c©(i S<§LyάΆfΖΌMŠ3―­’I%ͺ²FΓ~©‘rΞX$‡ϊGβyι’φGΙΔEΥK ^<¨ηάΕ,£ ŽSa‡€"λ”ΛΑ[―*Ε‘αfΈ ΎxV«”œFm…‹½Ϊ/υΦG/^±š­†e+lGU„`.eœβQEWYΆ΅&ζ”Μ8i£¨š3)muTΉό‘υ!φˆΥΛcΨ“ ιιΕ³J„ ‘#3Uκγ€zεrΆIϋ"p=:JOΎΈˆΑ*&m.LΙjcŒ|pˆηΞΨύJ₯έ«Ix‹Σ·j~-ͺΗzεΈc0˜½S%Κ& VY&9€Λ΅Ίd4ΒαΒγγl ΐε’”σρ²5T@ψ)μv›?ϊ΅JwH€ΖN΅,ΊdaOSΪΏ—`>jΘΥ ι±ήΩο™2ͺΗa€Y]³cQ™ εθέυ3n––ύ*z%ρ‚ΖR*Νj²ϊ9ή‚J!F!χΆvζ!*œUY|₯ꍇΕg§8½ω•ˆRJ=dμβξ‚d|dπΕh…WY¦BžqΓ• "@ωΰ‚ΘZŠg§“AaΔ‚hΨΛυ_Τ,ώHϋ96Ά&[’&cΛΧΚ1KB/ m…°¦d–³Γ»'γ¬.I›,™σΥ AyIJ$ΙRβ՝œNΐŸ*Цδ恑-Υ)8O,z#tζ5IεξFEΛ­S™Š‰«SΖ—D±`Εm†n7ΞVΫa·πξ)<>žb~{žB”^?ΧiRœ4ωά}]²xΛ6E€Φω >ϊZΞΫϊnξwQΩ&€ώΪkτy,Y:ΣΥΟ+iΊ ξ\Z΅;Ά£‘«UQDFΛ₯†E £¬3Gώ(κκςŒŸλθϊ§°U'ΪΡQέέμ•vA]«6‹vϋC.iύΟήΞž“°ΛΚ­kx©έΰσ)GCΫΧuσλ@+ΩOΝvbσޟθpu Ωι ›σ’κiÞ{Π™«'{^²[>΅˜θ;―Ϋκ"{,<Ν?zU¨­n-_/»0Œ”NOΩŸ#εgεΣΟύ.,—Ρσ4[ώαv41ΟΗnΜ_ΌΖr¬ο8‰―.šg FkZ N?_Œl’φuVy+NεfΏy …ΏKαρE<^>υ :}ήΙ‹Og0?Ψl`’tΆωψŽ΅½~2#2κϋOyo­ŠΪζ[Ζ„Γ)e€GΆ4N‘° Όe_©Ό€!‘ΜφŠE<ŒˆΰR¦:ϊ…ᙃ <=Β+8γ½ζήξΦύ‡―₯–e)S2°51/ΧU―9–‰l4ΑΊΖ‡d %¦§ΣΦSUπaνΣζρΈ±Ίdtπ %w Ϋό6pS-p7p)ΕdˆαΕΕΌ,ΜYV-ȍ™Ζώ¨°&CT.Ψ'Γ:κΞΊω€3 δΓΨWy]kΟΨZΊ|KcψΒ°P“g>F–™6Kμ1nΟ£VS Η‰μ40Ά¬ΜΪRŠW0Ός|ΘJΓ)[<ΧΟΣ²TA11GμψyVοΛ^Γ·†οϋΙf‹ζ“ΝLΫhΣΜΝ?zoLΎΚcΖ8Ή,/αW―/Ω04ϋ(«FΗw`Q؏‘—ΟgŒ΄oϋ:Ϊ'η3,αH=q1!Wζ‡sk.Π Μ†χΖς·X—Έ₯Ϋ₯θk»ΪΖψΥ‡Α$Ά)Žˆ6GΔh·ΗeΗǁ^\“g§³ͺ3ORηψΏΨ―³·ΰΔ¬mΛύΣlJδ˜6Q*Η*‘n‰ΚmΙ<Έp«e–'›4ΥJjž5³…SžΎHN›0μ( σΐΓ’ —³Ÿœlο&HsΠ`,>μΦ–Ώ\ Σ"’ξ—vΞUνπ‰’‡ΰXdFH"—’dMΉ9"TUΌ#štr°Ji΅‘H]’ΊΚ₯}(ιοTψŸΆνŒ)8ώώέ'Βp] ζ2"hŽδ<·UTb:5ž’8¬«Aβ©Μ‚f’sM,XΨq$sμ[ΩFρε€R‡6SV(†τό“<₯pm–κs/²¦—ηφΩδb‰/FˆT½ ™Ϋ&sΙ”TŒ'l)*5ρpU²¨BC“¬j”‡₯W_{οZHΓΝΫβƒR—Β©έ…—Ό¦š²ΦΑzƒΧNFΙβ΄7΅R%Ψ?>:‰ηmd[κ‰ωϊœέτΊY‹'˜Xα"% ŒoŠδε”ΘeΔ"Γ•‘…‚&5EŒ¦…ΐz0l_£X0#=.ρΞδquΏΝz/~B G,ίο@ΐζƒ’ξ1LΚHl¦J])σ,1<‚u% Ν΄P&ea)ŒΫ|4ςεu©­γγέɁ\(1Ξ…Lζdr’ΐ*τVΆΒPL š«@aUj—Γ%7–vˆ„‘κΦ܁Ο:u,^騘ΨIΧ.Ήβ=‰ιΰ³g"ΕQΧΡΝ]osoܟμΠmx;bδρηΫnδ‡μοΦ@Cϋ“GΞϋ™!£σ8!šPΒΠιYΈj4ΰBlKm#ŒΧ₯58ίAωΜ*‡φ—€β1{KŽ'μXωΐ3v4%– οΧσNœ‘{.ΧΆ ‚–Ζ‡… QKΘ%Ζ!ΒΈQ>Uθ_νŒt<¨©ΗLΔΠ|ˆ€Κ 'ΪE¦sΖΆφy$εωΈcΫ»ΡOŸΥΝnϋ,ηΛ3»U؁hκ2-tΔκVQRz‚‘ž…˜s¬HGH X#; @U£΅Ω±9©5žΥ…‹μ|5—½–Ξ΅ς²Iί;ΧπTοΉSΔχΪT† υςΘΝ ‘Β!·9₯¬²$D\βb2 ©`ΓΩ€ΪEJ¬‡!›~ΚQέ:₯³'ΰ0Λχζ82JλΔ€||eYPΆ§ζΡ3—uΒ ^uŠ …ΙΫS+aρ’2Ξ³˜3ΰϊ­ΓΪ'³§δπΛ],Ώ|2žSDWβ1”f`TΉŽΒΫTW}ΔF Œν©΅…κΤRΚT±IΔGwΔ +Γ¦Φέ1b—6/εΫkΨζ9su8|χςgΤͺHΒ*Χ‘ˆ5c’”;,ƒ¦¨)ΗΜΉΟ‰K!dήτ†cŸQΘΞXmξvzvOΟβ –+P_ ²Α5μ|Π­0ψTΚ%)’K°ΐ,sα;9DΌ¦žWςβ†8Κ/ΆΘθ4Ό>§οowΙYX”ώo]*Q`6’τΒZ$J_‘DΨξ Φ‡±"Β Oͺ Sν¨ΙqβDλw-žΛ―€‚Ήš+ηδqΣΪΐvaΖε\aϊ)‡‘θΉ«Εa[9“cΡσDD‹z^§8•G3^…ώ#ΓΏC£Bκ [³Γ%I]R$$œ³:ZXœκί(?ϊqJ‘³σ";ξE„ύ$%K0·d°ΞmLIΦ@·bsιφ°Ω80SNJGI> ΐεΒ5»‘”kΣPC„- ³š\Θ’NZš2œΉOA Œ`uΞjYο7νΫλ¬ΔŠΣ/ί½ED‘¨_£§Έz%~.…Eg±\&grԐΰΪj¬—q‚9“”kdLž}¨`κq&-ίwΆmΛZU‹ψχTz ₯λcIm)Hn˜‘žƒRΖ2[Fh‚5˜ΕΐS‡ˆ/Nοž8iΪ$±(Zξ\β ²¨šΰa§›\¨Ε4‚ωX±NΡ(λ-Ή&²Bx²•ΛΜ`Θ «Η½m[E%KΡX4X!K9P22.ΘΟu0οΙŚ‹ΐλJ%r`V'gΉw•]%†oΡnϊ£²₯΅#„δihΥΎΠC2νΛΧ?Λvsˆ7Μ_»ο]RΩ€K-NJK»ˆšœf€ͺβŒqg cΜx}©¦§Ždx/ˆ$a{Ewž»σ—CΩD9J¨NΊΰθ\²3ά»ώ;°Ϊπ²ŠTa0+l‡9ˆ«JuΣ…‡ ˜ΆNΚHIE‡K/%-―X&α{6ΩUwQŽδ&ήγ«ΒΛΛgRˆf₯¦ά«χΚμ~%c³ΠIyώeΟω±΅3Wη6χΘεlξήΑeΑ“ ΒgŽQ‡>η₯φ΄‚ΞΣYˆˆs-«Ά<©ŠςPΤ$)Ž”΅*ύ)ωϋdt~{}yywΞv2lήY_ΜQΎ;aηΊχs9…ωον>„Tt–ΪoGβHA%―'«XXλ¦[^δ—Β+1¨ …MΤ?Α°lό«J«O£ŒRΧL₯ρ_9―‡ό›Ηυx2Ξό#J‚²Ν?{6ρΧ2κn/\Έ—`κυή=hhF{™ρύϊœΫ>ΝF—³;‰΅[’}=»ι’Μg-ΤM“0g;Θ©¨mκg5f·¦ζζ|·ι·gΔ6n˜θ,όzEΑ]$–›·uc_­·>ά©7<Ξ_w³‰OeγΡt­Ά/©;ϋ·%žλg^žΛeΩX‘Ω/r;«³Σ~mϊόm·/ΟP›_މvΝΝmH§ ΌΰΏn°»Ϊςaf¦γxεWKΝ)ΰϊpςς`αώa]θΟν.ΉRΣ'»ΎU|/ κεπΞθδΤžΡ™[ΎμVίAω %ώψdΎϊE φ ·ζΘκjΌŽΥ;ΒΑyΦz?r˜φ‰œλ!QΣΥ’φvύΜ ZΗ­Θ€¨Θ“½€=T„­ΣΓ‘έφωύ;ΉΘIt|ߚ¸ζΓρyΊΎ_N£ΏYRNˆσ₯Ί7"o+ΥnΗφCΩWμ£οΪm³8’—qͺρk_Ϊ–ϊXYΌτΚϋMπ³€žπΉ@’jΩΓΫε;=ΒΨ‘2πΫΐιTIηΗι…;Βην)Ϋ`ŽC£™Z*2Ω­jΩ§οŸwjt ΪΗPΐ…jŸ* ŸW ―©μvΜ©Ί(lΎ₯ΏgŽΜκ>;}¨n4IήχΜy‹kκΙχΟ+gν’Ύύ”f6jE_φWνΓν‘ά±ω°I§„Κx /§Owaq§Σί%gŠδ]hΣGΟ=ύέz﷞B½ k»ΨύJωNυφ<)2ΰψΌˆξWRήnς­ŸΣγ+ε ·^οφόNNΒλŸήΫ„žΏ’q‹ sxκœZ~ΛΛΜ—η €βυρΌθ#«ςŽyί‹@Gλ/ηžξρ.ζ'Ϋr’sΌ±yWh„ΧΗ}O?}¨gωω‹O‚{!₯q¦Ϋ%”ŸμDΈB/πc¬Ž‡=} y”―xcz¨Q’†°ί=@ΐl­ яζυΤ6Ύπ!~‚$ƒΒ“ξΝQ;|ˆ]εΆψ]¦=(2n‘ίΠεΎS*z„υ²“+ήD †½Uγε 'ͺEyf5Ε~Ύ]q] `Ξνn„—ν¦όL_¬©μ‰ΨOιζv8ώsυΉ ½₯ ύ£•η3„κMMΕ/•ΩΒNπΕ‰₯†jΜΛ{;WΒΈΒΎ°›>I‰φ)΅ώN…0‡ςi:ΔτaΕ>΅i(X3 Ξo`°<ζDβυΦϊ ωO5W]κΣ\ ³,ΣσΌI/̊-ΒΈX°Y#Žύ}.σΙSr0μRMŠΣYΪtjZpŽΈιN¨…Ψ oeάλ*=§ΠΩ½Ό6:x.Μ§Ιν>ˆ ocŽi‚IζΉkhr‚ie΅Κi‘ƒηαp³GaΔ]7έχμ΄)†C ·v@]:žpά­)ndNyHη„Ή _w%―ή·ΙχΝnυt%ŽΡχςzMϊ΄‚ΉΗŸW»Χ%ΉŽεΪnj™qχΝυ—, [χ`Λό>RΈ{%π3d%N.ΖZ~άtιv!ξ2Œ-Θ6τΞ`(’\έΌΖΥύ±,oŒl·ΫK‡ΉψŽQ>―s±Δρλ@’α™ΊNWΫϋΈ T[ΐτνqZ·πΪQ€ϊ!Όwαα˜22΅5ήkOfΕΕΞ&Ζ€μ:ϊ:’pFΜμβν>­’ήίmκoNHΈϊ~.dοηx’GeλΥsϋi‡ΑσόΚ€’__.NDΟσyD±ΗΨ­OLΖΔ_ΔΣ8¬(? '‰oτDœτν•§Ζι~Ά’Η₯ϊ5φθξ^πρdnːš/œ―0»w$φΤ‘θΡ‹ί¦…ΕΝ†βMΒε/ |’ψ|Œϋs’ί| \Iο§Ÿ/7•’ΟΕ‘/aK ίqΰνM³/ΣόΨ4F~,-»BΪ~{VήΫTγ΅a:oΰοά)ŸΘXžz―Ζ­ϊΈ~ZΟoq(~j½¬Ÿižώ«€ύΤN›N yυm‘Υξ# HP5Γ‰ό―qν/Ι‹Ότ纏χ}ΫΣ8΄—ΈaϋΜΰ;›ƒ™)l1Ο‡{[1Γη$ωXΉK―6vΊ½­~žΛm^χŽκΌΙ#z5/υv8=τχ>±[fr3βΗύώY³§λ’›[VpwΏΙJš  g'ατsΑΔμνΠ`\’-v·:ާ_ζ„₯w/Π<› ΰϘb½5½%€zKzΘΌŒοC矏‚ͺ‡ιMŸdœq Cξsƒ‘©τίkxj&Οoυ9‡Ξ`ΨcςοΆEΐ'aέ,1‰γ&ν‡#pM[γ₯βρJ³!τ₯ΑΠ£ΌaÌ$ΆπχμaaΕη"ΠΓ"7Z;s`J{hŸ­ωHOΐΡφ~-U3žzτP ͺω~¦N[œYεΏη9νcΉθ—­g¨ΜN l--y~6l›'ΛΧπΟh 9gE―΄vΨ:ξ‘eͺ0a`:±¨Οƒ1†O.ά-).WΚ/[]>„o'tΪ I… ³ΡΤ±’ξ+ͺ³ΪŒŠ™ϋ¦#Ξ8)Σ"mδt³άπητD΄ ‘Ϊ[Χφαg’ΎΟΨrtR―ξ°ε˜ZΈSύ τͺοξc›ιD™8Π7Tit«Έn¬ΞκΙ―FΕίX¦–ξΨψC|/WΉ?bΤ\«O'βΜ‰JρGβŠΥ*m›kuήrήLύηsSОίCΒySΉΌΖ•pϊ νLnό΄".aΠΊ΄{{ή‡Α½½όŽαΜnόΩxξΩΡe?€¬@Μ’ώE©~–ΰŸΒ•XΫpŽέycS»η.6Η”lγ]Ω·ŠPŠ:Θx£ΤO}«τΞFΰ!ƒ#†νΗτΫ2φޘ·ώΖςυ‰­‚Ρ~ΊΆ5l9_–8} )pΌ¬υ3ι‚PΖΓΖΝΝ ώτρχ°]ŸΣ>Y@5½σjfψδ–xwΝέΙƒ>μ_λ…σρί‡wΤ’MšO_ηO³}βv―OQŒδ2¦p[ε-c:{Ιξέ\ •b5ΞΫ¨…^ηZΉ΄©$ζKͺ20]UΝΈšm)sν΄bR)_¬βή}AΏςς―/«U¨`eΤ<{Ζ|R ƒ©‘:›%ΦJ₯“ΗS±ͺœdΰƒ΄LŠ€n<5°O'ͺί"aqΦΔkUΘ*΅Γ ΄«ΞE‘Όf–Wα2—&Ι35m«Α)ΙpKŠ`Y¬u€AΖEΧr1=H"χΊ{™*3K.9«…δ’zΛe©Yb-+QΗG_Ζζ XHn½p’XΑŠ΅Ly­rΎ©Β-#υΛwΩ“9–9s,h‹"VK6C)L{ΈΞ"Jpθ˜pR›«LΤQzΕά0at€G šns±xQΓ³ΆˆΒ˜ŠQpα4g!ϋβ²1$¦ΖtJΨ«ΦSΓ€lytQΗ:ƒρ₯“¨κ+3žεv΄‚$Ζ¨krBq§BrRŽτΐθ5¬iΖ³{;ŽizΨηΗξένS•˜W*©Z˜ΘΌΪx°ΩΕ£©X|σφ6TQ[»P?γ„Ž*ί²ό'Λxξςο¨ήγ)>~¨Rυd”ƒ…''ΗW±Σ—ό‰œΊE‰(«NIΖΝ•υφƒΤ»D}°Ίbbιޘw™Um5€–±Ζ{i«Œ§ΔŠΑU)G­RDΒy(^ˆR|Ι±¨U²i”™γΐφαε½πάMΉρFÐs-Ή "³o`—μπΉk½Γ²k‚λό3μsrΞuΉανάπJpSͺ ¬  mΠ“N α]qN³¨‘E”} L:K-Ψ΅7XφT[ylπξΊΛΕ΅$΅ ΐ'Ψ‹Μ9Gͺ›§j™+ΖHm£ …'*Ζe…²2œz:Ήj³»"ή.Χp³{xYΏœύζ'ιϋ!udύŽώϋήα]šή–1AKœέ¨ N$­uvΒθ}ΦIˆΔxΖ<@ΦK@5mΜ>‚ΛMnϊΡ²Χߞω―Žτ―l“γ1萸%ŸΊDύͺ žJ-.d&АΎΘl’GVy4nΐr ²-Œdr ŸΦrFe+ή| ―\υΪƒ—;Ε,nΎλ²ΒiHΠυ„±bqϊuΦAc†bνV2™΅ΧΞp!]₯&wΕ+=ΦΗs‰ω0άΞB.ήΣ,ΰhgαJV‰ ΛΞUνpU:²~y°Lzη„ Ήh?*L.eΜ©±ωΌ jχέύcK;λ,ν…(…e*{ΌρAkn\εΥΪ’)_BΥd©ν,9'΅υF„PWLά›,œϊ‡^rΏCτXb%ƒg.be…–.ΰΥdΡ>˜’ŠΠΜa‘aΉfμνlͺM\›(SLΦ£dΐΟ’γzί'7ΛΑ†(aWslR&rQN•™LVr“Φ’€¨Ά*Χ¬‚2v8·2ž Sωζ!άAάxW‚ͺ!Ε’,;§₯bAοyP*Ή`”6B1«N£Ι‚WηŒsEDγΗΒTυSτφXϊυS–‘P„’pV‹7ΩfGΉ]%r[E2ΞƈcΝU’2κΘ…CcfσR6IQÁžγXOληυŸ›Ÿλ)ŸA}ώ½7 vρd_ ”…Λ²b₯ŒΟΨw>TBΆΙ9VDB\Ε‡tŽ`t"ρ±E(_{ΤιΛ' US₯τ%ΊΣ"e‘‚uλšƒƒt+5H—BŠFΉ‚iœ6YΙΩ-γp6ΙΕV‡πβΔZ =έδ‹'ψ±Θ„pŠsΓ„‘:¨ό`kΒdΛ°ή3E«eq>š€…†ΦKŠΥͺŠγ‹χ­ί#ς t!CΕ‰&iΈι˜d6=iσΣκ½ΕΚασ©ˆqΠ–ωαvDλχ|’”όρη·=>#ν^w›ύζα\‹rϊŒMσhΫWˏ]ϋγnΏϋϊΩΞ{-wvΫχΊ}œ›`Dήq^™)2Ιςμs°£Ϋό=zΡί₯ρr†ρ¬E T‘TvY‡ΰcΥ€ΗIΤL¬όMJZe’/Ξ±εŽ%XΓ§ν¦jκ χγάλ}Ψ Φ\69ηκMλβ~…E‡œ«δ‰ΩΗδ™J^“+BΘ.£Πx"M+`Ώύ±dhχβψ±ωΎυ}oKƒ@—¬›JΉ§PθΊΪBrˆ@'Š4Ξ“8VCj#qœ΄§$β(›Ω¨§mλ₯(ίRκ§Ω.žg[qφ!Bk`[)Όf'”‹CW"hr#ικ’D¦R€$ —"zΝJͺiμ4{Ž-Š™DeW:Ώά˜3Bς1ΪΟων!`6άKλΩM"~»2‰ΤΈυΆœΙ‡u­ωΟΤ‹JŠ»o&/”«ΐœΎJUΉRV)™₯lIΙ$δ2”˜sΚήxš€‘ ’qΩm³ΓG΄²Ο―O€Z|šqeLIΙΙ2Ο2Z ¨ίΘ…ˆΨ/ΩŸqIVΞ₯Λ*†[ΐŒ;n― Φυa͝6yγoj§0L>{ Σμ’ FΈ~>Lϊ­μΦυέtw½Έ+4`3G­ƒσ.Š Θgؘ…γάͺ`\‘Jαθ˜γ₯ ΪF1ΞLIZ‡7Bzx„ /# ν1Qmτeψςμ1ΏΈyσ|Ηέγa™Qυx΄°Tͺ4@D–\•vhΜΕ' ύα™E Hμ€:D5 ›ΎμŽƒλυ­?H³ΈN†š*S†Œ ZGΤFL6ͺ14>‰P₯ΏD.΅Υ@Œ~Ί¦2/pύΎΦa·>ώύ7ϊq΅ΓοΎoφs…Ž)Ώ}RΔςEM^;‹ΦΛΐ “:gΐŠ~²ΔΘ¨Ά»±)k‘’R…Eaμˆδ>6'DLsϋ€P£€Ύ ±x-¦dͺ“ƒ„-Q-6A*Y:Ο’–ŒCgh©B&’ [ƒ_‹& ΄ΓθtσώυZVMX·’GΪΐΝγΫοaΒqρmύΤ ϋ ΉΌ[Φh&kαJhRP°η² …š@«Ύη °6S \"Χ¬VKH‘¬όήz-^;=χ^Κ ½Φ§¦δ;Z `BrESΈΡ!;ζ‹vλFSCi«&ή}(hιΪIŽ$³―•QώΊŠXΙ!~ͺ†A CfΩΓΕ(V—$ƒϊΚ1Ε:‚Αzρ›3Ω(eΖ UZύ6> Δύrw."/‹ Υc³1JtͺΖγ„Ωθ4Eν$μ>GΆ‘·6UcΈΠΉŠκ „w* uΈ¬*χυ1|;¦|{~' ΌΒfσmσˆoj¬Θ{GDdU¦@ϋdΛ(§†q°,K“² •xˆFΫœ^B­Β3LOQŽ+]ΕH:εELk†IόϊςςΦ'[z•‰Œƒ%  ·EΤZP*6©Š# ;–?ΧY©,πOP?Ž95R|šΒΣϊDΆί6Oeς‰>΅•ΧΧb΄hΖ»Β[=…νϊ”W•`ΆεFιKΐψkς7;²ζψηΪ€ΞO˜δ/Ϊ“ιd’WΚ$8]χXΩ―¨Π•El ͺ ¨g²s›Βͺ¦ΐ #ρc QJcN*’@WΐQ@Φ,XŠ λKΒθrΕZεύΥΥμ³5wWζqΊαγwΡΣHKTΨdR8Ώ, dΕ+°yΚΙίK$:f(j(Ϊΰ#te Ž·΄V g“Ώ1œDψ΅ψΦΓ2©ΏΧ.Α)^ίkŒγίΓ칞²\Bauˆ“bG—ηB^ŒlΨ›έž~Ύ»Ώ³)œ#&L†ΡBi–,uͺ…Œ΅¨qC%‰K5`%Ο“Β`ΤU Ej§£ρMfόΓ)yb^Ύx#{»Zcρ° .—<䈲Xo­„‘ŠNΝ5·tXW:Pπ'eh“Β£–A[“ΈΐœΟ4Ž=i&FΊŠ›όvw1$½O°Χ£€Ω©K†ΕœΰΑpοK":χDœ¨)ϋΜ,ΛVcfD2λ― χŒrU&ΖK‘λaSw 9‹Ζ±{-Nw’FξcΚ0 ά£π5–…Μj*ΦΚ\δ]1c„ϋτBφξ+T )%ΖΜγΨμ΅£ΖΡ0(όΘΉWΔΎ πhρMe!Š0Τ5@jβίjΗονβā1Β†T“’Β6Ξ:y%:”ižΌΔώΣ&•D›΄P©Rs"—vrΞ³«Ψη<7·μž‘YYηηpχœ˜3ζh¦T`{ε$WΑ’mk‘=’™η)\εb–ππ"+—ΔυΨ“—!σϊβΒ3ε—=Όβw8Ζj{Gei‡(œ­Qi‚ΓΡ XNΖΥΚ¨–!z"m΅.³), Ψε0ƒ#ΊΟκ¬K#V_Ώζ)›ΰŸΌ@­ŒοΕ>fdυ^>ώ} iφπΈIΗBυχHφΙΈΊR ³ΎΜ(βϊ$3œσΔ±]*πsŒΐNδ*tΚ9€R|ΤΚdŠηλ!¨’.PœRρŠΐPf,–^vγ=4ιΪΟΝξϋϊ˜bOΠ6CUΏ>«ψ?³Ή~N―™ΈyΊθΕ,_Ό,³¦\»(DδIΟ9ŒO εˆ₯uœκဆylŸ‘©M‘w†x€‘†Sπ(ηπ;δaύτς8R5p}Ώ}οΙ #φΈeΪ*Œ< •α`‘%GΥp†Sn€ηΐίΡRο1¨›:Α’°bΔΣ*bΎsυΡ9ΌΪ δ-nZx5L+­()¦$qJ+‘Φ“ΕΉ‹XέG) +ΩHU” (ΉτΥr—s$ηΛ1z35ζcηΑΞ_^‘ΫBΤ”T`³;C)h.e™uZs!…wΠV!’SΗdJRΆ‰x œ—2Ψ’jˆΝQΞvE4ΔF,Ϋ‡—m©λŸsς¦π›tχ^E«K©,U@nˆR‹}Pc”*:Η ₯.Βτ±”YDπ†P–CUΣ•ύΤΰ^^χ‡†ΦwηΚͺήzκQ¦©kO₯vO9R°#&Ε‰t‰yμκ…艡’@f@·δ(‰ ON‚·Ρ6,Βχ―„Š₯0)Δ|¦ξ•αΤz…%QUW FΰCŽ 2^έ$`;ιDD-ž?Ρ8‘αz¦Πέρ7Ι#ž5fc TuΎ„ƒ…ΓɍΦζ‰RΜiλ „g ͺΦωX{ˆ ΑtJ`i )Δν­Ρ)hΪ+―ž^χ7ρŠ/PHΡbΧ{Ή—ην&·ΌgKΑB•«d¬£Ÿ c#S!rnyŽΊq“ˆTLeΑ¬]r9+J% 89ΖΈ>πΐξ^Χϋς‰~hσF¦ΚbWΏτR΄„χί¬.wέZ%sΡ#­Ή²{{Š›ΗΥˁλ·ρ™kύεΕzɍρ΅»xvχω‹.K΅˜»6Y8Ξ―ΫMάΐ²šK :<‚LΠ‰&fρυ?εφϋ,_σ\SLiWΌ <ڈΣ«Ρ‚—`“–*ΌΛ(ΓuˆDkhŠSY™+Ÿcο§›Η·|ΟWαTεΒXΠΌΞ‹#vΝ( M•H@Gd&<˜™0Ω%s_*ΉωyΦ*.:Ό;D¬}2€―žrqXcˆ’‰Ό‰Ι:—,ΰSΠ‰»Tɘ h1λκΗχtρΛYh«FπȈ%°k%: Lΐ΅‘ +j2‹Ψ—ΥιΌt%Ηθsπ³kίύΏΚSx|„Χ/¨[>y‡e=Ε·’§ΆΒU]²€œΣ€r70Τ4μΕqšbtX<†UΔI,Ή¨‘|‚ƒ5rζS»^\wsβ€YΌ?« ΕH:AJΣΌιOλŒ3‡c_P`+OFNΤοGμ<%}΅€ζΤχHδT’4ͺρ0WM^φ9Jl0 ‹m‚ύμHεΖ•Ρν7―ZΊ()'_!>=p NΕbΡ²aΠPQˆΰΉ1η/Χa›(eΉd*D‘-£,„έ!†| pβζ™ͺ0=Gψβl!€°’$bή“Š‰ha;G‰E…9 Σ$–g)<©‚λ3Υ―ΰ΄ΪT ¬οaτ@uνgΥχ†]_mΛΪ(κΆΤaΊ»}I /μ·mc³ ϊ±Ήι{WτΕΈ<Ÿ8τϋΥκ-#:Β*κ‘Έ³)#¬KΔ06λfώτ)η›~:τ‹ψΐ΅Ήk{ΉΟΛ{―ήJ ΅}1Yͺˆ n~―%pAP•άPŒURotM%8ŒΕd‚š›<|u₯οΫΝ±2’ΛΝSϊυ†i*)…wο«jl\[Ρ΄«Sδϋ¬‰ξaμR>T΅iŠk™4l+Δ9ρ]Τ¨ Ξέ`CHάρš,ςψ‰IΊΆΫƒε©ˆΎRHΧ₯‰!·ξυkίΎ“uŽ΅F‰ϋ_VGmNŒ“LΗgςΠsO£έRΎ‘ΛGηO«τςΪL’ό4Ž–U»Ο§Υ;±ƒl_ŸΟt„1δ|ωzχ©k³ωNΕΊLW²Ow λRԞΖrΡ±kœΌvΩ¦E«C][Ω―Ž€GΗήͺpξΉ3–ςκŒm…9ΗΞ“ΦͺΎe‡šC5Σί/78'Oeδτυ·Ο'ΆK―9αΏo“œvΕνρνΔAΣϋαb́ν8]7xρ2#ͺ—$ͺ˜˜”ˆ2VE­ΚΙIς+g*žŒ"WΟ]₯ζ°ͺp—’Qc^ BsξΔκ$Ή‰¨ Ο^ρb"LR₯+¬Dm”d\RcλDEΘ>O>sΒπ©Ν‹sυ7kΧNσKΑ^vBfΔS  Ρ"dT‘ͺ"“Ψg‰εKsUˆE#yΙ„ Αζ­™xωϊϊηŸ”Δχψ„\ΆάY―’Γ»S³iO{%‹€΄·™(xJ6Dž¨Η4uN₯œͺ©ΗάΖ5ΔΑφMš&œԏkš–]ίςβΈ»:­€K)›D=rTr5† XDτΙ`Χ °j9ΰ­ΞdGΜlΩ„y€BσͺI0μνo–co‘Ν/bω |’ΜΚX± ’²6ϊ σ.U"όεZe²ΦŒ3.ZMάηFj›EΔ”‘σHφΣΙmrφžS{¦]Fz²¦θ|ΥΝH‘`―ZΌή-ϊ(]¨°K˜£b;¨B8θhN|υΐGjjύŠϋεγf•yoVcΦ“Ši2p«€{XΞV;_ͺ—s*ΑWGάVθ)•U(Λjp[6ι`+Jœ{:ύ65ΚΎ©κ—Β5ιŒα”ρXY0Δ,Œ―Α• 5\…†Β‡ΊΙΔ(e}Ι,°±š·§¬οŽ”gD1θ˜’Te6vœ•R»lD¦΄)ΚγΜ«bΡDJ5γΨΨ±ΎzΗμκΛ„šε­„ΘM€6 ΎHα•ΤΨTTx‰Up΅ž'‘qȁW‘5˜ΧŠk’‚ΒpΝiόν7΅φωθΜβΗƒk?^\ϋΰͺ/Φe­‰kΝP)™ιXp–"“ήϊDTΑŒα˜δμ6:>Κ‹X=oφ°«ΣMιXaχφœΘ$^ ΗτΦOdΝ3R‚ZϊγΔgΠC8>žCΦ\ΓΩν:Ϊ|όΚ‹ΞΘw{Z?ύMD€Ά²©hΚ?ώΨ{³εƚ#Iψ~žβ3Νεˆ²ά—‹±y-23² ]άD΅θιΗγ`Ξ@ς@f£n“X,Vr‹pόpΧΨ"”k€H;Ϋ&_šμ°'ap THtd‚Γ‡ΏφΈpt†ηGπ&H‰K5 V–ΑοΣπ*(©JL,eθ±ΔZŠO:DΝ Θ©ˆΧοψΓξVPEZahyν9œήν–B'9‘i υΐœ2bZIϊΙ‹eI–†Ζ„:"Cθ&Ά»γh—Ϊζ2μςΉ?qd‰Π³λ±USZ V;Z mύgۚ,t΄$ί‘Ηί"Α1I ώΛb*ΐΊηΆq‹υ­ςΣΫζωβ:‚:όΑγc9{§SξΊϊ’€ ‡R =ξ"h‘‘e5—𻫕»-C0W¬˜€Kp<ΡςuνψŽέюΞη—ͺYΤ ΐY4© ”ΐθluδrΚIۘk \acΜ…μΕFjΆMbˆa$RˆΪžaHτπG.―€.˟ηίaF]δφZΑ>`;:΅Ονύ7·Ός^t}z©Θ½ͺxτ&Υ³ΧΩ)Œό«³€žρό;λίwω•ƒϋ]₯±KπΏώφ“^ττv_ŸίΟ5h¬Ζ½Y³Υ«Ϋ|@•ϋN uΥ¦wΥηύAΒ₯ΟΣ/Ky~,›lυιΗ―ƒέΊw`ΗMr_7΅oο‹ “rjϊϋgΝ©ΧͺρJπ©ςϊΛ–™' ˜ŒΙίάWξ7Q^šζ£Mϋω·ΗŠΪ:VO„”Γ‡μυ μ}γUώŽι—ξγˆ4|θξνn{Ύ?σ *Ύ«Ή»MΗπ˜ΉΗq68gƒsdB}QώzrΚg "G;θΪO΄]ηγK"σ‘z·sυό£aύkΥ}:Ÿο8ΰ5OŸ‡»όλ1β(hžλ_<`AΪ’ΕWΊDŽ–δ8ΣLοπώώύς@‹§Ο8τL[^]?Τ~Ϊν€όηZ[Nzs–βε6ςŽ\τ^ΉgŸ__Ώ‡Β&ž/n=£? |Ώή&u!']<%ΡΚ‡σ†¬νέg}ΗχvηΕvΏ/wω]^„-B8œΗΛ~ »™Ψ+Υωΰd|dCήι?%ΐγ‰/­Xα‰ΙσπφU©c†#x:χš§ύΫ3Ν‹Gΐrΐ‘£ΗΗυιύqΟ€bΚψύš‹?KΓ­ψΣ§ΘΤ¦4ςa±w•ώ°ΨLοh•δΉ2·ύέΆ/βlΑώΣ&~Nψ+^>ρβd:LιF°α“½/ίώΘ_ϋΞΝτ†7\9Εe±αE@c›»­ …:€^94Οuσ―r΄YΔαφ_E—Ι-Ή}”ΪlΛUkŠχ•₯;~}’··?k”ςόmIΕΏŒΏι`yΧz\/―όΆ‰”G=Ϋ³…Μ©Υ?”Λϋύί,~m ρpz.rΚάεΌΑμή•κwόa™ΓΆε’zΔ›αmΉ]―ΐ'6ίώ@ζ½£›ZˆΥtμ KΞ+ΩμΓΜ―Ιc`FξΆκτ^ΔΌήoμ&n,=νgωΜζ‹υΞ’ΥŸ\?‹’χΓδΧ¦}œ}ΰ’aV~2žΔΌ½„vXNyVφ©{Ζ5ά™cc]u_8O»ΜΞth‡G/ Ώ€svηβ6ΛώŸ^ιyQΝL]P_XΘskχσρbΟπζEθ† dWnγ½Ώ~ζ»“φŸ± Ϊ¨AŸ½hώΪTžk’ΧΐŒχΟo#­6›¬uΡηmd5ώ?ΫFεηύο ³]Ό™ξΏΊΏΞΌy쁈-πΩᝩAΎ?`­N:μΦΪx―bαΌd‹˜ 98φΤ”Ά.‡DIλ”œλDΡϋœ<+ρ•΅:yeνTΒπωqŒNςίόφ|Myρ•i5eFχVΚtو³±`ΦzaGl₯ΑΗ’]«Ϊυ©φΪD_{ΏG}}*;Ώ+aΪέ]±έί'¬ Ά\*nΈu~\χf€_ΟΏθΟ™ρσϋZΛοk@πΎΎΌςΕξΟ9ΌΧ}άκ6{‘Vj9ΓΊ¦FbfΦ|J•»V¦†–«θ06s‰\ED_¬Š\ΑO΄2±φ'’ΣΗΕkϋ φλ―…>ψΞF‚gΉί…±δϊώΊxϋst1ϊννΏœ©ΧF»'ϊ›³»©uξΑ¦.2”Ι*ŠχL:‹ Έφ=¨,“l=G₯#’iΥρΏ6׊ό΅'jˆΤΒÞ·S_Ϊ½ό“ŸήŽ:9ŽwυΘv<ؚm±j[.άΪ^θΒ8ύΫ>φΡεΊνœ>ˆέp±ΖΨΑΤίK.άήsΞΙ9ΎΈžΏ/\?ξΰΠΐ2yώ Ακη>Ο+όί)&jV³XΒ&Ž` ,nΡ*X“{i Έ yΚό?―ύΑ οδg™GZ.Φ³ΏŸ7Oϋξγ; ¦©ΘΑN|_Ηγ3ΨwήKο& ʏξβ›pΧοΟΟ?Ξ²χwgΦkQξ%_ίΊ+5Fς-ΩΦs·‘ƒ+u%"Œ©† W”Ι©ίu‹©n"³Υ6κξŠ4ϋŒΛΔ_&΅ςΊ|ΔζχSEΧΑƒt©AWΕδR V{SPΨ|΅AΏƒc­’}ίUNΝe1fΥ‰¦όTvŽΠkI“FξσOϏGr σΫ{γˆI‡Šx—ki¬t^:οχnE>ΰΠ…R}tΕؚ,‰ec3μΌνΆy6Scί`Θώώ΄>w{φ;WΊΓ¬}Ž;wζξ§³[8+iΗΘ[ ¬l­¬E6ΤC0FZυ[kΒ|ΚΡ‰jΆήQsξ ;β–skϋΩT"%Ξ…½t“²ι=…άΊΛΪγΈVT556ZG‘3΄μλZSώ丌± Ω²ψΆxZG¬-Δ•»ΪώύΧj$›οwγ{@x‹βε«;sz8ϊ› ³όΘάΝίl쬨7̌jΦŞI―΅S1φΨj•†E]²‹©ŠH²sY‘uΖ›(’Ό*\ž»ΝƒϊαάνχΪΉΫ3WΜέϊ#ά\“'6L‰ }”†σ$RB6œ+’θ,ρκ±z„οZ€ŽΤAψΩΉΠE±9ϊτψo°…X5ε&”ŒΧk1Τq*UTʎ½ρΊγ+γsR˜—Ϊ5~Jp³ΘQ˜›½Ϋn’‹ ΰ­ͺκ}*)ΆB"BΙtΡ—BPŠF”] κ‹‘γ0‰‰¨οˆ»“gθσƒœ•ΕΗ†… v²N¦9²Xu›Ϊ*x‘'§©GΣΘ[«SorύεlΥ^₯― r}+pΌ³wωΖ€ή{Οih:·‚ΐ‚ D^€έΣw$“±žΥΈ”{wbρ Hθ2ΞωΈξŒž`ϋα »ΉϋΊ›©5δD‰ήeŠͺT%φXΆ πΑΔΪtE‘£Œˆ'T©&)έΚUΗϊšΕΑΙpΝμ>ŽΚhΐ? ΰš4ӚΟέbπOˆμVΧβ3 T. Y$Θtpπƒ7‹b›xσ<¦ U'NR΅θΨΕ±'Z­°”VΕfΧ+ΰ²θš^ πTv¦₯WΝΐ(€šqZζ|Ν™΄(A·ξ½Q@Θ$μt­5‰ϋd―=ЍcΝΥρ;ρEEΖlQ MΛ9\tΝ΄¬ζψ‰iv°LΑl Ρ0ŒΒ$ ‚"θ…ΒFκΫ£΄*ς|¦tΠ+Ύ’Mεl²ϊœΖΛΑσמϊζ Λ«›“#Q‚ω8"qξ6z$bΌš’οΜYYη\@–Bκ•ΔΑj!–¬ΩΗ[Χ«BΏ’ψ.νΔowTΧφΓγ4» ¬ΈΉφͺ‘©]±ΎX°”Tw‰Εˆ±tπw#φ~FwNΐX₯ci M/goj§&47ΠΦO=•Φ­Ε dŸ|V1°¬Ρ˜c"œ#N| !puͺiςZq¬ͺΛά'>ύsήPŽŽψό“OHϊT| .i|ΧΩ ΑŽšσάB·Nπ’r€PnΓ(Τ€°«oS*mΟαχ4GžκΛsύnΝυ[c‰ΛοI―Λ±•1-ψW~{Z½xβίgtw·«‡#Ν―’šq|δžO’uτΝi 熃eΗΰi`¬>ΕnέUΒB»`<˜‰ˆ«N­α³ΜήΡݝFΘ›’+œ Jq]mց5‚tX`/Ή’δJM¦ζ–1L͈qΑV’Šeπωγ”jοσ ύλΑ+Κϋ·“d9»T²™c'ψΈαs%Γ`ΕF€’|ˆ΄ΆŠ=zNθ³F‘}K₯;Α˜Ή~| σƒ`ς­SUτx βoC*R) πGT ‡ν„l”Δ\Βcθ’CpXmΫτ:¬ŠFN¬Ξ¬™_”΅9›“oΊ΅ŠΘ–³RΑͺ–I°*>°xΩ1b―aΉώΜ­ιH€π‡„ύ\q~|υέ\ߞφžΌ&‹hΛcώyv²ΦU5'ζTσ?‡J4 b—­Σ˜A. ΕXtoDbψ—’“5`έ\*&NΜ>‹5Ο―ψˆZvώG˜{Χ (¨Q§dMˆή¦μ‚λή‹άy+Ο•š1”•{ιψ\@πH!VvΛα"v―GλψςγΫώ³ξϊoœYPd’Wnwύα™ŽZη/Uμ xG7˜Τ’d‰0ΰ»UIω_PͺŠMv>ΆΏ‘Π)ˆΕZ0:}ϊηyy²xα“εž{ΗvΔΫΕΉŒ•uχ•,pξI±+/…ΙΒAvη˜’[c쉦0φΌHΫuο;“ΡγΡΞ.^1BŒT•€Aά™Ή„Šε3 ζΒή°ωˆΑΣ²)!α$`£ΰQ°° ϋνΗΏ¨ΡΖνFž`e«φϋMΩΥ₯α―ό­'Αι†P΄£ŒͺE§&dӈθ^+(b˜wA€ΩŒΌζβ#&8(*Κϋ+ ŽvDρn‡σfdϋeυ'v_³;~ΆEQ8°ucΪƒM₯œu₯e•|8G“Y[D‚'Iϋ iςΧωͺt-²~Τ1pΏ.υΈ< χ#…iφΣ€ΒΔχ3:°dΫ9€ŸuD?JAΖΠt ΩV8½G*‘ ”€$:ϋ)™o)-ZpΙΥμž4ψŒ’­ΫXϋͺΐskυ¦Δκ£q@u‘4`ŒA?ΰψVoƒΨD`Ob›N}ώς£‰Ώκ‘°μάaH€½³Aπͺ$SΟE,³ Ϊδn―ΉŽ­†¨νm―™ΐΎΐS#œ@/o·uρ2rΥͺΘwjΎγΧλ½Ίφϊq¦6%σ¨ίθίϊ.%ψ·&":‘Ϋ bq΅=ρ+pΝX¨xŽ:"Τ`™LEπΡ₯«dΕA$ΈVCTβ#41’ΗΫg™VqH½Ž˜Xϊ:• ŠξΉž"±Τœ@ύΑAΑ©rΏ[ΰ+oΔΖU^&Wγ{z“bΡη'sƒkPl`Lšj:‘±M*°:vΈΙ©wWΌ§^km=¦ riœ΄REΉΫΆ†'ΧoyΚ™ζ^@-Νш§v‹%+bό;ΑN½9C ¨ΌΫ¨ŠΒΘ\²ήi|ΤjœRΌΧΞ΄8‡0Άϋ‘Gο[,O²ΆibοΞ‹œ)(‚3Z#“§–]©JnΫ”‹b™@­šΚ)!ZŒ_ŒΌl ϋe$ϋ–pηFΌϋΉ[―kΞ%΅"°Εjφ`Pρ$Η$₯M©=ιb]TZWΉš­Ε Ν0©Ϊ'xΓα ωfη ΫΏψΦδ]αΐNΉξqUΜΏΗ7w)ύj `ΧRς'Ήj` *U†ˆl†΄/…Ψk-yΩkΎΣ­š8ό{₯πsb=57όs!6…ΖιU•«k*λλ©X˜*―΄i^+ΐ’ζ8w€œ¨·2žϋβ7·²x[ςΫ_+΄βψΧWκLu˜Ώ‚‹΄%Σ)ΛρΆR”d¬IΙ€θp:Œ”²u ’εz/f«|εφ¬ΙkcΖΊbΤξϊQου ƒίΉ=npΦ4aŒͺ€Ώ Δ8sΖΗ"ξ>ΥN%°ΠHII˜±»QU³ΐ½¬Τ*€Jαšαξ~ϊΦγœ:'Δω««Š‘V/`υ±ΛΉQΑ²Κό#7Tdζ”o]θ΄?)§«σ·Μ¦fuΣBu(€γ‰™Sq¦΄ͺͺU,,W ³³WS‘ͺEΠk:6Paη¦Ύe“3Χ@§(oΪk +όkY:M­v`α©+ί”abδX½λ8ήΒΣ{¬˜l’νξ³Oͺ(η6θ΄ ΫΚνιOhΉ‚™β#†€’ε\–IΌΜcͺΐ^Αm,θ€›z&{yx~{;u›rΔy©Žψ€€#Ε»QΣd›Μ‘@sk¦€₯XnΐQ r`U€Λχλ»ΑhΒmΏΉόωm­΅”’’ίγ/.ηŸ–Nώή[OVQ)¬j±£——[0 Φ•ΚΖΘ³b•Š°£Kk!Δy©:?™Š›Α&Β‘’tΕ›2&©`‰«γ.ecΘ)Wi»πήT• %|8αψmΨΘ O­Ωσߟ#psί1—Z‘qfBκ+Rͺ‚A!vTuˆ'”•σT-E’ΊQlz\qΏ*}y_΄»ςόό°‰φ_΄Z­ΨΪξH†(νd«KŠΙ yδ‡η“PλgGΓρuΉ#{–RCͺ ϋ6ΚŠ5b% $αΆͺmNQΖΚW1ΘιΝHάψ²ŸύN4/ pυC·₯Ο±J5¬ty)ˆ Τθίs•K ΔfpΌ$Ԏ+F^Nτ¦θ›C„—Ÿ4Hα΄ΨqφJ¨] Ζ΅Β+ΟGFΌ _Κλ2 c,©w-(ΙΥ$έcίΥβQλγT°Z‰JžΤ>Μώρ[Ξrv΅e°šΦ@ι L³Ή5$cCš‚Σ(/ƒή)p ’κ――τg«Nψη…Ϋ½ςΣγΚ=ΡΘ[ΧμΪR3Kν;vλrτX˜θz)ŽLbΓΘPΐ^rΨΟښ†ί•C~ž*ζ~Z.ξ₯eυ/yΙT{B˜Γιέλ©ψ>φbΊ4!Ϋ?||9{ρhoJͺΐ”«'ΣΛ;_to•΅ΥΔTθSΝs`υ‘Eaγ“²ν9^[S ׊|/u™Ϊγͺ™Γ­h‘ύZ΄·sqύψφ˜Νήϊ°*‘>lVŽ΄Θu8 „P)[³ @ ={-ΧΚP΄δ+ΫT/ΔΎΥ(ξ0uŸLΎΊΓtόŸ½υ ’. 2) _†«”κ΅€ xFΆP·Rp©C.‰@|6p2d”_ιήόJφψψΔ ₯’'WKsσ›Vΐ³ΑjΐŠ£'1­-iΆΡ˜&Ω£ν‚,(ΐIΜ2Ζv/Ζ―μvqšG³λKΥ”4h0`Β@T ±.ŒS,}``7ˆΑ’’ζΐ¬kρͺoJΜΓŁ˜“agΙΖ4JcΚ}•§NPdpϋΨ]― lΣϊlμ3ΨsΥ¦Šξ[#d|U(NdˆM<ϋ½Bc=δˆ~l°λ}=3–ιo©$@Σ”Ψ&·Ψ¨g<Ώ₯‚T™Lx A βo@Ήa’Cσp°ζμυν+€λΫw~?Ή™=$;‰Η³MJeΰ΅ξU—¦V@ΕK.!Zέ{sΕψβ5P» %TΛΚ—œλu…ύιηhjΫS8–Λά/Ÿž§—yάΥ?:σ³ «ΰΰ’MKΔ)Τl ΰjcιr¬Ι«FφIE_Ε¦έ+–Ηκ2„’ρbΨ­έΨAa¬¨2 ₯Ž£SvtΓ±/hΆσ=Z»°ύφxβπέίΟ―Λο‹Ύη”u‡ΔωFΏwž "[ωγJΉcaͺ[ί)dU\0ΩK[HA‡PΑ‘»ΰ*ιΈ ¦Ή8Ο^jCΊeέΉZ άΦκΕΔΉŽ¦»Δ98€Ϋ-Βΐ‘τLznFNœη«=•Jςk*Ωΰz³@ ₯‘’G&yœ2eq‘Ν±[ώβ«tž$e.ιδ ƒΨ‰κJœλζΆήχpδ 0‚hœτΉ|£βΘψ/ξZνΪuΉ F-xg Κ^π ]2eΨ¬NΨj¬Φ~7£ΙύνΧχEύ~iZGΤ :`@TΗι Ržjœξ±·td\‘1Ήζ5x`Αt°žŽWεΈO©3μD—FηsΞ{޽‰Ύύ\YyΑ΅YžΎ›ΆLθ‰ω\cγ XD0EˆHUϋ “6˜Xη”oΤεšCwv€bfρ@εσ²Ϊ'šWΗF(_π>ΉήΦdΤnδcφ#ΫW‹ *[ϋž"Ά"ΎΝ―§ψρύν#Φ͟™η7ιϋ“ώϋΟ»•/O|ζθό qβ‡g/ΕkNΤ8ψή;Θ¨PwIιl΄`±Dˆš5&Ξ&Έšˆ†K.κΨ³ά…:ž(›9*H›ζAδω›φHκΥ²Σ-™N4QΦ3‡¨t#ΆX24rTdΡυΰ₯0vκjjζ(ίR•N-­εR[εb8hQ―¨ΰ΅‘₯X²Εδͺ«h ορg*λΠ€―μVj€ΏΣOά‹Y{₯(›Aύ~|Έ΄ϋδGŽnPΤ,ΘWば(‘ˆ¬„‘ Όg@ @ά₯ =€ζb*d‰ Π―m`σ6Œ'β-7ίσI₯Ε@ fU^LƒΤ+0Π­λIχ’ΘΫ°{Γΰ •Πpμ}0!FχΔϊz†sυ8Wˆlζ &ΫTΙΌΉšΖ₯{ε©_+ί’1Aϊ·Tp(ΎuD ’Z€ž @©F½ώtb˜―Τ'r~ώJJ§ ε₯›ΠτXΩEΔCνYpu‘_Yk’5Μ&“¨&α—F0Υ? ŸώχύP%{ςΌ7χJNVs―­2±€%$«|ν*ω.šψ=F€Œ`Ω(‹ΣικAΎFW Ώ^Πͺυwν!ΉΥ1=³b'…σw κssΘ€ͺ*.X):εΒ¬ε‚©-Ά('̌Q{ηΪΟόΖo+A€αΪS‡£†§ƒΫ³ΡZΨλƒΩZ ΛχΎΧmIΐυ5νΎβžY†‹QΡλ`GΤA;©R΄Κέ ΅Ύbϊ αW-ςωn37XǚΫ9±—ζdύžœ˜Ωm‘™Έ%©Ν5G‘· ₯GœτnCΆCh„!o K?~«ιlΏOή{Πίψό·sŒ61ΛΘνϊ{γ9ŽΩ¦8γŽ^Ώ=?™ΟΜΙόXΓγTZΣmKΊWsγn¨΅,ιΩtμ؞£Ξ»>xb/(ά•tΰγΫ’ίU)šέ7D)Œ6 ‘W μG.ο$n)΄…“Θ\€™Ιg!Nι˜q‰qφMΥ§ΏΠλpψc·©«6±΄ν θιHΚαMΚεl)6β˜WmΫ•A0 ΞRŠb™-{/pτΦέ+M‡ΓYp³_y΅lΌCbΠCΖιV‰₯©Π[ο³MYTM”Ί9―B’RsH˜ )s.A'ŽU{5r'υYoί.ά?a©6dξΐχ X Y‘ŽEFo TΙs£¦Ί#ΞE©¨IyœtΠLΟ=M\ι\'ΞυΚϊΕΛU·Ω½ :ψ‘έ€μLj₯ϋκ³re­@;d+%XΦ)O™KjŸ£Θ?eφ|*ΌΌ­δΩ<ΥίΏ:ŒnύόN-G1ΈνwεΉ­ΊFΎΏξΎμ‘χλώϊΫ-·¦Ώ'κ©ΗžΣ{Λ/,i-ΏBμωύυaΥΦ²2«V£V GψF ϊ΄wοwϋ‰»&έaƒa_œΫZ‡μλΣ¦”—κn>ΰφ~hAͺK΄™δ©!°hD΅Ω―•XyΉ C!Ό ­W1…#€ΊΪE~I#€‰jXwΪτ (΅ΨD’¦>Q~,η{8pμΉuΏΣ›|Jncλ}M@YΌπ#2Œ:Ρ՜ϋΚEtSך0]ήS.=ΪΚΡH΅©(7k P”νSQΆ‚δEπΨV+@ΔxDqΘ»ςή;ΏξυΠ΅Ε7DΙ½oŒΆOM ώΚe;©Œσ»CRIρ²GL• mR°ΊpΛ]9 $yο(½°uψΤU’ Z³οω;υEYδ|ŸώZ ώζ-£ΚιR” U`>•"ΚjRYΡ ιχRΩPcsΗ$© Ή9ΧMVΤ―λ’Έ Λgχ›!―ŒŸΞοΛη·η{ΑŠBNcŒ›_Nηΐω*juͺ2]‰%!XR"Ή―tͺƒa–.Τ0 Ώ°A#u[=»]Ο·Ιx?‡¬‡»ΝΓ#ω+¬ίΪ?>¬ZVΟΟάΘ»Ϋ ¦LΙγ‘QYτίTs"ι(’Jμϋΰ-—Ε`+ι„ΨWA΄Ω WΥΧ6^νΧMΩDS_+˜>­«Ϋχ§t‡\&°Κ,ΩL Θ=PΘ‚φΏ;ψγΚ?2ΊΓΝ‰Mυ.فk—qχ)nΎ˜IƒS*qλ™\οΑz“±₯εZk[)tΘ%³ OR‡ΟW-ζ^!¨ΔςNŒOΧn»dΣοϋʐR―ΕnfΝ―Ο‹σΕ©εΛΫΟ)0IdρσAΈΥ8-Ή%%š8½*/ύϋYy‹MeΧ•by qΎ)K,%e7•Ϋ.š£Ή=?kK{ϋI£RmχA*)kΟΊ§$ &iKyyς“V΅χHwΥ»Vπ₯x{‘nMλ‰Ί…ΟMΪ•Ηtn>9`聇Z0KΕ2˜ΌάrΤβœΓν,ΰΟI#HN"NΪΪp @±œέ“ΖƒƒΉ¦[Ϊ‘(»₯w͐ΞMFήKAv%}‹ FΉΊžυטΚoον?LΟV)ΟͺZM§ΘWΌͺ$6‘žϋ P^JM7œύ„H *Σ]2\όGχτ^˜½ΞΨήϊίΊ¦ΟL’Q-;W¬ΘMEy³@ΑQu‘{±Ύ>Ψ B^1˜`%}‰,`LύZ=ής@?ΨœζΗΆn„Y ΑίΛΖΊηMΌ+Ÿ™!DΩΊx<‘§œΉΡ«ˆ–“:€T„L›BOΦ­7©-° ό˜ $Zkq³u"d&O^Vτ0Θυ+ΤbŽ:~/έ Θ±|Δ'Q›Φσk#“4ΕlCBβͺε–;ˆRN¨OYΔsH ώ,ΑΡ$±ΘŒ*ΩjΔ·θΜ0N4μυ ΄•8u)Ύ”e'2β¦636?v³u&΄L]΄D: +k1€β³#ΨΔΟ››fiyaELKθ πdƎt"½"˜qH€i νΚΈ»e^t°\‹ΰβςςcq~Φ²7·Π(ΆUL‚σNτΥJIHΩΩ{ͺH™†XΪέΕl3¦΄ ά&Ε‹οZΪ]ΛQμ‹'θ-ΐ9μΝFά½“4τόώvaBO‡ρ6έ I €/Η^›f,Ώh¬!­dλ<‘ΞΑdF ΓΠΙq<ΰQ\Τ?αΛvΔ—ζπςv‹;wο”O‹…δΆ+e΅½ž_ψΫ;½ΆS–<Κ’Ώ=„ϊmΗD―𝷞#—\yΏΉ5Hλg Ύ‰¬―¬&QΰΜ"lρ…Ρ:$Κ>ׁ±ƒΙX_Zκ ydIOΜζ¬Rόkq’°»¬E†θ"N&βJXΕgƒIΜbƒ¨›·$†Ω‰ x!±ŠζΜΗG°x}ΈΊŽMΰ?-ί—{o#ψθΛοΐOνaΝwͺΤΘ½nΆΙπ0³g%·ϊυ`ζ±ϋυ·‡ηBwxΉχ€³xκ،‹ƒφjl썝τπλ­ΆΙw~xΩ΄=―,UΉκίmήΰφΏχςŽύΘ8υτ,ߞ_1[»οKθ+˜½οlg`ψεOzx»« ~z;ϋ uψ€²UΚΉΨuϊ"m?6^!Ρ³ΔήυcΫ“[”€dΫ«n`p".Ϊ₯Ύ•ς"S£RDD ηΠ ¨tw  ½’πΓ‰&›UpΩ<ΛNqS{‚΅η¬]κ"ΥeΎƒ*ΜͺyαΉ97ŠβOQ‘jμ3wόFΛ5•ΗuˆŽοc― ¨4(Fϋ€φΔ’cτάŸΌ“σszN>xΦΟ`g†χ,ΗhοβR«$οlk]‰K΄σΖ]‚b++„]δ{ΡΠ‘} Β9›oδ\ͺ“qw—loM šΙTT GP\L•!ΣrFJQL‰.5›hΐ#Ε8°d°e£ QL’π;1ό£υϋ ΅k7Ωk½[ώZw¨Σl°ΕX¦8Κ cρ(τŽΙLLˆΩœ‰΅6χθ«ΠΏς0Ξ’s{q3wγύώH'Έ{žcw’.ω‰— da ρc©ςςΤΙχ‡ΈωrolCΙΜo€HΜΡή_5:ΫΣΌΫ=Sσ}(>kaτΉEx»Ή―”3 ˜{₯T­¨ϋG’PqžΌ΅ΐŒ$π™­TŠœ•VΤD ΅©F³ ΉΫ―¦˜dϋMρˆΘΊ(‹‡Ε‰Ψ²ϊ`‘Μ%«ω##ύ₯œϊ„œB>_ρ_Η Τά °½\Uίmžh½(dVΰukυ{V’@`KπJ^F@ΗToΡW[σΤ&*½—υηχ§Ά£=GίΫumhΧιLœ/…˜ψω[»(7f$©&ϊtΝxUT“φ€SNj„§mor‰ŠDKŠ,Υ ’™PΓ??9“3€ŒώΒόz7nœυρB°c~) ž„ΙKpL₯ΩQΰ[ατ?τψ0ΨΓλΓEΨI½Τμ‚š-‚\r7U§ ;¦Vhc=ΞSυβ“NϋΕΟ2HιLQ^"Θ)7‘ͺ°ϊμwΓΥΐλΆςπ#Υσc£Ž0A]+Ρ‹­KΏ·hcw嘁˜€Κ–έXkj8(Μ)IE(αͺ‘"š υΦ>$J8½>Y+5Ξ>‰XMKց($οjϋ’7*#q!t"uQUƒ5#=ϋΨq0'Z ³ΧB¦DΊuγ-WRΙ‹ΖU5›ΑΆˊa!κ;ό7!KsWiaΙΗ2OΉΔ°²3_.#γsϋ;Rš΄%y+-λAΧ^''†ηJ,ΐ₯\*―bH τDδ½tηΌό&—IVρxκΩUͺ»6ςκΖ6ΦξEŒΊ—†₯*‡QηΞǍaTτ1’Gli!ˆΤvΦvz ή_>~j“Xψτ‰`ξΌ*=ΌI™”¬·έΫThdοΞΕΚ*ζ‚³gΩ‡JIšΐAžk½τ=ΧρgMr+‹§mομN υ©>Ό·‘auί»s'<Ί.Ί{εΑ~qPΎ{$Ώ*Wρο·_―τ²z―p—&^~us³k‘ϋ1@δΔ•›ΌΜ$d¦΅ΈΦJΓu―Ϊ–»³δΖρ@U'•­&•–ΞFΈ+ΣσΡτ_ Ο,BφU,Z΅ΖI$KR1UJϋSφ*v…IANΦsPΕ½€₯wD|Ο“ŽέΞ5δŸτπΞ7π ΉΛi£5–Vd[k™δΎΕH{£’A[ΨŠ1χ†¨!vbd”Μ8H7gx¦·k^πχΛ >™ϋΡBb[3ΙΝ†Π΅G0 ΦŠκ&*ΔζOWΙw”M΄ΖuQp²!•’?—΅e€΅<ΰ/=»t»τΰu2ΰjœJ΄Ύ|t*©!j6‘ά΅`ΛLQ’‚ΙL ΩΩ7pν`ΖQΙwzθΧ―δˆrσm_‹₯jμΰ’‘ΜEψœΔ’²ε‡κQu”΄κ6ΖΈl²Όwω°z•Κ­»2χήN^ζV A7αΧ–Uˆ ^Ρ°₯»Τ‘γ›ά "UvىϏq©ͺΎf?Ξ$0oΟ+Γby[Όz3ΌςΛ)λœϋ-Δ 9•˜Α£œ”0¨‰H€4ްΤΨ³3ε‹κlΐ· ~g\Χώ3aWώvͺ’9χγΛβG6ΝΥh£Ž qO˜‡ Q5_ΕΆΗ%ƒ{9Dg*‰g€ΐΦΤ<ŽyΫflwΒ.±­ΪΩ>7όωσ·N>ŠsUΛUcί+±©ca§•…qVJ ΐΙ,?·μŸ=ψ™}}ςήΆ?ˆΟŸ‰ Χ2κΉ#PšwX_ΠM(.2^Θ9‘ΈΧˆYˆzŠI‰ˆC!‘«μT’cΟΕΣ$y)X»ΫDˆέvήΙη<; zΈιWš_0‰U©΅ͺš²MHΩ9²€v,Ά€ΤΕΏ/šVlidkυ‡Aξj|»κρΨΠeo€Χ°©γŸ½υœC΅;vn­8Ν%¨R\Hβ§κA₯ݐ`++Φ”VtZu«CΏ5ˆ™˜’ΕΏΧ’μΛ/*€O4ͺ<^›ΉL61₯?9Α³ΛhΖ–]S…gc €ΆEž­χT[GŒGθR½€žsNHξŒ•SN¬»ϋ5M–q}Ίm²Lλw¦N?ψn[ |ΤriΞ>YŒLNžίƒ―s|e»–1MslZ{₯ΉSA«Ι ׍8Α!Ω‚ε ’EY}HκI…؁;­^א|©O“¦oώήf|Δ&ρ]I“Vσ—bφW’šΖΤZ Ήρ4„Μ&␂Κ:tR“οΦqΌή³—ΑR2‘΄4Ο’΄Έ“˜%y,10φ~u—Ε±)H yͺ–sϊoόίo½νΝ»΄{:g'.τμAύΊψ{rŠr;ΰ˜ΐ•LuΪz€ƒ†&χ ώ’Κ_κώΑ΅ΟL @D»[ŽωΌΜ=A1Χ¨3ώŸEu½η(žI‘Uχš3{² R€Kš]k&fgŒ¨°vl―ΐg†Ι’K|κ5ΏvW(œq*h|Ρ.YκX8G~ΐl3@O ₯Ή$²4ΉΧΪες΄‰Ÿ…§σ½ιWΦO}η‡IΜνφFΡΚηaΉ¬E|«5 c1’"-&"[SmN€6ŒXhΧ€ΦX”L αί~O‚뒁ɒ±RΦά"†Cψ”ƒ‘WΖο‡&TΞΧED_΅Α”IŒJ3Wψ[TF9[δŸJeΏΖH»”±¦² Κ1Ο,^«lΑ΅ uΔ€Μ`zš~1ϊώό*e¨Ώο–o―_‚[ε’Ε+-ξθιιyU|½<Εƒ{ΧόΓqΎ§%Ύ΅ϋαknsΏ#PŽ΄%MΌ»—ΕFfς ώΒ“ϋNδτ[w―όΐ΄άp/y’+«»Χ—zόΕ(―σ)`΅8ψ‰ΉLdRn‘§œ—ο'z³vΠζƒα@HΟuQC$α(―± 59λΐίR’/Bη,<ΰLΚBNΌ±πΊτΜΒlZIƒΗό‰Δό$u+–΅ΰ=e[£kD˜M©κœφ֊²hΰ˜³<%˜08zN}ώ_§ymφ"x³ΘKEQ%―±₯ZΦHm%Šv1i+z…"T\tν΅šΒŠ»½Β‡Ÿd£Ο?ψnLhοŠrjόmο/[ζ2’ R75ς/‹MληpsvΤΚqŠεŸότΆΌλόVΏοbΟ‚n?Φ]ΊΑΒ—Ρ1 λ`*”ŽŸ΄Θ ?πxPŽώό"hˁOuψQ φT3κς½>žEβ‹GiΨ~ύΉΨ_ƒ)jwς›―ός@Ξ΄Ί>,š€ε±…ΎΊvυ}i7CώόO΄zΞSο³”a’'Ÿν ΄ΚW_­Gj$w2k—YΓγ›―%ž_eΝGΰ‰dTυ™ͺ”ήuΞ@ΡΒ²σΦΕΜAί$DK£šm•M’/’ρΊ‚υ ¬Ό¦ν¦«ξωΰκ£M[ΟυV}θ,6*θΆμΓνYΥώ>{δΗΥη[!i£…―·±hύυΑI:Ϊ@ΗΚΚΊ•‡Ӝΐ˜Ωοmƒο*#±³3Ά™β}rbfH*fνΕΒ{Ž-¨ΰc+ΪF νs”ΓP©ΝrΙ.JΒΗ…³—Θr°ΔΟ(bS}ΜΚ…˜ ΕZ(”"μy΄MΘ²,Šι.1G`u"ό¨™|EΜή₯ϊϋύJjμΨΓ{vύΏΤΕΩd/΅μπα’ξΩS’Ψpu¬‘$C±IΛ>§\+pΰι‘<5Iτ§N;sS2’Σt Jj| SΕφ„¦‹|*£”τθ¬XAΧΊŽE‹hL―Π^θϋΊ.…ηδ0Ε³I”α~κ+ΓΜΆΰ~O@nΟ]끏[A΄•"ΖΣσΫ’/κήύΗοF3Χ΄ω"„½ό‘“Fύi͌yΰΔdxΌφ^p‚#“Ήi;>κA>ΑHwr§΅t~ŒmY^ΟΪΘΏ~˜Ζά>’&‡ ϋ’Žϋ/Kη§Wίέ_ρϋΌMVΒίΗ΄ZŸŸΫ=wέi2c§iςOΎKέϊ…•—Kp"’hBІ΅S, ΘΘhοZΘIυ^€8Iϊ«ŠήΩ~f K1όx'ƒO³!¨šƒΌ;"ω搻Ε7L―ωL.D°²ΛβY£qVZή€ι˜ΫτZ΄_|z]2»CBΊqY”YMΦ₯βt«!ηΜJS΄-ΪXLwΎΩΤΉ9n=枭AR˜(άk‹eέθTM ‘άΏΡ^g8*BΊ†ΚΏεθo½Ύ?½m|8Žο&Κ!η/.$Q§z­5ΉΒ@ΝXη‹ό‡v‚ς₯Ke$'uξΥEΰ©ŽτŠϋ—Κ!Ο(&_S)9Ύ ΗΰcnqŸ:ωή5ΥrjΊwJ΅hν“θ£rΘ-Ęs1XΖf%]₯ͺΑθV B†žν»ϋύυkε¦Χ5vŸΤΝώ=±€œ»FO˜.d… 8ΧjΣ€MF€"r`ΕΆςUEΎωθY΅ΰ‹aγβ:œVωk}ƒπE€+ΔdŽ‘ӘdΨeώΈ_q½~ΜɏΞ;άQυ³!}‹ΫΞ—υtΖ`ΠImω‘ΨΛ‡  Μ'ηƒwSp‡γkΰιYlxxR¦!α₯άΓiώΨuΜΘlοΘь‚Nc{νό™;ΨξO~|σ}Θξwtά—Ζ8ω9π>ž”πΟouA^λ\‘χͺχΕϋζ/KρΪ’r&ΫδR‹сQθ0:ηƚ²§@“Ρ|}#xzÐf„n₯ηZΰ;>©њΫ.^*±ΉT,χ;*r« Iͺ₯ΐmΌ“ {ωεπjs σώZαάΊŽ|ΈΫέ5Fͺ-2;Ήςb/‚¦IEλ*@ mC€ΨRŒ†L‹Α·n‰Ϋ7“κω‘wΜ„ϋ‡vWΜΔ8BΎΑVπVie‚&ΐc+}=c›Ν˜―L–=±Ήsχ‘”Ξ)fγs%$­Ζ·ΒVnaξΙΨ­Ϊƒ{CδΞΥ 1ΒΓ}~r†™yr eiΘ‘zc^ΕΝΐnΗ½e†ιTτΙ(k8Eόž('Δ ‘Υ΅“s·»q˜³Ωκ½Όh–Ξή€J@f^£k1:©!7u΅  Ώr,Υw6’ΐb-ΉIπ”xς5ωτΣ›T iω&:8š‰ΦHF4Χ¦F%ΥβΊκ =Ήυ„XΠ­ 8Β0β΄pε»8— Ϋίϊυ ¬»₯²œΘͺ@Ÿ‘•LŒŒ’ΓmŽ-Z β=r‡³^8'©0ŸϊόΏΛεݏ§Eηޏ'τά^2¦.π쒜ΉΰΤ7ΩκN.ή,θ‚OX=Ÿ3ۚl"eΐ,ˆ“a_C,G±Ν©yόΡσΓXΎp½9ͺΉ4 H혰 ±+Τ$ ’9©½+ОZ±‘@2²s&KlΔnΫσ€g(~96ρ;ZžιΈι΄ΨΌ½ΑS³8α"$[i+ΔΠ•¨15e§₯λŽJO>(…ΦΥ ͺ6+=‰ˆ^&dyNϊT·ε'%7νωχύςXœ>¬8–ZƁΩϊυ•oόJGg7Ξο2Δ1Βτ’'Ÿ"eΜZ=`μρœ²wVb:&+Pλn΄τςιŒεK…Ώ«/οήώ½ͺƒzx.Rl΄‚!+{Η©‡Q«ΉmνβΓ™ϊ§i"΅«›`Ί±9»7/ϋJ`Fk]эU««wŠ@ ƒΦ35©E¨A Ιρ³;fί2’ίΑΗ"ݯˏνΑΗϋan­ §ΩΙΌ •·$/k*±·‘P§ζΨDL¦I…ύϊΔζ₯H₯–η¨νΩU§?ρšΩYZΗ sξˆ<ΚvUN‘¨΄‚˜]YΗ…ΰƒξUQλή± H Υwχyg #~ξalU1Ήe£RΩqnΡΛ­NCkpqη΄IfC]+­Ωk5~Γη†HlθΝ8ζZΦΕ‰@˜Ÿ]"Kaƒ&ΟFD s΅=YpxΐšU¬ ™K{ΊΉα2“Έ34τ "ŸλΣϋγV i:ΧΘo¬Ζ»<7!Λmέκ©βγ$₯D `'~zΡ[˜…β~™ΡubPύόΈΕ­;:9ώR3ΪBόψάήxϋXiκHΗκqχδΟΗƒυΝχ†ΉΫΈEξ}{WNσώx__ή——Τθ§{όκ&έ­ΏΎ[Ύ—e}]~=Ώ¦u(Βϊ°Ύώψcβύ]‘σDιθδη\‰°ή^&»Y` S© $φΊΪX­U,Υ*yjvΘ΄ΉYgRδZmJ*‹$ψ΄[‡}p”vώ֞¦!€2m()œο₯cΙ‹ Q¨Υx«)¨αˆ•θJ—$†μkόβbΥ;ςχŒwϋ,uL6Νό¦L2VΑB€ϋ…CY|-š%o™”2bΒ€ΕkSΠΌ§q΄ύόwrwΕ8W?wσΑb‚?tŽQ꩜αΜ¦‹•ΆgψŸ’} LΛ3”eб:Έθn φφύ˜τώṞϊβΞ^?”„¬ΗΚΥ쩦˜Uԁ@S€“’«λ©˜h\ξTCάm%Ζ~Υτq)έ½=5Θ±’”Ωo ΕVΤQIExΊh*:bΔ SΖ¬I4(ΞκŒ :9ΚUέ€DΛΕ*―ͺ%_ί-œ–ίŸίξ^^Yj*τGΥι„ >έ33-β‰.Vc΄Έu"”e›=x<$€£M–TˆΞε°³)’MjH;3!*?tRέχ§#γ“m9ωnλBΎ_rw\·ύ‘/›_έ&ϋΘΉ‘f-‘©Φb―1%¦¨‚ΨΨFτ \ξjjΝΉΰπ ΄\Ί¨άA€½A] ›Η?yλ9`_mμn ŽA™@ώ”uν«UΣ‡B}κΡ™ˆπ – DEn);]=ΧΖΓ vMd]<ύΉ[ |ΎΊΝoί`Δl]žq²iΨ˞WζΚαα7Ω·>0b¨UP‘°qςBβA ukΰš]’Z΄*jΐΆιA,–‘S,ΐLgΪ„”υθT]βΖϋvkΝο\DŽ ‘ΓδήT,/HΎ‰©Χ-**Ύl‹ή5ΣΌRnθ­ΤκζΤb˜Œ'z[όδΣΤ[ΨΒ‹pφ Gv) ςόW΅‘jΫK‰Ζ#²ΰ[­*L9@βˆ:Ž[μ}ώ«7ΐ+ ςάbΈ±'$ZυŠ ($ 0Θ%#ϊ΄Υ8 7i€Θ)Δ²θ[%4ή/νϊΟά ­†Ο²άfώχΒR±Όb©c[Θ )ε]‘χ.KΉ#Κc―Kί˜¨Dšˆ8›b=a£ΆώπGύυ\^~,.{έΝvk=•*¦^ό+:iͺT9ˆL=₯œ]―ΉV-–WFT£€v,0"cσ1Έ0!άΏ*ΏΫ6~>όˆ~ΜίIή}•ΞΐΩ5W@“ςμ‚Ο`Jς2h€ 00’±1@Η=vƒ‘&ΫΓ8β₯‘΅p―)q—Oζg²•ρόάΌ?}[ΎρΣβΤlώLεq ό •ͺ€όiπŠE\4³κƒS91”Β”K7S\c°(]Ξn”υ#ΥNκ8rμMΠnΠ …κ Σt‹’Ε bν‘ ˜Š<Φ Q$QΚ΅3xΧ–ςiH5YUœt@¦¬ŠZdΆΜ¦Ι^ž¦α/?Vؚέ"£Ά†ͺ©eGΚeg*’ύœͺ(ΰ!‹J ]Lh M“³Γω Εϊ<ύ¦=q°6ίXΟΚζ—ΛΕӏ©‰ό@€:1ρσ·ΞZ­ΙQ%’΅­#kξΦcͺœβžS 1cΒ\‹ΥβΆdD›¬ˆή8&ϋ3ξYoΟΏNϊfάμο£=jϝ•©*!η˜ΐΕΛ¬45›šΐΚlΑJ#ΒqαakδΙ[ϋ¦ψέu™ηδθœ92ϋΪ&λYΐ8ώπλή―ΪΡ·sη&rύWάZzΛ:[Δϊ4 ;q(ͺη€να<ώΗ« η’*έυ†.uZΝ[G>£`ώvnγk7DP­7 >n+ρMήp ‘Uδ«’,~½Φˆ΅& +9χD:[UΓΤ Φ u ¦ζ ΙR’“j–KhœάZ›I …«Ρκ,¦D’DH1;|μsÐŒΝ€ 'οΣ’³³AkύJLoo―‹ςΎ‰Œ›o―Ζ?ΟNΤώ>Ή›ϋbΏ" Α΄ΘkΩaΪ\«iΠ7¨%laŸ‹Α΄²QLε˜ΑΞυΔ ήœΜsζNfcφxŸ{ΚςθγŠH.γ€ΤΤV] 0ΊΛ92ΗΉ³twH‰΅cΧ Υ›Ο$lΖΉιε<~Ρ™{έ³}Š­RΌσψμX}NΞλB Π–Y³ξ!q. ΩKΥ©)tΐ8‹ΉŠq^ΡλQŸΚͺΞ_ζE!€³ΙNW½5³Μ=2’Ε"s‰Fl‡šDηΤ{ Hτ6„τUζ{Ϊͺ:π§ώΙ·˜“sΊ#jc“ƒ:ΉΤ›Λ‘‚Q!:ΦLέ)›o Ξ‡±θήsbœ…rΙλυcCή•ΡάΌ‘Θ{oKW)YΡνΚ΅Π‘š“ ΊmΔD‹‰t―VχMνΙYPT« "R.;Tw­xή«°­‘}€A“ryuMμΎ1ΜίǞκͺυxο­ͺTiGpχŽΩA-Σ$zVβόk}τΧt6iΪ>šΐ1χ“κK¦ΤϋF'ΥύνΧχE=WyσϊηNμ‚NΆτάΥ^^ŽJε¨[bnρΏ€h;6δtδσˆπζ•ς»ͺVlb=0›ͺ1ΈIΈωϊgXη“Z7ϋ5vQ“Qψ,Ύς:9CY§`΅ο€S §±Γ«ΡYψo@θXήl(Ψί]uΘί~!b¬«ͺΩ§—χ·ϋ•WΨ8.6ΛΐΏV6;7Yόο[ΏKŸšΰyΑ†V€α·O”― #p±Ρσδ'o=^£bΪ Ζ(/βέ‰©¦Vέ2 O 9v Hδ΄D‹P,qβ¬ΓN½pΘΆΑβο£gooΐλq^15›ŸΌυΤδPšιF|ΨyΥ%=i|ΗwΗ8‰Βυ˜°%iΌΞΕf©―ξΜΤl\Ξ Έρ(WΟoνΕϊEаbΜ.(3lf¬zaœS/ΎΚΒ=‘$”<‹†ˆέoδ©΄D¨―ˆ‹o(VY΄ΕΙ;ΟάU'.w1Uƒ…/cλVŒΉŒŽ΅ƒm1’o]^šαxόMά‡­ξ·–—‡ψ$έ€‹·;κ8{#(€Je “#PcρΦΊ ΄bSΛ-pMΥ(Ά©#r!ώΪ( σΪeœκ ‘ΫMωπΕΑpι[λ”’šaΩΒΔ–|—Κ[Δο^h[—G0γ£E8ΟR)–ζ˜Β.―ˆ9όνόXVτΦt([ŝ;[Ή€ΤD’›ΚU<λ€χ\dΗ΄bdΣ.».'Β" ±/Γ5ύΩAό^΄›BχA?π 3ιΔΦγ5Pfš‘+utTŒED[`dO•”t*@…Ψ뇇0ΏώJͺ΅$9-φΰ°₯³[+ΣR3ΊfΌZ jƒ/*›A lŠ@ύύΜ*ΘI:δϋΤw ΐ%Χ`Y`ΦϋœŠ Ζ'²]EΜΊN»«ΰXI˜z , FΔ¬ΖιΟ/\*¬Ή³Ί[Br)¦="Ν°EΒN€¦Uκ­#L·ˆύ₯[ =€nIέ:‰Π΄ €Κ‘vιυ•ώό5άb.IV²r­€δΞDΆ7ωτ|Όηg`3AΚBq<Λ ώΟƒΗUΆΘ·uFp«XcdεκρΫ QNξ‹CqSb’ο―ό―ωΉS¬‘Š„άJ•2І“‘ΊΞ¨ƒJR‰V[Χ(ΎI)γδ()MΘΤ δrενΩΰΜΘν~x©9Ύ;*w>μ&ψΈy/šΌ_]”Mm„Χ‡#H6"―b΅ΙŠϋŒ-ΎWλΕό™ ΚυB²Mϋ„ί$Ο’Θ‚ΰ„oίχΠ›š€"GpO?¨ΩπJQzўhο™n9%{35ΓMβρ˜ϋΝ^ͺb N½Nϋ\‰vEQ Τ‹C ^γ|τŒ#“S©˜‰ŠsΠδM ;“;΅ΏM~ψ΄Ίb=Ξ*³sΨ— !riλE?5QϋΣDH4HΝŽ άRΘς*βX'ΧΊ·qκΩκύύ$#¦Ω·"ζ΄‚ ·$½ΎΞI/BrIiπA6!b7vD₯€7CΨμ’υ™lu%~¦π'½.θινΎ>Ώ?½έήκ„Ψt’„_]°ΞΘΣ8•.·Θ,Vpc…J™?κJX§±έœ EO<©|¦ζηg}ωρν΄,`vΈ¬I•':+ Ÿ3HZβ ?§”HύZpƒœU•Z7,oΜ½LμΖUΗέΛΝ7€4ΆuΐŸϋsυ½怬EΡG¬h \³Θˆ sψBΪΫ‚g6Jg=ωρχ λρ­Βμ§Κγ φa°Ο(’xVEUκm₯ePQ*J;μ6%²ͺ-w€ΚΧ*nΝSζj{DŸ.S—Ψω˜Χu]Σ&Z£6 σfιΩH_gLΌgJžgΚIώ’sόΑkή?'—xλ ϊρE7Ί›νSk†Ϋ–]gLΆu!»FοχΘ4γj£―kό»~Ρβm΄)τ&Έ‘Λ ”Θ™r‰^Ί€‡Jsΐ~%Q`Ρ¦—wͺ’‡œ `νrκΆ‡OψΥolXξόR{I₯Ϊ `BΕ`B ˆoψΐ.•˜u ΤͺΪϋ”jŒi‰ΈU›Bο€½γC[bwΫB¦£Nί+΅ι~ΡΣΫΝϋue ₯ >Jΐͺς$l퇀₯š¨Ά― ¬m°5ho]Η)δ²’£w_Ψm•ΫΊλΜ__n>FΫ¨7ET  #eGhVIζVJΤcB»o‰;›mΒώnͺxAπ’uΤuM7λ’9j›H±+ @|8$†Ϋ@/ξΏ½σrΛίή`ogD?*|—υYΣ7sΊšqψεŽtύ%όHΆ€wmξ7ρ΄”ν“αΡ’ρŽ‘Σzλ3{dΉ8}\™ν™Ή8ΏƒvΉ­΅ψ„ψg€1°Ι€βΒ‘%ρα`&iΨO^O‰9 ιœΡΜGž΄`μϊPcΜ–{£[ošΣœ#ƒ0%3œ΄yβ€(·‘ςάι1ν<φŽσQœέό˜Y›€ŒQXt €TΤV[VΘ8N€K” ΎkgΎΒ%ƒ˜>.ύ'ρΊN“ΙΣ΄?ΨUŸΕΩύ»ϋYQ½Α?{ϋ ς[°ˆ\TI₯XΚEΙν}Ήδ$&6ι;1N^”Ωη¦rˆΑ‰Žhά¨·Ό?ΎΠΓxyυΆ+ηS"ξ“$•ΧΓ΅Π53:ή―αζ·ηIRγ“h'κJ#…dε|Φ’;V & ׎”HnPt© ιΐ™RŽTΫr΅Ό[ώYŽΉVσλίΌfbVΫςζ Kz”(q:>uΥm¨J,dδΚ$y»f¨ y˜ƒ/Τ{‘¦VΝ–«.-Nv·|yy~}ϋΘdlΜΝ'₯Vε-Χθšσ&ΕΫή΅νΆ‘ΓΠύ!Ί_>¦0$ŠΚMμΒIZ7_Ώ‡c;q23n‹Ž}ΘΌ‰ΙCŠδ©ΩF)A)PFAސZΝEŠ *WD]mg£Έ:₯yAz„Iσσw*wϊεΫyΐΟΔδ\ςnQwߍΡΠA{…'(`€ =i£uͺE#Υƒ€¬η,g5½ς/ύ’Κ”ͺ&c«ΙN&?CŒ Ά†© ΊξάƒέΩ«U0₯{[‚<ͺ˜i՘7_f·+σ6>œ–Ύ%ΫD8„Γ'ΛTη`"FΔ‰\UvΑ^˜Ec1&P¨]yδT„£az‚Θ.Ύ½zΝotθ Ήά§»ΑxΈI;و†cΕν„KυΝ3+sΚb ao q]ς€dpP2G΄Φ3ε ―©~ƒΡπ<Ž΄oyΎΨHΈ₯\xH>Uym’η¬5ΩξPqr†t%†n-α,†Κ*ΕΉΗΏΙΥΫεΉ‚)Ω -sšΠ8d/ h–‹ φ«œmΞ&Ίcka^šE―*ž―”ί ^}£~l»«»νσeTHaάψηδ½υλ6wΕu€Ηϊ‘5`Γ¬ΩΓ1[“xη+Q…ΛrέJY|ο’(±q¬ακO ΤXž½8*Yβ$“ξ|^Sa YJ±Λ!…0€ΘUi=‘'+„l‰}c ΅+ηό«ΙlWϋΦG5‚O“ΣM:‡5Β!j¦†φ[Φώ[Ύ–ύζΤ/ι<œ(HE?ή‹[> φύσv{Κ‘νΛΟSύ;=Ί“M€»S‹ια­χ°Ίί\+t>LΟ7˜π…TGbš”Β+©ΓHοίep wuwyΡΩ}΅/ς΄·?^ϋδRί/h΄„ ‘Ξ­·]ηU+χόuΥ7ειζΥ~¦[όΗK'NWΙtŸu™{ Ή°δ…Œ”RrΩS`“ΌP±3TWΟϋο<ΪΚω‘g-2H ¬/ΌίΉ›ζ€ςpΏΪ?Žž€νβ/κ±U`J q<ƒ\7;Τj–]8½huπAφ]:q`†e2Χh“¦ν!-<ςk~ρv!qQXš0ϋjΚ₯"ΰΣ\k@B²Y%ΙkEsδL5β }ΚΖZ/Ζssί₯Fk¨\mΡΜ)½XΙJ&",OMηcυΈΆΝ!θS½— L  š€^jAtΘέ₯“”2i낁χ¨©Ϋ”U ¬fx*žΜPF΄Ώb_œοςΗ!Τ‹{I]rt•Z³.”T!5‡¨Cn°u6¬7€G™›i HΥιΘT$ΣCμτΓΫiρolhΧ7Ήž`kΎ)$β%²Μτ’.₯ΤEˆ ΊΥ]3J¨ƒiŒ`*l]IKΑ5Μ½γ ωόσω}~Ÿίηχϊώψή)v cargo-0.86.0/benches/workspaces/empty.tgz000064400000000000000000000004371046102023000164720ustar 00000000000000‹empty.tarν–±nΓ †=σ'g·1%φ©R§ξέ"ΔΎΈ(,ΐ•όφ§ͺͺΆkVε[Ž;Ψώ»ϋΑqςKω μ` oF•ύ4Psώm=RU<œV7ΌζlλMMYF³ ˜ ϋ§{œPχ¨;‰%δ8‰ξ"l φK£α9£¬Κ‰#Ζ cΛδδ­{»§EUМd‰?Η*fιlW*y*¬»ΕόΎΜž7iώ7ΣΊ•ι.·ΠŸ­šΏNϋ vπτ,œ₯BQΜα Όμ„R ά¨Ρ =œΈ6 ΩΑ£O΅ Aϋh=œ…QθY(X}CΕƒΈ Ύςn,m2’D"‘ψΌΥ”d/cargo-0.86.0/benches/workspaces/gecko-dev.tgz000064400000000000000000001401651046102023000172030ustar 00000000000000‹gecko-dev.tarμ½i“γΖ•(:ŸϋW θ^Hb_τz桬͚‘l‡$‡_Œ­‘™ ] @`U³oΜηd$Vd±ΘV R7$Ήœ<ϋ²δτ!™2ώ8ŸQ’.“Ε#Νa$³·YΫUώ¨πΗ6ΝΞϋψGΧmΈvtΫ1mS·ΰZΣ ξύΫ ώl³œ€ŠςoΏ?χ•’L–a>ωTΑKψ‘­ˆΏ&Žxwˆλ{„hžjšazΞ˜iΎ£Yžθ„{“OΔ{Κ$ελ$ηψκ*Ο7Ω§σ9τ»Ϊϊ3š¬ηλδ}EdΎ,αmoύ/Ύ:ِ| ‡‡/O^ύο«άθΟ~?ζOCΚ³9lΧ:‰ηd³Y”χQ²\ςtώ9’ˆYž¬£kžG΅šηί1-c<7ψσΖ7Ν“$Κ>ύΤί†›nσ0Κ =γMΓM‰υ>P[“<€ œ$©ς=식oˆ§JΐIΎMy6yΕίΡhΛΈψΚΌ@£σ?όaς‰2™ϋ0\§πΎ{JR&‡ƒΰL±‰^ΨNβZF€ΰ€šˆaΐδW|ͺΟTε/ί+ί}σcΛΓ0y•rΒδ­οΏόμ‹οΎœ­ήά$Y˜'ιt°ΏΕ’ΝχέT8 π™6yυΑžΛώσπΏ₯#wΫύ›‰~"€kJb…Aώ|δz5έ1›ϋošζˆo‚%^1Α~3ΰ[KdεΣύΆ H”ρ: jΩM68Ϊψ±ΰeΰi³5‰’GN ”Χb½χ07₯ γg|ί1φ†ύΣ€7`ΈGΎXΉτ„Gœd|±&ο’:‘1›4ΎbΞΔΒ”o‘,Η΄ ιΪΠEW­YΟΕ³I£5H½­m³Φ:F*έέ8 3ϊXkόΞ΅{ΪΒ“Ι~=zΪd9›τς ?ΈςΓ&d<iΘ±Bb¦|^φ‘,,Ψ1Θ'KΙVW{Ζ?ρ³‰eτί4œQ{Ϋύ―¨8–9‡Ώ}@Œ+8λQΔ)žΞμRfΰ€ώίΦZςΏf9γώί^ώ βΗ=}ή­ρΪ@”P*ˆΎ!ΏύAeM‡Lo$ “m¦T`gR•³Ύϋλ·(dUΠ|Τ¦G€a ‰Α%ϊ?MωΛI=„9ͺ7ΐBΖy6χΓO•Χώ.ηYψž³sΙMyhO+P‡ŸΛ-Aθl{Τάo"‚‘~’< r!\wΟ§§τšΩβUα2ξ­ρ?} ι"εAιλ-xςš[8K–œ€₯ƒz„lSΡE—zπ’6ž6ͺˆν³ρ•Ώo•Χi⿁ŸΆ³8B²YRΙ“τAΛσύπΏ9βΫξΖι6 σέ|Mb"‚ύ²hNyš/JFτR ΰ)ωΟV[ώΞh» ώGoαkŽ πj ’”I7~ p§Σ―μFΗ„.P“΅H‚Β­a/[ωzM6zα#1L‚@D/ύψxΓP„.+ϋ/|„’gϊπ84]ώξΖφ"ͺq^oΩκψ1$lKό-ΓΌ'n»L['" )Aθ΄LЁ¬Šˆ–p‰ε؁ΟOσΌ€ΈΆmΘeι&€rΰ˜ά§Τ †ΉͺΛ°"1‹€μΓC$6β'/~ΤΌRN§π+/.1έHΛ΅kό–UμLΉŽ•›“cΑ}ίΙ΅QΎ‰αEΡόoFrόœ‘ς:”7§[q³iΏl„|υΥ7JžΘ˜ŒΑ+@WΏ S$ο~›)e’Ÿ&O01E ₯Ω€­•>f­"΄©t;Ή_B@ηΫΏ|mχ9ψ¦τίγoΝ₯IUϋ#ρώ’HτŒD§φί²ZρΆiώŸw ›4‘Σ5_/ά"ή&9/³`υH&«η΅©<#i$dہβiGΘ.‰O#ΦiΈήD"¦cC g—ϊvŠu{ε―iς–Σ\ω’•~œ˜TΗ ·Ξ» yΧ8ΟΏΔΗΤΗσΫύγ›Γ Lœ Ε2Ϊς«$°ŽΡΚhͺcώ―{ΰύώ§₯^‘ή»uΔ8-݁:τx= Ρg¨B{” •ΰΉpΝ¦„RI©ι0πωαQμܟxœ†Κα#";ευ*“WoΚ‹Yφ*Α6–αΠBT)ΔƒO?ύ²€’―H”ΗΏ…6@P7iˆr8Ω ξ+ΠMαN6Q™mΕ“υ”*Υu™ Ϋ«Φ …‘£ηΙ?.Γ¦ŠŽηžτ8ΨόθωdΰΤώΆΡΚfj£όwύί‰$]˜d%~έιq·Ž’βδ)^d»,ηλΒrƒΈχ§`ΗKXύsβξω.Έ$£aώ_wΰ#M%ΧηhΘ}iό―ιj;―jψψΏζΓQ‚ΰπuα’±ΏΏΙψ–%en @¬ΑΆTΜHcBΤtΝΧIψΎΜ ooγN#/Γ"ΜΧkQω†]€φΥ¦iC³ΫΦ&ε”/C˜Ρnˆ‰§Ϊ~š¬;SuΝ05€ <Η嚑kšI}β3BUΛ‘άπνΌ<^΅ρ—ˆύPωcJβΎ*―ίΓο7~ω{σόhˆΐ•ŒρΏDόϊ―£ώηϋŸPρ ͺŽωςœΐΙό_v»ώ‹ζŒώw ƒ‰s ?5ν1¬εv  ε5Hke±π•Ϊ`Ο>$²|TŽnω‘dψoWGΣΗψΫξGόΟ2β A=SpRώ7[ϊ_{Τί…ώϋ!€Ξt•&qRΖϊ£―†€ Όaj’„ρŠcΜFIΜ£…γτΞθΑ’š7³}^™/“ΦHϋ>›f=…θΛpې5ή4›/Ίύϊ™λ°gΪ9Φjq1³bΎύS˜―bjb²#LwZl―²ώk?|ρ_J.>\LρΊιμΩ―@Σ£ϊϊ‘Ϋψ@π³T—ΘΞθχ‘μ?&ƒΟŠœπρ§λ?8-ώOψ„Žϋ[ϊ? ’–Ha}4 η·έf~Dξ2ωŠ+_ύεkιsBM–cˆνό_D.‘,uδ?ύιϊ―šitΤ΅Ζόowjφ_‰ήA䩊{§d»j,ΰ«cΤ₯€,υβψΙ†δ”><βτωΏώύnMy–£δ'ξ0δ+)€NμΏn˜mύξŒϊΏ;ΰZώg½ι όj·)cωΠ―Ώ]ΒsraIykGΦQr§Ω Ν •mwe"M‡Hˆ˜’ΝbΕ£Mρ>ΣΌ«₯©$)<εyΞλbIy·+―%œ; 5 wqφ¨e“— VύθΫE›ΧΣm7ˆwσmΩ€λεb-ŽΎ]΄ikυj[§—Vlν°ϋ s»lgΑδΎΔw΅ιμοΆΪΏΓ!΄ŠΠΣε(ΏΡπ–IςέΘƒ‰ eώΞύ/Δ@Y01Γ„1aœσ”€Ό‰QεkΕqυY™#3λJωΐwOIΚ ]κ~‚xB *Rζω†‰4£’αΑΛ@¦α<‘‘B6ΪN)'L6ϋώΛΟΎψξΛٚυ₯ή\-Λ„―³$]ΞΙ_ηΝσ<άt‘«we¨£§Π3ιuΐ—θucΤήveώM’’αοΒΖ_‡<εγ8-OΣΤFωό_OύΗVXH–aͺΝ’Τ½fυͺΑ0ή§€»Γ<Ϋί:•f¨νP0τ(+―«h°wΗκTTœ&N”¨8Ο½hޑЎ8’™ΒΎM—:ό1Y”}»hΣαΫ΄‹xW\ΜδXwψRwW §^.š΅#u’EΆZσυ‘χΛ&uέΎΤo0ξo—_™WξVC`jχΛwρ€$Ϋ8Jdšέ4Ά\ΨΎ6/‘K|J|Ή³τΘ όΰϊ/t#ώΏ±ύύΏ`»S’ξθtb έΡΫττΉ=ύŸ-%yJΩ­Κί]zLZTCθtv}/σˆŠέ₯Οξ1¨΄Gφ΄Œ:ή- IαΣI;ZR₯d!βzŒ-)ƒ#κδΕbΕ’§Έt|Τ–u^} Θ›¦$ζQδ@Φ†ήρB£Eσ‘―;ϊŽmΦή‰8}ΤήxηΪG_€ηΨ~λsšςu’—$±ρB­AωΖ‚&)'[EΔ =ο5šνίήl#`玾yh2iϊ ]ΔΎd3{›ονψΝ7‚K^π(8ωξ‘ιq&£«FBΈξ.ΪNΨΝχ;šνίnΈkw½Ysί†σ ]σ:šοŸA;¬«‡iα„βη“:™žMeκŽ>Ρ‹?-ήΑ>ΫΫάΥΗΠ:y2`ΠΩΒ˜zΨtM«Ν€•uΊώB-οtΆN‘k΅°Ε&d<]'ρίυΑo« Ό—―PΆΘHζaχj7›ΐ[OάOsΪΡV>˜ήωΜίv-υώY?Ϊ°”&ι²(*όIΥ›°%'¬§’jŒ!€wαξΖ›£Οχ_|^C 8±¦‘Άτ–εŒϊΏΫσ>ό»š$BύOeφΙkz‹Ÿ”Φ† lS°ͺΗFΕ0(‘³τΜ¬Τ­5³ώΛna―)οu…5ž5€Ž(ΗQΤE½QΤλυ>ι ͺΐ_―ψ£t2¨Ι€₯ˆwZ σΑά‡¦x‰―5ζώ δyϊŸ'ίτυiΧrΖϊOwρLWA=6i˜€aΎ+ά6 τŠ@„2fIJν €Βx/΄R&°―‚ΘEA%Ζ•ˆ)…:•ή“ƒς¨”―θ“–TYV‘άuά Π¬ΐδσ‰Ζ-ί2W7m•ΆjΎΙ:bΪχ}γΈqžχNUB BW„τšlΣκ6IΦ$}Xd»˜žΧ―dθζ΅ΪΎΰ$£„ρ…%Ιz\uή 2•n»ήhwΛΣ|,’`nΊ!nρLΜΧ$&"<&‹ζΥΧΪ}& +Σf’‚ŽS E¦½θ32―ˆ²5=brnψΊkhξιvΰΧχ Ωͺ‘k^θΜwT¦¬gXBjΈώˆ{S†n(ρdψpεkG†Κ=nYΔ΄tΘ#žΗzXΙ§„^ΰ8– BΟP³]Φ™»7Œ§yΚσίψnmkΌŽΘ΄JQΜ#ϊœF=Ξ—(jt¨Κ2H―T­ΌσeΪ⏍κhjω.Ua™i€²π|Β3œ«αp§UE΅pΏž„A?}kΊτ((Ϋ<Œ²ΣΓ©4nWs„£ΊΘ‚Ηξ^bž?ρτa.‚:°ιšΆϊx›‰t«Kεo3!Aӝ>< ΑόψN>ΌJ_MΝο ³Ω|©7•NBƒ'‹EfρΒkΤŽβα ίΛΤpƒGΨxιE½k7Ξ«έfulίωЬωΌ~Οχ[„cΊξ˜E€Ψι†γš,P©…7‰oΪΆ­ι]ΎL,ΞJVr˜)α γ– ”yž’8Γ³;―vΦ₯‡ί¦Ρ€#'φκίpU.Β C†¦›π]8έπtζ9gƒhσ^­/•1εzκά7,‹1ˆejΜα–Γ|μ€­rίt©νυŒωΟΙzYN4KθΟηϋΦύˆ†"x―ϋΦVM`qΩϊ,;$R³fΗ;’ΕdHeRͺ–us/\œΚR7yΦΔ¦y‘ ϋhPŠSφΟFσωP“gs]q4Ο·‡VDΚω0;hυ~ϋgΛJYΧ]u˜&O"ΰτ– ²¦v¨Ϊ a©κ°ίgŸl΄:nŸ¬7φIΔRFDϋN»€ά¬γφΘΏά΄Cvͺ€―eόAΜBΉΤ/uZгm‹δ?€Ή{6‘Αςwq’Nώ^$8ΈNHΜ$dœόώχ“Ωέσ}_:VΨCώn―ϊΩς„νaQΡ;lΟtφ2Ϊt? ϋίσ ΐ—Ψν±ώύχΏGixƒό†Υήmτ½‡ύ7γλΗ2ͺί¦θΥu ΟΖΣIΎ$”|EbεΏPΚα…ΧoςfΕ‡:=.υά£ƒΠυΞ}ςiƘοΆϋ_ψJ/£,šζΙ”Ύ{w«ϊΊές1mΜ}ό»/ΌdR–K²^ƒΤωEΈ&(?Ÿ°Ÿ1υ‚#*ΏηωΏ_ύΓΆΖσΫύ/¬τU_†^E[žΑI^½¨'&±;δΏ‘ώίΧw=‘l= o9x³ιΘϊ€κ :^ ©±p„¬|ΎJΓ,αF¦­ΌFJƒHΐ9’ˆ—?wΠhγωΏνώο}«Ρh1_&ρΕ’δόΩbΐ©όBΧΧΨc¬~όί“±žά±RΆ‘Θ»EDšβt»Ι§Ωvƒώ χ+cZFOΌΨ>}ߚ²2ςHR ]αΚ₯)₯hΡξΞ΄fMΛ|‹χΪƒ|ΖΣGN;ύ³Ρ£ι:Σα9sN9Ϊ^ωυ+™ΣZωΦ₯"Ό*―q‘:KΛ6 ‡Ÿ)L% †O!n›²έΘώxΌ c˜ZΈήD|Να0%Œ…‘qr€$Τγސ₯‚Ÿ+^B }Τߞώ'UKνŠd«e”ψό…σΏ¨ΆΡ!!LŒϋWω―!ρ§W)‰Y! E°Β£’[;ψ‰±6ΐΧIΚ—$y€Υ½·²5 £7Kό»λ~•€J(YΞ>ύτOŸί‘¬€»θGέJa p!’0 ς5›Όb έ"&e?%αƒθ5zυΊbς›ηŸΑ WΌŸ¬΄>£°A…ΘΚΰ$ΡͺΩ=δΨAη.ρί#ώΏ-ώ/½θEΨ?­!έŸo:%Nλ£ώχ6ψ’Ίυ˜Ÿmœ‡λV›Ξr―ΥςRjU”Dl·‹JSΆ(β ?§όˆ,’n`ΰŽ˜Y ™Κ`π!R 6ŸΌΚ‰ψκ#tΨQ{@v™ξ6y2tJ―Π+@ΐ«φψσFδSΎbϋ€§gτΪΙ@|²,‰‰ςYΏ%qb‰ςšΙ{3&οΥΩ„^‘ͺ‚ΗZτUυΔƒπ³­€—Π]ι}φΏξ{ΣυvώΧΡώwωΆΌπΛλBϊwT~šCŸ€ŽG¦Όή‘hΔ(ΟΞ C >+OkΈ€\”YύΏo»Υ, Wrό(ιbΟkϋ―[cύ·Ϋγήd󗬃n&eD| ;:n‡ΓΙΙ[N%†χ±F§ξ]0:Ϊ<`Ξʨڈ|V„ΰ±re•ΰA…U«••4Qφ9Ίο|€ψJŽŸ—Σέ΄Ζϊοwάk€ύLMΥjϋΫ£ώχςί>–Ό°z¨s=άD*RΚWΉ$ΛXπS&βH];ΑYIΨNυΣε«ψruΞ-T7ΈV ¦'ηš&q/•Δχ$óߍΜNOϋ>F§«y/“ΣΥX28}Ή hΉ£±θΥι7ώΏcό‡£ωŸo»eό;αβ ϋh†¦·ύμΡητΏΟ7M²Μηd=1ΑϋΠνΊ_0yΏ[H Z8ΧΌ‰ͺnΓ9_o0=ή0ΰη*”Zγn'β_°ηnϊπ8Ԉ'SJ€‚†"ι&ŸβχZ™=π ώ Tλίν”οxΔί+―Χ»‡7π>kO5ΜŸv$β7Δwπ²Gίο‰τΔΟ`NΡKmΡ[ύξBeό†‰tτUτΆ%εΐŠ ϋίSΊ"qΜ£ύύ^– ’³/ύΜKfΠ?’)ξιŏπ?Οfn•ψψ%™ŒsψŒΞ€€½fϋvŽφοŽ/g. ΆκŒώ?wέYών*€Sϋo:-ϊXrΤߜώ/dq²`ΕEtκY₯$3~)RΣ–)³•&²' γιΘ.KEq/Lν3-|’NTοΦ;βV©πœΝ§eνφι&Q43֊T†§Šƒ›]έ fηTν:Μe¦έͺdjΆίuΦꬓ½ϋ΅…˜η©—Ϋtυοό„€lšC/ΩΙej ΟxΔi$Ά6Ιύݎφ§Ζ)`Ζι~qαος“Γ옦ΐ‚ ’Ζ(‹»ξW©pWΖ,Q'ΎζΆωp}r'Ί|ΎDύΰ#―u‚Ύj,gωPθR”Xνg“%9Ω7Ÿ΄>ΤδΫΦ‘ΕOƒ΅]χ|Ÿ‘uβΪΈBPμ>όβQσΰβMqHφς΄ΰΟ:όγύ£ ΐ‰Ÿΐί"9ό‹ΕœρΨό·Ά’’¬a±'άέΕ„;2«ύ4$uY¦O^mΆ~Š?ι‘X[kuL‘2ς{ώοΆόΏeρ·έ΄χνkΔ2Μޟ€€ xώΌ$ΰ'λ?hmώίλ?έƒoδσ|ΌΈ•ςMΊΧvsjCκ?τϋK]Λ1=ΛGχο۟gX.Α"&x<7Ά­απ‘Ή¬Μ<ί§χ›Wλ3_@NϊYMϋ|{Œ»ώG!&l.#±fb{ΨόiU$RƒU]·›δ ‘<Χ!εی#45•ψF‡ θ™₯CΏ ±ς]'©ςš­ρί¦'B?©V"5P™σΟω„ΰ|ό›’υ_nLWaΚpΠσ’φχ:Lnβ«›VGώGcΤίΟh°œ†AӺށ ΓD˜iΫu›6νdωΣ)νw,ˆEC‹o΄MϊYDόŸ:Τρ­*³BχΫ 3jWEƒ0Κ%j{u»mž0¨™…iλ»f]cY|D*,]€€œ’œ3 L;ΨͺW‡3RΎε)]qευšΏ‘π;?K:‡},“4,h¨πξX₯Iœl³Ά?ή·αr•?qό[‰“xκG@Θ±Ν7PB±fξΦ q9y΅JΦ|cξΡηΙC˜Lε‹“WaL£-γε΄ œƒZΡoΏωόΛ?π%^J,ΐΟτٟΏώςΫΏ|]όF²τ‡?Μ0ͺΠΎ{>FN> Δδρ’:·–Φ΄Β ΰΈ.«οPŸ[ pdη,y>›ΐϋΌ^$8ΨN‚-]e!ωηδχ“Yέ£E>˜ΎSŠΩΞP&Μ=ΟξώΊΊυΌΓwΝnΠI΄uˆ-³ρζS³δ)kΎ ΛτΤόjs:=―Βmaˆ¨ρŠaχ2žγnm0©ιαA‘?ά‡KιΤ"―γ6—ϊ‘jNΠ»ωφ¨»νώwΈˆ])άΙόίzΛΣ1γώίZώ―'t©:ώΧs΄t˜KOι„ΨFζ'} Ος+μυ!lϋ=+ρHƒGe­žR²ΥIšlc¦όύό/ί)ω ™δ—‚mLρ…μx¨ΩΑσŽz†γη: ΐ.ΑΊ>β»νΏŒύ»8ikι5kΜ~ωΏΟ‰όά€]DΈημ ΨSψ#˜Šdϊιfs^πn9̏=hχΖη.υ_ΗόΟ·– ϋ/l»(Rrπμ2³ίΠύΧ4ΛjΫ΅qοΐ'1ε‹2υ£&Ud¨ύY”δA Υ'=°Pz·Έξh³ΙI₯pΚ—όέΠΤ‰ΐŒσ²Ρ³6Δ²Έχγ<ΗΔxπWiPΉΟ£©ΰΛ”€;AξςW>‹YŠξ_p»Tώ(k‡Ž0χ4¦½,h*0UΛρRœΫǐ? Υ¦μ\\2Ώ‘Σμ ’ςHχ)2WΛY%ςiήΘ{=GP˜ηαζ˜t(ΝGrϋΛΕ7φ1¬1ώλΆϋί‘Fϊ?CνЍωŸnCΫυzEΛΞtQ·κ΄«ϊ’4%»"«({0wΦ+Υl™'d»Ιͺ”pεΊ›{κFύmχΏ«VΙMό ³Χ4ΖϊχΒW­ήΡ½thD ˆ•2FΙe|Ρ!(κ=}ώΌMrήίι&MθtMhštF$ttΨΣ°ο°o€«”BwΫ’θLΩφ±oϋ&΄ Eq€E/6œs>²‹}Σ(‰ω4\o’Lφί1=ώ„>™F4 ’HμO°•α•θŒf8±Θaœο―χ ΏΔξ ;qsθ`hx‡κ 2Φδλ Κ*μΓ‘ΚM]μΔŞ'δ1 ˆTž‰ΑϊΕΚαΏϊΒ*/ΧΩR†§±mJ“8K’ς3˜¦ν/‡ΛŒ=Dd‡AŸΕ}Ρ~”­“­π>·NβÏ σςΩSΚ=’WΕΧδ΅!ί-Cm‘.+wΝΓ₯uΈ΄ΛK†JςG€k’—ΏPΝ/ΰ,MW$fΐO1{Τ3—ΛmΘ ŸΡ¨ΌΏ H–Χϋ›Ϋ φ―Ά§Έ:Š\𒳇8yŠΌ‹Ε“LkρπˆB|zS*ΞΛyΖιώ&²U[ΡqBB&ΞNβΏ-{ΔMίζIytx–ρψ±ςK—³’7ΈYYMy;έИ₯εΫMq7[Eπ‘ jN€εΓœή )~‘Ά?£+VF-—·ας= Šβη6~ˆŸͺžS•K* ―έ&/ώVU'+ψU6ˆ%’žWς"εΛβ γ τβΘ‚|=ΣΛN3=άs [!χqΪςJ ²εΪfΪE‡όίέόΏtkτ0τ²yΉό?ͺ ΟZωΖψ{ΨΆžsίV¬ˆIΠ =Ϊ•β ₯¦lvΎeΏxυ₯¬ϋξλ%Θ?φD³Γύσ?ŒφdAΌΆν%σ?8V›£ο=π5¬w…Y^Ρι7=Ε ΔPσλG€η“οyb6'ε+iφV YHY“zΑh€ Ȉη—’"eοu•‚Ρ)ΤƒsΦ„&Y+4$k4яΎ]θ':ή—bΤ~ ŸuώoAωΏΫβΖŸxϊ0›ϋΎM£Ω-ΣnΛζh½ώ‡MοK xΟ2ΊΓσA\·*νŸΓ’|KvοΡ#ξu Ώήδ+ΙYe[‘.˜γο•DοψωΏŸύWsFόaπ4Ώ ώΗΆ;τ?ζsό›> γ°`\Eϊ·υc™ωΗ{I7έ󄃿εaζRΣD(Ѝk*%…²ο5Ο #9ΉΐΗφ€mρ—’$φέ7άhυλR“αηΆϊ[ωΏγ²ώ{J²U*Ruaΐδ=pΣgyƒžΔV+§£«£Ο=τ?‡oDwmr ½ϊΒΊ{Ztpβ]FΗηζνp­Α„¦'›2fύΔκkβ§!ΈςΓ#ςDy½ΜΔΕπμsβ°-²zΈžsώ/₯ΰG3Gύοmρ!ίK?ΪMoΕϊ(έ/€΅ΗRS€£¬?κσέΟ…ψίΠΝ1Γ}τ2}/όό9Yˆ€—¬Ymϋ―₯›#ώΏΏ·"Ήώ³•·σηd*ЇΤΛΔζ“W9=>ͺ3«·KτM†*•O:μΓΈj?o„ψsΕχΙ™―ΦλΝ;/Yχs°­η‹”,IL”/Θϊ-‰“ǐ*―+EΪ7Λ5 £“άkώRΨ’ψ.υΏυQw§ύί+§+mžηω5lΝΆώΟ¬ΡώssϊK$Έό?y(βλΝ*DΓύΫ|U\7UqΌ-€!A~ς멃7ΰόίkΊ:ž›ξϋ„_Kx2‡έΞ‘υίξ‚O€Ϊ}†—TW&έvΘ8ďεHΜ”?°ψςϋοςύBy$ΐ‰ž›rO¨F εeηJ*ΐKόΏΰηxώο·ςΔί*“cvδχϊ??Μƒˆ,³½$ˆ’2‘¨ώVMπ$ h!BόV«’"Έ‡(HhΌ(%πxDΰόσΗόO£ηύφ_―FNβ£-™Ζ(} όΰ*ωίλh~V]nqώο’έγΏo»§Ϋ4Μws^ _Ν“ŒŠ|Φ”§yv)!8e±Mί±ώΧ]ψFύg@Γδύn!s‚‘΅ρšiΪώgΆ"z_0ήω…6έηϋu1N«p^λ§φδXΕi’όηǚΣβ’ikhΓΏF$Η\hΣlΓiΐςfΫ Zτ‰”UππoHeέM6%€ •0.γ]Ξ”‰j‡zŸTχdUK˜ŽœX+΄¨―yA¬;| εΣΛi‰™6l=ήρβ–=}ή?SOMyQw)–?Ϊ]]šί―ory;χΏΗ%NOεΉωζΗωg0©―ϊύ  ξ0ΎΗdώΔύT|±Ή'£Lύ«ΓW ΈΔί°F;ο±ΎXό―e΄σ?X£=δCήv½φEξφβ:ΫΕ‡« ¨:E]Θ}Ί( GΖ§οBV!εΧ§Ά_Hκ/Ζ)θεTŸK(χΙ³ιε/ΔeπœσΓψ_ΫRGύοmχ°mΔ3άαMΚƒΉˆρΌŠΰΙψ_§ΝQGύοπ―‡]%€œ•?σ|ΕSŠ$αuοτΉU# e IΏ"§κιό_A ΈΔۏη–ϋΏΟ‘¬7IΜγ<›—ΕGΰIφ’ωΫψίvŒqo―{VόΟσ#0Ι#?ςHZΡrqΡOZ°y²„Φ¬neGδ:Tρι§zς#Liύk:7Ξfςνχ_l9¦&Le@ϋ\HΩΩKζΧ £]YρψƒΆqθAίΣƒ±\ρ}i—Ώ¦Ι[Nsε ώΘ£dƒUԎΚ—p&•MΩθΒχ‘ŸηύΏ>„ύΏN€“φ»…-ΛνwΐkΎ^“Ύχ;ΰ<Φ$^F₯¦ς Seφωθ-? †χB/Qs’G‘Ά¨) Θg%oα•Ό·αςΞ†Λί$₯+iχ?κΆΠN“ψH°†Ž΄¨ž‰u8O~ΚΎVvƒƒ„PΗ,`aΔ{rθ’6ͺXξ~·†οHϊ°Ν”rΨAΌ^gβtΧ;Δ*qώ»3!ŒtωW‰Ÿ©ΌΔίFϋχ¦ uυωN*kžiϋD;κκφ(έ^Gβέ*yjΧf¨5 sž dq²ώNΕ›ΰDŸBξ<Ρ¦]ΐΎVœ~`E t<ψγ6}€9§ƒ7πΏ/χϊφh›'4‰ΰEα€§`]qQ€NΊε£ TE„/ τu ŸM^±„n­*~πcjGμΈηB§ΧBνmdLδύοΏόμ‹οΎœ­Ω7†Γμε`ί­t#ώŽοΗΕςXοΖϋώ??ΣuvΕΔοCιΏΦΚ§«£ύοτMb§Όλb)]μγΈ‘Ίb@Aιzχ “T½χCJΝ)±¨«₯±΄έ—―Ε\|―?›ˆΘπχέ6|Ο#BRμμώ‡σ?ΦΈΉό‡ν•θ „xšΓ|iOCoε΄lsŒΎ ώζ‡i# Δ*X`"δ€»];:2ΕΣ,“!£Απ&E–¦Ε:)“Dxp3x·³7&U%Œ5ΙιŠg{MΗώϋ›”#lnsΞ¦‡0ŚDΡ#§G*ΐ?& ’ΪߝœςΝ“EΆZσzd[y³·υ’LƒΥρ’tΩ¨|θ`uΤδ…Α?ΰ°»C-ΔFβ—φ₯¦]λσ~€ŠC­ˆΕΖlT轂ž+L[”0i«² …«ύσ†έͺ™ςΠξB·‰¬Δί“μd£bοšψώŸΆ:κξΎŠ|aϊΟΪρΆ>;Θ°~Δ‘@ρ`!+ ²ΪMX?κ-’u׊Ύi²s‘) zά€wv<Ή”ΆΌ7Ύ=(I d9ϋτΣlΣO?ύ,₯ΚP%K€φ7R%ΨΖTΞ$Μw"i#ΆHΆΉςΔΙƒƒ†E‰i³4AOF© ρ b¦½Έϋε σΡώ{wόΎη‹ΠƒxAUoι0ώ{Δ7Α— Ψ£¬}j@jΫϊQ(„΅Žόώc ¨_ΞωΏΉχXεΖϋVΚyAšΔ90yσl$ΩκωΊόΏM{ΤήK7{‹Š<²ά"Γ.€ξj ’KΆ AZX'ρίΝχo"ΧϋˆorJMΓπ KΣ\b3Γ fΐ "±˜κΎεh ΖνzC"”&ΖΜ<αŒpβ2χšv/ήw;0·Κ±DκΡ6ώŠο•qΜzγύoζ γΨ>Qj!ςΈΎXώw]kΧSΝ1ΛτWΚΫλ›Q…§‘ ύΒΞ σΏ;ͺ:ϊέXώΟ`6ΉτΙΊj πIϋΡΚ«;φθyό_Λ‰;Μα{€ŸwŸ`‡`ΫΚ$ΑrρHΔy­‹βή°LΔƒΣΖDωœ¬ύ4d˜2+‚ίovδ![‘Gα,γ·€#OΘχ΅ͺΦθUTρ9όΊ$š(šά‡φœ«Ζ€^ιhcώ‡ϋΰβP]‘œŒΡvύΗ1οˆo†Λ?Q&ίν”οxΔί+―Χ»‡7πΏ”hA rτ‹—aϊΟυHΐEυμΡώsγύoΩς]Δo`±:πΏ5ζΈώοςŽΘϋέBŠώE2½'=°PΈvλ²Δϋ«.ΛrΏK~,ωοΡάB–έΣo”,jgγmδμTΚ—όέΠ,ΏžΒ“9?‘ε·πmλψž•KWΐ”΅ιAY›Νb‡yαοL^‘4%»Βη]Τ 'πѐ Ο:E{Wφ–“~#ΏΓnϋ²|rιcέrγΗ~š<σ€φi"χφΆ0OΘ~«Ϊ0Vˆ’„.J„}Ήg9­fœ@̟ ‰Ώ]Β2₯œΠ:1ξgoΧΣj†ΌΖ9FzθξΙT’ϋIΑt€IΐUέ ΦκοEI^Ό©υΖ&`―°OϋŒ”"RΆ€Ψ8}fˆ" Νψ‘*:Cc^…©ΘΓu%ύv΄M·²½v¨Ίι‡,άΟ°Ό™ρeΝ£_tφ˜ΘDΏN½Γ– oŠyg'r΅m¨βΐ3DυΈ‡ςf;UΈ >eΚαŽ(Αžš­ŽpΡ—QβΧΏ»ΏΫnŸ―#‹?β7';k[šΓρwk²9…ΊBQκP]kύΡΊ·¬ϊ©ΘΚzΫυ‚nΆYcΘέρ3E@#~fΑΡν\[}eφΣυΌΨξφ€ ³£+%ZτΌM“8/΄lσώ6ŽΎ Ο;”\5{Η18©šοθχ}AΡΰμC,Ώ¦κƒž·$νx«Θ{§θ*i(ξM„Žζ‚Ϊ†8mρn‰·ζ1P‚EΆΛrθ^žT‘ΉOr;²*πxΔR:Ί š$½ΫΟρ|oHz†²w*ΐ»Yγ'θR`5‘[±€λσ}§Δ.+*TQΞα+%s1ίfωŽ$>| W ο^rΦrν[CEηqq«˜ε4zΈΝ§:ˆx•Ιnλκ•cΰŽzΙ”Ξ«Q?d·}Ήϊ4%9―ͺiwHΒ>2Φ“ςߝό?œΡώAμβεσ«Ά₯·ύΗύΏ‡ώ·’±ΏZαD=8ΐό[ŠD΅FΪβ#i$8Υa~˜Z›λ+δOΕuΧh|νIw€ab>Θ§˜Ζ_Β‚eΐ’B@3‘;XMΰ95fκ^deθωΏ½hϋ πΑƒΎdύΛθΐcύΧ{ΰΆͺqHž¦n°­Ϋ;ΟΚυ•&h.nmΈD[π’2sν]ΜˆΏΩ„ΗΒ"$ςΨ7Ÿ΄¦Τ)Œ7DίͺlΫ!ΎΦΣI% Ο;~š^—jŒE ŠoM±ώΛ]φΣΎ*0Ψξ9Ζ~Ύxώ/ΛΠΪρζθyϊίmGμ ω$ΑC―ͺΫP‡!νTŽk„ο ˜@ά‘A―ƒuλέΆ}9.d|±&ο’ˆEI§Ιy(·"« Ψ‹Ψ—V/Gψ™Jχ‰>jAϋ]ŠύΊ΅“J…ιP3AχϋgΩ Z]T™’—ΰ±bΝH–_’xώΏGώ—1׍χλ<»ύ΄Œ\ξ€―Σͺ’[ΪΈwσ’%‘ž™}YΛ(‹¦y2₯οήΥPpε~Ο›1N<¬½έxΦv…ZU^l‰1;—ύNΖ$^š-σ‡$ȟHΚ•ΏΐΎώΆ«ζλίΉ½ξlrœTΐ™ϊ@=…»ΟuK€]aŽωο-οϊΟ₯'νZ«ώ·eZ#ώΏƒόΧ!θ΅Ό΅Ξ¬Λ^‹ΟU°žιΕtBΕΨ‘S¬9²Ό„Φπ |˜Γ!ηΉΤΰώίωΏeŸνrAό· 0ξνρ―Εγ-cΫ‡@Ξ8“Kμ?Ž5ζΈ-ώγ<šG %Q‘CH¦‰—!›AψrψίiΧ±M{τ»9ώ?^ΣρήΓΓ½…rE—½‘°iΡ;*ΆT·ΡM>πh—mύœ,³fWή°Ψσ3#Π;τCε)‰C˜B¨Ό~ΏίψεοYΜσ8•Λ±IHσYš₯3ΞMρΘί£©cŞΈΟή§W³œ²;ω?œ1ώόΏO2n›ήγ…³}”1:~uξJb \yα1ΠrθΏ*>•›o³Jπ_=Ζ΅7€Ύ½M#©‹j 4IB>XϊhΛ/Ο?͘ΓΘ’¦ŸA>₯Iz"4²+Jχ‰€›K£ΜυΊ²¬θdο†ΗΣ"\K¨1γxπΝ~-Yaoi'Ζϊ6z—ξŒ|ΛAz AŽ‘3Oh ‹ ήύ»ρ9ZVΎHHΙ6œ†AHΜΤ(Ϋ㯎دZΝ²CCŒεK“§L^œ’΅θ^Θ‡ΕπΔό zBΖ«|όŒΒf«ε¬L ™€Λ}ŽiψLž’hŽΑΟσ<ά΄Qtƒτ›ζΩV₯cψZV KςΏš0β[²ώλAΐίει^Ω>;@ά]”id^₯œΒ‰ύΧU³)ι&ΐΈ·§½ώgΏ~bί’κm'½$‚ΛΕ’δΌ[*μA€bζv1Wήh;Ϋ%ο9Ιz»ͺHieΫ‘iΝ'φMtωs4ΝΆtΐP€`N6›¨ ŠΣrΕφε\b9vΰsΗΣuΏ59’8G€šγ―€α ’wΚΩΕ±ςA}šs²nfn°RΨ πF_–ˆYωW±<¨ό¦ͺ§-Ύv$υh'6σrτLϊœSΌ ώ»i£ώχΆϋ_ψν]πηzbMΛjΕ–6ς7αΊό?ε=,>EΌδ‘υCοΞdSf>“σηΊxΆ­žνRσ˜Έζ :ͺ‡€κέYν* kw>»πWyCG%V-£Ž£εlϊœœuQ1›ˆΔ|šΟR¨Σ‘0t²‚ŸΛE°Ξχ¬ιΛ oΊ›¦Ye·|Œα,X“‚ψWβ)»χH<©νέΏ#‚/›)ъP̎ςμ'ƒfƒLΝ0™κ@ΫOOΣlΣ•E­ΞρΨm₯ :"}ΙξXρThUeθ ў–Ηγ…₯«qoοΕηρ±"€M%ρ2*S*bΚΑk&Β’ϊEJ6…ΗΘ?&P(ΰ…$‚ ™³φι₯ Όζ+i«δIέΏ&Usu΅eržο6|ŠΡ]π(„SEv‹(Μrq`³ύΗۏ }υυZσύ“l—Mj~…€t72y#N ά°(_’χΛτ…R—ZΣ9E₯νς!τrΨa όJλ΄ο?ΆLJ«€kΐΌΥ»xZΆP¨.ελg½ͺΰ―#ΗΚίaq^/Ÿή„qΎ2H$uΑ₯xsΪ 3ελΏώM!”rX%’s¦θ_(rΐ°€(ζΐ*Š–ε“σ ©•xυEΊ+ot`Ε+±δωlBƒεοHΌϋό½HpUώ9σ‘&!ϋ'¬:μέοΆqψξ%NςF³5‘IφΟΙοαΟdv4=ϋΛ~nV‚ρPcŠΣXξο4η„ζilcΆWι [ΌΈπ·Y…4;δ–Hό·}K0δ{3Ρm2Μ°YiήΡI=Όϊ_WΎ²PκυA ӊz΄,9 {r°―ͺ³‘Ώ|=·Ξ,51΄ΞΔ³ Y Υ]SθΦΦ]Ε~ΫZ«G³ω’Ϋ―(œGWͺφ ŠίΠΑΝ}.ύši\‡γ΄9Θ&‡Υκ­Ν‚]š&b³P"Λ.ΛωΛ“`xxΈŒ§¨ͺΙJ}¬ΪΠ”\E‡-αTμǩΦσ_ύΏSώΫύ?﬑怗ηTΫ±;φδξΐ΅΄=m“χKΨ8ϊ‡cΖͺKσs4tŸ#;›­HΚ™βσό‰σX)*Έ…‘€ΈΏ+ΝQΏWΠ¨‰Q 0Ί\I‚+¨ ;λ3• WŠ?yώο…υρόί/7Ϋ«Šώƒτšν΄γ?Μ±ώλ]πAΪ―‹ο…/«M)mI[)uQ‘,Κ…¬_‘§’ ηŠ^o€Mτ™@πœΤTρpCΖΟ•^ή†£».±;†³Ίψ+ θ?ΏΈ!Έu}‘3D―— ~ρ~ζ@MΎ#ΡΘΫVyύπ›Vχ(‡EΟ$[m‰ςuš<ΒΞΌ~ ?ίΰ_Kq£T°ŸGάͺxγDb“ΡŸό—‚ο§ŽφίΫξ鏞}›M6/P ™8—ͺΝ§0Ά:΁,œΕœ”Μ¦ό§k–:ζΉ ύΏL/Š1€'ZασΘŐNͺL νdΫΒ›<…IKXχΫ3©ΘlZΫΣt&/+ Μ¬Γ;ΰ"Δ?Ξ‹‹„„L„ƒ'ΗuŒΜ.ΓϊΕ{g˜Ρξ•aŒIŠK?(―γΌΈHΉ(ίϊ$ω€†’ή@#Μ‡wώΟ‘ Δ Πxώο’kOž/žΪSmΙ–>ΦΉ‡όΧΆ6k»]EχMœσ5‚Ϋ<ŒΒ|§δ‰²ζ$Γ(5_£Nl›‘ˆΖ΅$λG©Μ7?Ξ?Ϋ`"ί±β5ςύηΩbΐ%ω΅±ώγχΏΘ~³ψOUΨϊšρŸ£ύοψΏΏͺWΎΒ„F>z%τΉθte8+eΖ‹f…@½Ή+…§ͺw;RΘ‹L(0η\”'ΓΌUB'c‘ •€%Σ£zΉ?‡Dω–μήcΚ”Χ1όz“―x$oτλΫJϊUd•x!Ϊ‘σΧψkδξ‡—˜ μzTΰ$oλmΟ1ϋνρ_.€sσυβρΞT:ΗΣζ¬CΊ"/±λσRΊ φJ‡†PΕΙ”’8‰C*όž§ψ½¦> ƒ ΜJ:8iœψ Ϋ½©$?οTbƒ‘ κπσ„ΐKθΏͺςίmχΊ5ίΟΨΗnϋ«Ζθqϊ”€ ―~£όΈβ€ύ±κ9ΖΌL$Ι' ΕΌkΩ'ΚΣ*€+ε‰+2k›ˆŒΑ¨‚JΆΝ4BƒΏ"½―²™μ,L•<%qΒέ#WͺLΌήΜ+(ΎΖ4Ϊ2( qaŒvПx#ΑfJΜαyž(>W01 όXρ”ΟŠObήbα^Πκϋ~BcΠ[Γϋ$e‹ Iσ šRός/zVE[‘MόΧμ՚―}.Iη+E™Ό•"QŠΔslž­“$[M>©<Γk7žHΆžΓbΖ< ƒβQŒH部Ύ1GΗq£¨ΐ"žfœnΣ†Ά&1&χ›gY4O2…€Ÿ)OσLΆ+kwˆΣ\5J€ž’l…Gi^Δ·/Φa²νz³x‚/πt…ρφέ±·€S€‘NΣ*›©Y ΅asΑ”Τυ:›A3_Ύ+€A‘²&;άt„@xΥώnηΚS6Η64ΈΓ4L)6ϊKYy¦„ϊ2Ύ  ¦ŒϋžJˆœ½βr8T†ηsJΆptΒό·R Mœ#]‘0V=ΕYˈ*XŽ(•€Β-πU΅E€γT€£"1J€•ΰΪ¨ 3“0’>&Εͺ6€ΉΡϋa”Ή8ζΕ’Θ#/– yŠA ”)Y‚Oa<–CτWYτΠΑ= ΰΔΈ€?Ι±!μΔ‘„ ^ŠvννΔ“ήΒ,Ÿˆώ`P€ˆ˜Ψ‘Ά{7cj‡ν‹Ε[s’ωzcŠαS)[ΏN·XPαϋ‰ΝͺŠτqΤ„,uό @ΐ\œ”†²9θΝfWmlίΏΗ]= “Λσ}:,Τ#“K%Α€l¨³XφΤ7Ι ΧΣ²’’R_ΔΣa¦ΐ)y"¬!όώΆ Lσ2ζ·―φ_”y@Δ1ΕΚ !&„’ŸΩ΅ Ή’lS₯H«‘αNΟDΡJ²Ι‹MΝx.ΚA!ϊ†1 –‡yδ€»a€¨ό ‰œ64έnpVίύεΏίν‡_|ωΥgϋφΗΕWί~φυ2(~γIo}γ ΞΒ.ΐΑUΓ€θkX$ΫLIΰ½±F.ΡMΒΞ@z’γŸD‰XΦ’ΧW΄Wi!~I±.Κ“ύ5γώv9%œNœEvHΥKΥ*ρ« α¬θ>εŒP„ήψDG·ςA«ίί(ΩδαnIrέΐ”Ε1Δ3HW ATτ*Rί§Μ•,ίEΈŽΥΈΨœs˜«λžm«Δ1=ζsSσˆεp’j,π·LΛΐ/vς:'Ύ½ΞΒu;+8'σΞfΠZŽFhBtP•Y¦―N ΓΑΰ˜Ι-Ν§jΰƒ˜Γ-ξZ:ŽGπΖ€°"`ˆKPΟ”M€O|m½Γ#‰Ξ΄p`BύY"jι•ή²Ϋh ² ˆ™} _θ˜’Θk„]η‰ό<Μ²-P[sΌWo³ύφ―‰(œ‹‘Mawq*Y”δk²9E䆧%ϊ9mξ_6ή֝ν9ς)r\0šcœ˜–›H@/‚©G€r¨3€›±=Η²-έtίfpbt/ΰΊΕΈgj†κkfš“£CΑno6Žί(ف‹KΏ@£}(Ππ|³ΝgΚ߁%$©pDRΫ1(Ί} 7 )ύ”πe¨ν™M Μ»Q΄€ανΗ·EΩ8>€]E:"ufςOŸπΗ'Κ² ψp€ΐοΫι…T*X Α].Q‹R’ΘV•šMx«ψΨ'β"†}Žmγία3Σ΄Y{RkΔψ½‚§]{GN₯L–qδνj³+κ[›ϊŸ(‘7ΥŽc™j[£φ[ό)Έa”k*ε Γ"ιΎΏ“‚!ž oςςψ„BωQH koo–όx9«X ϋ½β§½Aα›8ˆ€Έ%ΝΤ&pΆ+e ;PΡ.εΛ0ΛΣέ9NΔ‰š…ΙCφήM^ΙΪ [‘0ΰ¦αRΫ0-ΧQm¦γ™¦ξ˜†O·©λκ–mz.·MCsT7°Y@-]%Ίmi3&έ3 ,j$fΡfΒ*vέΑ뢎*q“ΊŽ―qUσ™Α<7p™Ε<βΤχ] x Κ™ojA@©Ο9 ,Ο †πΎΑcφΖfY ωΉκΰΓ Lβ2˜4Λs5Ψ $Ι βZΎ ,·τΐpˆα1ΓdDZeωY'šέ?ψ?,€9rv―<  ˜ΕΫr#¦8¦ΞlξyψMΧ΅\Υ‡yιp}n@Mγ”ΫπC²Μƒ]Q, νΡdΝΧt•JαΎsв~zž ΞΉιβ^y’εΩ–oΓ†Σ™BυΣ —;kΟ%J ΞU¦η`ψΎPZε2@ΨzοN¦±le1dΖοkNƒyœ©ž―Ή†mq¦{stΑφpfygF·ƒ@g:Η€m₯”ΐΡ|=°νΞ½jξΕ'pΗε€πgΕuJώN–Ηφv·JžZ˜ΓΌφbhAμψΜυT`ύlΥ#†οi>›ΐYT-Mwaσ,Οt½ΐ£X,ŠMl­oO7›EY`³gcEΨφB’#Xžj]ΧΓr)“ /― σ:ώΨ;ˆ_ΆέΏΎec7\9Γ‘ 3A"χu‹XΔγuM—«–a›ͺahΤAΔ¬ΩpŒΑ9 B€0ΰά%N7j8 “-jυτN6υΓ₯Β<]{²ˆ 5ΔΗΰJ%œΑΡ—ph“₯κ€Φ9ΠSW5YΨά΅= P‡gڞΦ9Ω’DΐaG&š’]Κ›œζοΏκ<‰ ΈάΡ,]ΰ}pΎΐ ·ˆŠ5dyΐ@ §”Z†E=W%†Ίœͺ­2fIΩoόœ6Ζo]cΠ ίΦjƒ€ηr“;₯[†ψ–ψΡV6Μv,ΝƒΩ"4@$δκZ*@ηyγΏώ‘ςΉΙ¨κhp3 Γϊ.H X ΔΓI€Μ›fPΖUέ2-€<Υ°€Kΰ‡X'œ:E-fΘ0fκ.ά«˜™z˜Φ(2ˆκΣf횁 œœŒžε‡45πMΗ ͺιGΗAhοΖΒ°DΠ€!DTυθ\ϋθBΩ‡YΒ€Ί&ψΖ<βχsΩΙ4Νώ_ΤΗqΣ LG%–©y†es€ͺ–Γ)pz ˜ΐafhΓΞ)† Ν£=FG΄c“E•Άfj^ϋĹ̐;7LΓ±ˆγΑ„pίWMώ4€©ŽΜ0Χ’u΅¨#šΡ ±Οk1_αw-)Β.>2qQΔ½ΕΩ_†m30m`5F‰ιNψRažiΤ₯†mΆaΩ(™X ­θ.£ΐ]8ΐ]τφς‹΅τ­»Ά|b»šο9šn€T8Ά―«%πŸ w|ΧΡ\κΑρη°³.³ΚΧgVs- ƒήYδ»Η™Wηu}ΓσΉζΒΊ2 PŠFΣπ=Οt3@°βž‘z:υα±5314ζόG'Τ­xΊσ)ρΓκ!™j€³μΆ FΉίu0ƒΧ>n Hοϊ*ΥMǁΙλF€eέA†7@,ζ¦ΚAš΄cDwpˆ d:°QΗΔΛδ·'¦Έ(’7i˜ sFs›«k/(§€74jyΜUυ`,uΝƒά;H˜ΜΤlͺ‚ CΉ(…ƒhώαδ9[ίΝ‰Λi(Έ;š*6˜ωΫ¬Ύε%SŽώ0Γa άΠθ[HKαέ0/;™κ‚²pA¨†Ω&טO€2ϊH-tΣΤV- L33΄a·„'I"N²{—?"cΚkQ  «&±3•kF·>χ₯€ˆ‚ΜTΈ€ˆίΑVzύβ’šΈ&ΘNu―9_―ΙFjkCή “ςί).8›nBΜUήΫ²ύυSMnPκ™ρFž<ύΆ†y<χ7¦Εδ˜ΏΠΝ³ρSι›Τ">κΏ½›Ύ‡ιύξN}4GΖ¬oW‹[SΊΩn’$ͺmkcαO-gα ΦlΧ `7Bkzmυ'θΨή –ΗUVΫ:²ΗpbΣέT8m RPϋβœ8*+|>lX ¦rSw›λžΛ`[)7`aσΈΟ¨pΞρ\Ν&°ρ '«ε9ύ[^pZuόb\b} ΐέ!ζ:ΊξP` αlκ·΅uΜM 4Ή&u,O₯ͺG‚ΐ€Ν4rοEš¦·5΄€φΥαYgΔpΠ-Κ§ͺΫΨ%ΆΛͺ9ΜO 45†ΞUΟuΈ”Jsu•ΫΔ·tΓ@xψ»DΆ‡sΠΜ4!π{O¬±„)¦’GoΒΕΣ*Œ$ροΧvΐRπw‰Κr:-,τ*z:*qu«Ν5kΆjXœΐ&¬©η€dn.ρ–έs Νu‡θ„‘yΣGba–Ηxί:O­’A£dΪ u/π|›h"?Υ1T ΤωxΎa¦S#œYγΉj@<π«α۞幁ί{Β 8ͺqύκD—ααzΐ]8Α@vL‹ΑuxΙ΄H»0Σρ,†jq›X&AŽΝlORubό )[e«pέbΣ―Χ·¨ΑlέTέU95` bΤ’6ΥTہ“μ›ΤΤ‘ΞM•q¦y±mΣσαλτ>‰Ίrδθy›iΎΆΞΓΣWs5β0ΣTt9!qmΧŠ Ι·T‰γOΓΥέvaή–§> σ£:dTΥ£“μ΄Άwu˜€.εt‘AΌΕS!Ό,·!Ϋ8"ŠŸb΅q8‹N±ZοežσR.Ψ―6š&z>ˆ{L[†jΛe φρQ²δ)F Δ`0±Ζh›qθκ̝Y=z’2ώϋ¨υψ„½Ψ€ιΎt0n’ οΪ<‡kψŽOˆ―qΫΡ x% Ί&ˆ~ͺ2ΫΧ ΐ&@ΏK¨b §sn3― ,H·ΐ]ΪF?yu0Τ)’ΪΙΕΕZάqΎ0Κ>ΆIΛ§F»Ίυ@eΐkΐ’x*Wf ‚έe†ξZšƒ‡˜Sj»&U]ώsTΩA ΩˆΪ<Γφ<292ψ©ΏEχ–™ςΪ”ΈAΐ±… x§ΫΧTΨ4 šͺκΔ 03Β4ˆ’j¨ͺiΨ6Θ}NΐM@cέ8JΞ`δ©„]π¦",h³”χ°Βj ¨„NΕ–ŸΨΤ}―ΝΝ΅νA€νδΜχU΅ΰ°@·  Œ^k> κΐ‚K8HSx0·EΗ¬^9wΏ }ΣL’‡5Ihϋˆ†§Oͺ^*,Yr’>ρ`=Œ±z½ΐˆ#R ½m:Θ‘E†Δ€XG@ŠŒ^\ͺσ]β8ˆŽ©j λj6·tcΰ8lΝUM`:T‹†ΈϋΞΊ“Οq˜ξχPί^€ώ6ρa―“²Rτ±ΥXoH”Τ–Α5₯―Λ„PΛγ T DV Sǟη–C9,Θ€Μ΅\fϊ–¦{Ίa«z,€κϊͺκΩF―2μΙ/­{δ†oQβ£δz.RfjYΨNΛ4­ °|ΗΣ\Οσ}ΝW Px+8ΏšiΜ92‰ƒκά»yu ‚7ŒŽZΥ3-Σσ(ό‚τΑ°l‡†λΪΐλkh:±|Σr-†φx›ΨšzdYΛJ‘]aWν€ ˆΞ‡ϊ\³lUγh8Α€‰Ε} {6σmί²©́«!@A zRαw0!ύ4|’Φυ©97)‚¨F`θPΎn:2•«Lh©ΔιHΎΛ}ξ »,Ae PJ#π‰αφμιό‘jqΦ€4νκGΞ+α–ζΉΤσΉΕ W₯ΊfqΝgŽAA΄α`8ƒω¦ψΐχ=ΰ]lΨ=;‡Œ‚Δ΄ œ¬ΐR烝%{‰J ,3‰φ‘Eρ’W§₯UρU‘΄₯ΐ·―ν;mG§Ί Η8LFΡσΜα@λ `Ξ€»ΣA”e Τ @ΐu4MtώlKΖΈaφƒEI\;*:t‘FV Ν~›•κ§O{~ΰ`―–H¨Js³­1SΟΰͺ[ϊπΨ½΅ΩŠθ½ŒDS`; ’f«Ζ*Ύ£φάkpŒ&~`Αс;t=‚°BQ;γ iΊDL`9Π_ |‡ζ˜pN58ŸDLwΊΟΟΡy ]@λ$jמΰA =ι©gϋ:qMψΠ ₯ͺ΁nεb~ ™άφΨ4Q‹n™ΤΡhˆ>²δΚ°αK΅Ζ•A‚Ϊ3ΐu0Θ,T΅5.48ΈάrA 6Ρ· ίδη 9>ΣaΓΤ^“Œ~A’d;©ηΥ=΄…qΒΡ<˜5-€0€ P½ζ©¦iΈ ]y9Π*•Δyv‰PUj‰}~j‡@νζΌΖωvό΅0Ξ φώΝΰ¨πsΑΡΆ‚ψΒ<|*₯#~Tς<Ω•N£#Ν38$½Sξ8„Τ·&ί;γ4‰“6xmUν#dΗ‘Ί.Υ Θ „PˆYž χ#πLΫ’ΐθΜ€@ζ \Έ0aξ}~ΐ΄€¦’·<V]aU qBIWΫψaΧavЏy|ΐ"œ˜6PΥΞΣ<ΗwuΣP}OΧ@"DPΔMJΗΧ,MΥ ί DU]Uλεφvͺ¦έαϊρTgΒr¨»πΏξ:ιΊŠ:3pΓ L•Έ†ψ›{πΝ†°A«ŽΣΝϋ/£ΔoΉt τϊ†©oj³ΦΡΕύκζ" d¨Έt-ΰ™MΥQA<Ά,]T†ζ!ψW£@ε< :P  γͺ£[Hv Ύ©ͺ>ΐF‘Γ ΦΣ“3Sόz—?₯Dz°lγ-ΘΣ§εGΜζΣ†΄ύΓ―­γΎ­kͺo¨πe σ˜°εšΞ-Η#A˜Ž‘·f€ΰΑ@`h‰Υ­£Gδ>œ{Ά!ρTζοκΠϊ]Ÿ–ακŽΚ „sΐ_–JM_υ ΧtM n»*てRΓ w©c»άœF]ΥrwΫAq‹i<σΠ]•¦„—™tLSw 7'P-Ψ) Ε¦Λ½ΐΤl4š₯<Π5]ΨYΈx6ΣΖύ  ΎΩΝ΅žΔΑMM~x―}’]d&tƒpΖ5ua:WAŒ75y€j1Ϋj`λN΄3¦U&Σ|Λ$ύ T’<„Όν”tu<μΊΆjͺЬΆaΨL'Ί‰Sx‹©Œ‡YΩΊ«Ξg‘Δu@―ΟΊ^A1{·h³‹x–½Έ’ΥJ¬½Ε\ΫσuΤFΊγςμάΗ`m}M·A¦πΣ!ΊνκρsŽέξݚΊ?a}ήυύβπΩ>&π±Δ54Λb”"¦‚aϋši<°™…gΖ€œ«Ύ› ^ΈπH¨­χΨfk“5ΤυV}ϊξΥ΅νœθ:œ`ˆιpSU ΓG— ;0€ΓwMNUhβzVXͺ₯ƒœ2/²‹πXσνβθα*€-ƒφ 8'ΨŽΰΐΞwA6Ρqk du•rW₯:U \ρ}šλ =!sνΛά\k“œΚΚΒχΓe\Ή3`ίύΌ΄djΫΕ``όAΤ·Έ= X'Ηυ ΜΤTΰ}`Š|‹ΨΔ‘Π€‹θΤQ^ϋα©»he΅ͺsΜή ΠSΟcŽI€Η‘ αDs—ΐ"ΗΆ|Σ΅8 s ,žμ“ξPΈι›€ΗΏε$Τ\Ό*2β©+7Γ΅•¨@WΉa˜ŽΟm’λl£sͺξ2ΰΖp1gCΰ;ͺΟ`1l H4ζ«Ύ<$9αc=dŽR)zQΜh‰pπφ—½‘£&η†―£‡œξι γΝlΥΐ §@g05¦μ7CžEκyd-²1αΪό€’MQ–eC˜O`Μv˜p†FGtk8Ψ­°λ†¦{jχΔQLύcΎ;8·)}qfX`έV5 ΈŠΗΔέπΐ«IςΡlΰ-β8N@,ˆ,“ΐˆ<β™=ۚcΔφA>π–Σ΅3,2©7ۚ€ί‘™Φ~3<%[§υΌœ Fδ»!“.γ%>‚I—ϋΧ2]σœτ<ΚV$ε¬ρpΏ„•0ΎΆ‘fΘπϊ"ρπ4βο@φŒ•BHΎόrtΑ [ΑΛRtσΛX˜s*fQΜ₯Ljl_<Ψ3·ˆ:ϋΘV¨Av†π;Ιy*|˜ͺυξ%x+œ¬H™~Œ!I©¬Pƒ\ΏDp€«i–pLA ΅‰θ$`Ύ¦z”f9 ŽλΎ¬Άij¨ς<Ÿwbλΐ§ΎFžαf~p7 +Η-―>λϊj›3έαL@³™mjςΈNtΝ€›ΤφlBΉΕΠ°¦™Ίεϊ–`h₯pΕ|sΘdϋέ(N.γ?oyΛiχκΙ€ttO5tΥ€–¦Ϊ˜½ΚՈα F‚nΐ:ΑΩΈME²'Ν3tΜ™ζλg'\ω&‘+Ej‰ΊWΓ)ž¬ΙΞηΣmΖa~ιςΈΧχ‚2-ΤΤ¨P–ςΗ|Ou™Eαόά½ΩrcΙ±,ϊΎΏB¦~Ό«œ‡‡kηω|Δ6Zdf$ *’`d ύυΧca ¦€Υ ΫΤ[’©HWNξΎ–<+[₯`]κ5<&MθεJk¬ω³{d;_y[jσ«»gψ »_Υ)Ÿδ ΉJΤ1­+½^ΎW1W­β°σŽ:Ξ'Ψ ινΦv„¦8]#ΝςλfκίΟrŒο γ6Ž£5$φ½―ψνλ’ΏΑ4ΧΕ+?ΎΣ²ύκ¬ζι#C–r•5Q°ŽM΅B²I6›œ€βΗjB΄άU_’1Φ8+-ΪΗώ[ Σ™‰ά›· τωyΓQ}η»—iǚc fŠ£±Φ§|τU²/)5ιΠƒϋRMξa#©’‘χΠfεΎΜέZ¦†­suΜη.ˆΒτ₯¦.GΫ)–ΑfΈ)ς²sp•₯8ΘαK‘€ ΊNΑ˜’°·L«ΕαF2œΓ-ρKcΣΣYΨ—hΙ4Ν&'₯@*•l9'.ΑY΄±ͺyΈ,γΩ)ΰγ„―ŠMΠ”~ΑϊL0ir{Ρ’©0ΏRΣa,:1VΌ% €i.‡PΆε§^Ή0Œ†Τ!dƒέΚmφβΆ‘―V4{tœ§oη&αLΞ.wŒ§»LŽ5•œ‹―z&*0˜šHΒΕΩPρΣ€uΨ΄>BΘΊyώΩFc{h{y[ΒsQ’YCύmΜhύžΧ/ύJΫφAp‘±ξδ!ŽΘΤSΩ°e"Β$ύS 'Ο)†T-S’ͺEνsMpڌ¨ΚSc²p;T¨&ΐ@=R©p#=ίPL|0jΗΘ–Α1D­%‚9¨ΓΡ!· ΟΠ£VR‹„ρΫh΅caFiŸ[걁LXΗΨaκ₯΄Ά&W5| 5£SΓω =T‚0θ1ώΚΚg& Ϋ kbsΐRγ9R2ΈΟKtix;*¨{“mIπΪ…ZΰάSdΫ9τΦ’Œn*IΥg‘ž¬&εΨρ­π΄ΐΥ₯Ώ8Μz*ό;ύ"BlŠ(»4e$<κΑ;!Hή* nœΊ’RBπΊ€kl’β[ψ*†Α\Nτ&©ώΎ ― θŽskCΝψϋΉρq–o„κμiAo³ϊόzžγc[‘Έc ”ζ†ςΎvoΛωλ?l:s―ΜώλϋΣIΆΝώΒΜŸ³c¨Νμ=b3“ƒ3rRtRKΉ@δ±ΙΌΥΏέϊΖ GjΦΦƒΩ}5λ}~2;+~ώv}ZN3Νw°3Δ­5Χ ³#oͺσ,LΎγπ!š`­;ΫΪ²φ’Ρškš|τ’GΰυPd9LΑΧΗΩZbo|°Ν6iΔ;½žž‡{“¦s`ιΐŠr @Jμ.€’ΰ"U.‚δ*PΉ-sq'ά€ YΥλΖζLeξυκΎFΛ§3ŚӫЍ&J(A ŽΔϋ ΝΎΐΛΉx6Β' ηaΰT]NmΤ³Οΐ»"žHώΌCΩ<ύÎΡoϋΒ€ŽϊαŒ›ΉΓΠ…Ž>(bιQiœΰ,u1-U IBaιm…νuήJA~LΖ΄dUι\.ςtΝρςΠΆuΥθ"H<œ·»Ο<Πβ8ͺ.ΐ cŒΤh*d!.τΐT’g’\oθΒkαrσ:ŒΨκΆΝpσΨW_žJΥέtu8Frβ_1ΖΤ(DΊ,=-ΆB«NΒ*εuNΑBŠΔΰΔ6ΧΫ’ΘλέμήhΆmK9.П|Τ–ΩΨl«Γw&7ΑŒ‘;…k1$ΐq’hMh–κ|«Ό”°w&4?ΦW1‡m“ί¦"I D-šΧg₯‹βP€’Br„₯²9Xλ °―’¦Aδ.ΦG s’Ξ—Ϋeπ…Œβ2<άWͺžmΠΟmέΌ{Όϋ"Ξ³Τςμ ώΪ5Ά υ ^m ΩΆτίζΤήλΫ‘‹Ύδoψ;ΫΏύ}~Ι qά[NΔΓΕ$¬€v§/₯D/ωΛ ©_a#ψ\xh‘ˆ΄2Qj-Vε " )Iσ7ƒΗΣ?Ÿ<5o}υ-v~ψσ…EzΏnmžγωLΌ•…Σvβ%φŽƒΖŒ· YΊ±Ι†BQw„š™-UOrΌDφ$(Δf*5B¨]j·-ΥiW`MX{oJ ΰZ_k‰ΐς &’—l]Œ!0΅ƒ/ k>™ρ>'˜ϋξ] Vΰώ~X_ιΉ»Τsά揧5hΣηπ°4 Φ;EopŠzŽΪκZ‘Ϋ XQœ1‘PσΤKΗ3°νΡ(xCε²wm€γαF’‘6?ZBsΟ­-±Τ•ϋŠπ?ˆ:™°±Δ"ε“62\Z Ω5_±_΅dŒΔ΅χΘΫ¬g{+!>ΖrΕlίqΌi§φ| m±ϋgΜVόr`VWιjb—ΎΗlˆ3l& •ζUtΟ"]ή΄Kn‹οπ-«Ϋ‚”—Υμμ­wš<­NήEljΈqœΖ$%°°P‘²Υ‘*†›τ₯γŒΪj@Aαξ…Ÿœι•?ήηυλμ Ώέ† κή<&$ΫΪcΘ"ι†Ψ†Ή’Α°ο}-cΣB—ΰ[`!!Ξ]WΕ5_DΓ…<œϋEΒΉϋ?ζΤΧΣ>€Œ-,‚q‡ρ#š#Sΰ–chπρ\ay­‰KEZ+`pœς2Ζκ³—·8>“7V֚L¬a:37‘ζ*ΒUΩ*’DMVˆ.”(¦©δ] I‰΄eΦ^ΨμΞŠu’eleΎ/Ε‘ž΄qN~ k³Ψ“B>hΰΛ-ZQ τΒΣ'ΔεΑCυ{‘›f \iUzT(ψσαρθmα-̘W€+cˆ'TTaz.­˜šλ½L ›TzΥ1‡ožζr0©(z =·UkθJuŠ$5:o§―<;Γ+=}5 d2,‘“Glοs5"§ξ3ζ ΫdS)Z˜slM°_H_c\]]ϊΚΣ­,{"Ξ ,5|£φΞφγgPpFiϊ.cηΰͺβPμ_u0!ΔΝ έ $;₯u‚;$Jͺ%₯žHSΕIαΈ_™§ΩJ8ςŸα…Η†€'§]Φ•E—h§ηRlυ‘κΚ5xuK^ )œΣBsτ$o<]ÞxΝIlh&'Œl’»€0ί;Ϋ B^ψ)»LC¨Ψ+βΒLd]²=V‡aθXRklƒ“[ΌΡ]Y–‹οξ{Ÿ8œιYmC‡d[ΕΔΆLk™%]Ρ£χžl2ΚxΚλμB2 NΊλ„%Xͺήb]R ?+Έχ‰+ΪΘUΌOξΚ΅˜½©!UΙ:γ;vkwΥΉ2c]¦jβeόλγ5ν…kχU}ώƒ›Θ πΫέop`\ρψ ;UrIή:E†rΦδ\Mœ€Ρc§ΤΊ'‘΅jΓQΆœώ„ΏiNR2fςϋ6i<ΊeΦ '>³%ΟEK­mHχήKΨΟB¦X<Φv¨”ρ&`ΜκΦRόmƒΧaεΠόeώηΓβΗό’CέU!έ½J”‚ΑΥ% δOBThο$G‚ :ϊπ›½νŒ™L½y]”οo AΗv=ŒρύTνCO?ΐ {Θ6bxΞy)ΑΒβ²Ε-¨heEίKΔ œ€„ΝΥ½'ιόΉ\?ό¬ΌΏ΄ νζ•ΧΏ·ΕŽΖkxΎy»6 Ϋ:šŒι»γ:)ηρIŠ@N­t`}1Ϊ¦ΚηΰaŒDα;ΕDMυb\ρB·DJ]œ ωλ/όΈ?«Ÿ/o΄Žιζ/oO3ι9™Ή%υΖ+―OοKzZΎ?m*1ΨEYlk΄₯°φ‹­?3½βγ₯\ν€ϋpr²΄„Έ"QŒΞ;ΝΧnH΅Ηζ‹%κ Ήx‚TΪJtν³λlΉ%ΐviΪy ΛAεοηχβNRΤb‘ύΤάυωW<;ιΝΡή{Έέœ?*gψtΏΪΐwΧ`„Α₯κ8z©«PkSRΗΝ‡ Ψ°Ίσ©Ξv €θS¬Š~Ξ#$!ŸYΣΝH?±ΆgΞψθ ήΕ₯Ψϋ~W%zΫςlφΛ½Sη½q @ί^kWˆ”V"\‹… n5ƒQ;{hΒZ•cχΕΧ tη₯£ΦœΏ!Ωήm]αΖ\ήύ>«* I?!ΌΘxxe’Ψ-Ξ’³<$/[ΉττŽI*[π¦ΗΦ9θJ1ύκ%”ƒ»©―mΟlešνΐŸ!7ΈE{ο*΅XSRRi šύ)86ε­¦’+AΣΕγνͺΎ;ύτ Ες aτΔτ²±l_xΉ΅ΫΛΟƒt€ϋόAa­’.V“)%ΣΊB|! νVεNY…8ᬻ˜K•fj©-”~DD―]«Α&:49ωΧφςΉV¬{ŒBΙΙ₯P[—D‰ΒΦ1ς,UyΚTœΨ@:“z_ΐB#p‹\²ΎΚρρQžΡpς‹%ϋνώ3γεβǚ{GΨέ§. «Ά€ϊβ/ŸŸΩ ―ή6䨫'*Ϗαςώ8χͺ'η %΄θ5c]k‘½S¦YΗR•a4†˜ζ›Cƒe³Ϊ”š‚ρ$,τW θG†χˆGXΜϊϋŸΞΦ›«[ϋδΖ*…Ÿž[™νΔ7ξέϋ\|¬Όmω 7U<ι§·ύΨ}φœ+AΓσœ/V•¨~}}ΨΦms­eφmΫO Ρ€Φϊ£¨±IΩ hD–G—xƒΊΤPΑψσυβσAΔŒί6.ζyρgcΫφ»Ν€nΏ]ΎΓ,·ίmυ¨,ςφŽΙυ·?ιωιπvπ;—ΝlΘwΞ_―L¬Ηβƚ¨3γW‘;©±Ρ£{^„όTΟσΰ.π€VMΚxΛέFύΆx εΞλΥΫΟ'ώψκaο3ή«/RΔ}a~φ[ΕN~άδ%¨ ώΤ:!»Q›ΰ\C5%Yι+­ HΘ*TΒΩ» ό›ΨΗΛω4½ά˜aς. sςΟ§χ‚“ΛμqkΙyΐ=ThIεBΦpφ%h-do΅ m¦Uxαͺ’2FyeΉάJy·έ\ίiu‘˜ζρ«<φ–kύζ}Ζpa)ŸνΣ-ήЍ]ΈxΫωΝΦύώψtν?u›_πέ—Ω^Ϋζ·77ς{ߝqlΏŸι~RVnοχ>c« |ψΙΌΌΊΑ.μ½k{Έχ^ΪLΕζχƒΛS3r₯ύ9χ3°=Ό}Y•?ΌΒ¦/·œΡΓOζ―uVŸζΫtΞξ5ω¨έ'Ό}ͺιJΫ+%©j‹ο/œ²~a±ψ ‡ρυA2ύkyNQ{ψΑΎ&τοu(\ϊϋν„.~―Sš§Χ>ψzφΩ’Ž;;nΟεoσ6γ₯ ϋ)ηΝ~Ϋ%FΑˆΨ½°φI»ρα΅ŠυyXυ5hϊχjψιή^ύϊMζΟoδ4φ‘«΅¨τ4s]iœ¬zΖβφl°.Wyn/«νžΪnmbj»νκΆϋλ…X|L;ΓwΖ†ψΒO[€1š ^{ήU:γΒ\~€ΰφ?ξϊΌ)²Y5ω]ϊxLά|(tKΡZ{~}ψΎ”zί‡§ωΛϋσ©·ύ½yKς€Υ Ψmœ·Ν'α'K9²ΛAͺω¦‰χρυύπ•m–_aΏ]€};Ψ@·ΚΥοMόŽΡj±ΖώΠΣΓ€ΞΥIO_©){Ή ·dŠdΉ…F’8έ4bΨTz#[©pu†:bξά…UOr‘†TΥΖΗ _ΌzΨξ‘ν¦ρό4»Τ+&yέηΣ’=Ήͺ–©Nω”›MΖz—}θ©UΦJ©Μ¨ΥVŸ#Zο[1š\5½pΧ’―E#B΄{Λvq„‡i9§ο œ•)eΔφͺ‰*|1ޚδCMR:V*«Vͺ`›ZeγΊω,ΡYaρί‹mN¨ϊ?ς»λˆ³΅ cε GAΙ‘DΒύλ#8ωBos{ΟrχΩ65zŒοQ€Z.YΡΚ½BΰbΧμτ5Χ›‹lkΗ7ŠΘ©ΦΝ§JCφ‹ςΧs(ƒŸβν½ΐψTŸLξŸ Μ!χόtm‚‹Βξ2ΏΎε€Ϋs­­j«΄±Rn|RΖgμiCˆtˆB£žxIθ€,ιFΨ _Ϊr1onާϊh{Ÿ„ž‡σΎXνXΖfώšX”Λ”SŠ"=|ΦJw‰ΉZ‘Υ+1x²­ ‹6:̈°Ψ'©U(56‘ͺt>ŽiηΰΩΏτεwε‚ΛΨ .K·ΉKΆΒH»F0rΞ7§JiΔxψb`Γ|œπΎU«PΈ?w^νVπνys‰#*-³ύ‹―οΧxSŸVO'”mvςβ€?eƒό:F¬ ‹ƒ¨žHΈπ£.F©$ΓΥ”s ]ΙΉ8§τHoΠEΚΦμm1«?~άςΚD\όΌΕλΫύ;ΒΩξ+ζ.Έ;€¨Τ{ζ =»ͺ‡θkͺ₯Š"dΒpH©κŸxΎzΖsήTξhƎοžgλΟS‹ςtΪΫ<}±‹’Œ’³95@@Wš4ΐI(Μ1φWΠ’ωjΡz$jχ&JcpU.r±Ό>I{φZXqή₯³xΒG<<Ϋ­|gw—ŠσΔ(ΛχΧ·[ΏΗMχ°KŽŒUΗ7ͺ›δ-η΄Α?¬kΏυxP“y₯ή‘Λl-Ζw濾κ’v>WXεΰ=;7cq Ό§ΒΤ²¨Πi1Eέ₯…˜›¨nXEήpΌrz7–΄μ΅AŸ-³œΎ)Ο»€\S-”šek˜&ššV!gψJν»K±Yƒ@ΘIC¬ζΞ!’Ώ6τ ΓlŒM?=Χμ;uπΣ’P‚αΔκLγQ `ς5ͺ‡”)I³G/t©$t3.sj°˜εΆώО€π =§gχξ²ΣΑ² 1 ΛuΣRݎi¨=7Ά"Ί£Υ@Ύθ„α'αT »Ίi"3§MψΥ…όϋι6m)vW8aϊXrΒΆnDJ*—Ίs.o²M„x±jNˆΠ„“-΅Ϋτ‹Ή;ΏM]'ΦΘ‘•m­½`‹8|) _υ€lΞZHn…°Δφ>šΤ]ν)Em―²Τ­o7ξΟΎ•»a—TΧωbH΄λτρΒ•’’cuL—tΫΡΩ‘3J€bΞ0{J mYΥ]ͺ]k’FeΔΒέρpېρΆω xpή9oZφ.ŒnMŸpcΆόb}΄|ΪΣiqΞZe36^L¦+a‚‰Fͺ](\mƒQrρΒρj«i€εΐG%ΑžXΕ)»>’LtƒύΒΤxyžn±‘T(]γ¨Q3pœΪ;˜HU-Pu0 Γuvx2ͺθ&4Ρ/»ΤoΜ§8–γσΈλΗ9ܝ²ηνΖκ Ντώ5Ηεi;Wd:½=ζ(ExI#Β`m†QΦ0Ζ.yΖ„_½'/ΥCRΉ©ήλΉ‘5Α™σk3φΡρ-BΜ¨œφπι©kO±Δ0cφA\ΐ^ \ς™TΧqΧ€Αhw²%υ^*$0—ΠΥ_9Φό£― 8:…„½mI*ξTΘ]+Ο’αžuΑΉΖ`Zv΅{ͺηL!rή+cEtκόdωŽŸ}κC›œ6YδqHˆΛκBͺwδduΦιΆη€7°αα˜JQ}τN$:#^r~‘»Q1+‹φσώτΖp>£UJθR…Šς1dλƒDωͺyƒͺΒJ‰ˆ_禝ΙςZ(?˜’Λ§?΅›,ο0{Ρn•„ŠΆΡι&O‹gό±εj—œmˆ»?Ύ_ώ€ώψ~x¦oxέfi‡o₯”c΅‰†/ jH ήš  žϋ·¬‰r?Λœœy}i”n)Εt`9Γe›^΄΄>ΨΊ2ψqχL8VΖ‡¨„‘ΒόI7„EΠΖΊd>¨νω‘ο"KΎΘC{°Μΐχ‘ŠΕŸiœς Σΰά³CdλlvAιh#ήQΘσΨ5οΊ²ν$_75i™΄ψοKΉB#νπŒ&w[°Ίw”pœ•‘΅Ϊ(:)χε-₯cΡxVζm~πΒΛbωΌ«sΉ°·ο1+ρδ ΗΈδΰΘKOQΏrFˆώ\.ΚT]ͺΡY*υm”DwΕ ΐHDL bΥ€‰»½Z‹CΆK}ϋΖ0ΉgΚΡ•ξ)(Ή’ν€ΑEΝBΞ8fΙΙl`ΔΖ›° €#²Ϋ…V,Ϋ)υ*ζ/―OTωa~²ρ¬„fΚͺD1w-rΑ!κΤ]‚Λ₯ΎUω…;ށΡ₯£€€ΡK₯Η½ίόeυF/χΟE­cΈα€@“ΞΚϋΤΊ m=ςZL…€ΣfΩKdƒˆW8 ΈIhit‘ŽΣ.Ω±αμ1'GξΠ:£ΨN.……6Dˆω³ΡB@ ΕUλ„OJͺzκΖva‡Γ©CΨN°1£…Υ³νΰMΔ<'dXϋγŽχpŒ:υœΔŠΒLjL^¨Υvπ…0œ]Θή\I’Ο…rΤ ήΘ€f‹–ν:2ξωΛΟmξΆa/*ϋ΄«?N>^ΰΰ¦JΆz*ˆ>¦†(?+–θή²H+<ΜΡ£Ά…u8Γ°«cxΎΐζψΌM]_L±L‘c²F𱠁Ώ`ϋ$χ―μ’ΓΩ’)’ΝˆεF/–šUτό Χ/RζΉ. =αXŸΪίω@kSSžΡΑc"šqRŸΨ¬\—5‘Ζ7X‘<ާEΔΐr\…¨π^έ”υr›ν•ΝόXΚ>fۘώγε³ο]ΥΕ+Ώφ&Οχtiμ?ρίzςΛϋσ+=-Ž3‘WΎ]˜5ƒ?ά:H _Ϊ qœμδ5σy:i›^Zaœkžφ&hw–>seDzh›tnkΧW—ΧώWlχΥ½±>{λ‰ΌέΞάnSΆoύ_ FGύ‰NίӞΒ3­Rέ»·3ΏΣΥΏώπ©NΥBOmΩΆœΨ{Κj‡ί>¬ΫΧχ‹–Bkςσbq©’gΣ6γΗγϊψι_ !‘7₯i‰Ή€(Ψ½9QWYΙ€­(ά΄θR(!o“Ί5MΐσzLu_ [Ϊr1…XσG^σΠ·?f{‡1³iΕ'-ŠΪ^ŒΊt„’ΪkŠ’^¨³mˆ²'„Λ=v‘sΙΞ‡’1­Žψ”mGμ―—\οšΖ†&Κ!ιλ‹±Η©N>U½λy:Sˆ=Ξ‹{Ψsv%χ|Π|±KηΚκA/ρrmτzC˜lZD[sL¬­ΡΪU!‰§ŠΏ²-0z·Ύρ&ͺψQ‚Γ&ξSϊυ LAK^ηΎoMΚKM'νΦ7nΑc*όΟQΞοšΟO|.W|Ϊ$ώk{χ―pӏ,άX8y©}ο™Ηώζή‘=Ø޲Q!©Ί.Υ™b£‚ο&J’«Υd4zΓ’Ω*¦υ¬SwήWΗ:ΥάΨ’ a°R‡Ο?}·]²r©Wa™uΛNs(Vη₯€’‹Ξ*m[²‡6ΖLΎW£’gŸρc)ς'.ZΤ#ο,—'Ι{J±›B˜ψΠ΅ ½υΪthE _ NRΤ’ΤWي/ΌU$¨M3cI·αœ?{ž\ιΥ}6΅α»φΨ-β+ΐΓ*šΚEΉhZ¬Ψ.”¬Γ’ςT€1 §^ΒψΓ·ς~ξ–U²₯ζGξδr΄Gn$-lΡ)'OνZ –(±―{—_QΫ¬Ÿ?υ―_guρηb ˜s’a›ό~ί­q’ΛHΧi©ΥOTCs™Ι5Ο.φhzσl)貦ؒ·γ]zΧΫF‡9=38φ”k>USήBWEYΑ:°‘f˜c9ΧXV³I‘αηΩ΄@·‰Jέ0ΰ5w‡=·οάpΝJ ±β4Ζ ΅XΔβΛ…L‰,°•rV2ΰ(D"Ji`½΄ΈϋψόVρΒΕ‘Ώ7ώvJo &4[ZwŠtυΔ€c΅9| »ž£ͺΔ©%%„Υ5[lCΑ&§T†Gλ|5όQ\nCήΣ™ΡΫωG?…gί—τzχ6-X1˜8λE:ΞλFή!TσΆ°θM5NΧΖήωVκ@aΛΑz§₯EKΗJε|‰ΣŠ:_δn“nnb=ŸŒOξec/ΉΨD=› ’vͺHhš…~½δήkυΙHώV²™0ΨL1{`Χb:§4ͺΌγŠΌ;£Œs‘L=RΕΏ~UΌκŽ…_Δ!ΜΤfΌο{‰Fϋ{ͺͺZ€`;ΐΊλ †‡—η't˜WΞΓώ»ξNQPLtQQ5^‡XΰΡ°QTX…ͺ±GE€XuX7‚QˆΦΖTU!bγFzJλQp|“?&£ϊ{ΔPWb’{ΕQ‹ϊυδͺF’βSve“IIh [οA˜z²‹‘" o:…¬pB’3R΄”/%΄ΰ']ι*ŽՏﴼRŸδ8άτ4^Γ”a‹WΤΦ½ZΦ” L@>»PDίT-JŠΩT―Rς€Β…j’V‘Μν™κ—»χΐ•x–l1Τ; lrfNΥdx Ds ώ‰αΣ›Œ%έMR@v’GνM€–₯ΛήvCoZήϋ ΣκΤ₯₯Α”’U―"Κr©e„₯ˆ&je*ΞθΔΝτPb³>ˆƒν t\ΛCΡb-Ώ>Ί-yλ\²――8ίV…CκΨ=1φ#ξkΌ―p8;κΧ}ΨΑ¬¬žΆ΅χί—.Η³εΰ½·μy.Αθ•‘T:-x8Ψ¨-€‚TβS€¨sWΚΡΆάΞΡ‹DW;xD”ηΈ&x] <ό‹Η}―bΜ/MΔΫαE)ι‘Λχ―o_πYΪϋ ?nK£ ΡYK™ξμΠξ ‹ Β(Ϋ#Fη”F،±‰F©υBk#ŽͺοNWUЍΞ% ΅BνAsκέΪΠ½ŸjΚϋΙ± vΤ,+Ϊ’|ηŽ’£Rˆ{ͺnX»β`ιbbE5iGR¨Ÿ΄&ΊγσΙρ…ΙγŸ©"ϊ0―ΚR.FΖΪΐ_[[•βκΦΩ% tFM#rh=κψή踐ΓLߐΝΚkΧΐˆ«c¨,6:θX#*Φ¦‰b7-H«vc‡±8¦FΤp^H·!Έ^ςμqI―_ζu΅GEt(ΰyΐβXώ}i‹wλνΤΫΫPP5VφJΧ¨YYΚ5WFΎ€ 0ψgγK¦›Ι±δ•‚Βq ’šΪ?ΗώαρW«Ώ:Ή0d²rUτ![ν¦`+JΙ%wμkΚΙZŠO:€‚ˆΘ–S!αT:ߎΈc*E8O«Kxσ,υ/•(­ζKΉSψB﫝ύΨU§V!V*B°p]#’&Η^Δ/»ˆA³ηδΝo·Ύρœ°aώ;Έ:₯{†k―ίωeώγl=Δ5]f™ƒ??ζο~=BYθt9Kό’| pTrKŒ(αVr5MΨ(Λ ΑΈΧΨR7‰CΟ‡ Τž>Θφ―Δ•Άƒx£zΔ‘먘ιΆ/θ|Νΐ|ρ}ΛρnΉ’ewφH!ŽOϋΤφJzυlgιΣF¨buΑ„˜qΨ3Π†qd ’Z΄ΪIr»F`@“£3]ηΡ4Δvθ˜ρβ²’” ]Ύn³Χω9ΉpKχΔS>ϊς翎>m8λΘVβlx&'(ΚW—™ͺ+δKusRœίn}γEnΜ=žο7―ύ{[lήΙe&{-! |hΞχ΅ΒΪ»l€*΅t$αG]₯†8Λy£'θe«0–’>sΦ0>ΨοχϊΝΨY(σl‹­'›}-Ω²Κ)j4ΰše©¨2Μ'ψ9'p̌Pημ‡sW—tρηC-‹εέ― '˜±ˆpu‰MWΐ7 2F@›Ί%U9±:ΔdZ-Žœν€yŒawkYυχc‰Ίέ¦Έtυ{!ί‘ςΜmOw½,κCΓλΨIͺ‹GύˆΌ}§ηuঁ~<Ό¦€ξƒŸžΎΆωςβCνΧσήΚK|R}ΏI@ ΅|ϊcγυRΙπΝϊsτGΫ°GLpAξlsSΉΉͺ½ι€m׎λ@Ξϋώλ’{’m'd9燋e\ξ«ΐ½>Ν7EϋΝ’/ώiΡ‘Ήν.}τHm₯hv{νϊ©Ϊξ‹γύΦ~μτΑLdͺ¦Œοβ«Ο‘CήTΖ~τ—9όoΨUŸΣœ³D΅πNKžn}ϋmΈˆJIc’’έ’¨Έφ½©*‘&Υ~»υcαυr H<“€?–M '©€‚ϋΠ;ΨΚΗ|·7jιYσ‹ΏΆ-ϊ{ΞΑŒ_βέf;™ο±™]΅ΕκαντvczΚΡKo…iX σeΑΧUwCδE—š„Šρ­/TsV[Œž;—GΨ/w|YWαϋ“d =±‰“λ3›œ¬¦Rw.)οœJ6†XΊiˆϊΉS—Œjw™Škέ’*±Χ¬bΆdCc]{‘GΊΜ_;²‰ϋΩrυ/ωύuopiνφ·ΝΏ] _₯*=c"ΫlRΜΐ³,μ "5ffr%zΒΦ*δP0©/³% ΟΜΦ“lT~Χό­;ΦΞ φα•ί† Όc;ό:_~»υbŸρ"ƒώ•γ/Ÿσήθρϋ6όζoN΅TcPM ½©Vj™4Άs₯Φ›«"EHμ―ι)έ€[ Ό³ύβΪ.ίg|όο9ΛcͺΚ 8ξmρόteΔkN˘ ς,ηΞ½…_“eζ 'θ^eΒ₯iYτΞ΄Œμil^nGσ3-‡ΜπΏ8GrΣΦXkHވ?³L·³Λ^:vƒω )μpQz’7Ž“_i‘―Τ¦„€”!Φl<§ž£“–i_ή+jΙ4ͺ!₯ΠKΚZU}HğV Ύjπ$@b΄·7ί£ο;lsy|xGψIυ •§S‚Ξ©σμΘΈhƒΡ«ΥAΉHΊ™xΓTTŠ’Β4Վnc [+]Kg€)~PΝOrCΣ λΨbXΧ­5Š[4ΒΨT2yͺΙJ©'%Œ¦Ζb’odLΤΊ·Φ»λ‰΄3ζaΝ­Μ…]tΉZνεHΊΫίαr±χ"ΤiMT6υuU$βs©³)E{!S3Ή&£j€<‡"©ό&wŒAj&ΟίΖ­k]†aψ›†ΊΩωŸΦqύΌΥCyŸ?΅‡³ σoFͺΈο­Ws{›pΗ)pIηυH΄{²Ux‰ΎΗω ƒ§™Ύ%«{Ξ91«ήƒGτZ€šHZw:N±Ζް<Ε3IΑ v5ά0/Ω1%”=’Y‹punC‚[‚xyΟΩΣιΣ!)ςΆχŽ ς(DWŒx·’8()ΞΑ·ύ—rEƒ3;q‘mJήΩύ©:!WœΪ5Sk[€%ͺRa·U΄Ν`h΅ΒΥ¦aΗœP‚₯S –έ ρpRΊ•›ώ–…ήΌη€ιΤMN\Ρ\}…[ς)°I.¬ih ΐ§Š–G+­J«’)½ϊΘΑWXφ¦r6YύZ)FψP_ΈζτζΎ|Ϊ“ŒeΜ >„¨«φIŠΙ8K«™ ΨΞΨγ›i[P’Σ Σ[Χγ‘œΟμΙ­\ο *ŽŽΧqjΐš΅/Ί`ε„»zλ¬QM.θš›Υ\_HsO62Β•jΌƒΓθŽb„)+z„|׍°-zΰ•_/S½οή Mj9*ΰο°!F]ΘUm 5₯M'φ–8i£βɘJΕfxΜBΕTrŸVώΔψ„Σh\ΣkL‘­AGŸ‰d΅”ΑHjΔyM­zD ‡™MοˆR,•eŸ €V·+;Bn³WQ΄βDD@ΛGΖ3ρyňδ BέP…ό‘Ν<<ΗiϊBξl€Α±VQt‘3+);ζ`YΑ2sͺ>»δ…ΐ G£Rυ`mΎK£υZΌο<B»7ψ{˜ΩRx5λŒΝΑώ0ž™ˆb·Ia€Ψ’LBrSΜς>/ΫZΈq~ ’7ΰ6λO z;6¨Σ‹)ZεJθάnrw‘ΧΦ΄Εr`œ7£ϋlR±ΉHA²3­YΝ6–xϋέΰ«ϊ4η—·ΚΛ·ΥXŠΫݐ]jFϋβύ₯m% _ΠξAm³δ{©ΫkΉΖΧ―u₯υ&ε"UΈΓ—ϋ#ΪΚ™έV-²VΏ…LΒgβlεμ}Χ‰αχSUF!δV ·έy‹Υ ΙΫμI(‰ Sπp?!GYόKέ­BZv¨“86Τχε’,–‹Υ‰όαԎ€&cυ.Œ&šR‰ΞU‘œξΝΆŠolχ±Βƒ¨ZJlNχ\cb„?΅η‘Πξρδ»½Ν”μžΫώ°mΎ½6όΝοί{l°ψ© ‹] gÊ#?mm"ΚrΦT•Άu“ μ\j+jύΏ/}ݏ·> »8`φqAυ‹ΑΑβϋˍr?νwœΤ£{€¨ΦΈg•"ΥS*;Γ’A€`ΐ Υ kƒύ@ή€ΰ\I,΄-ήΤσw‚ŸΩ ς ·‡ΥόΉ€ξ† ˆ/«ω·Ε ΏόkοƒΦE„<[2&‡ (Ίά ‹€0ΐΎۊTΗaνΦ7ήxύycΡ+-ΏΚ"?-ήN³ϋ“―r‹8κK—E±£U ˆˆ{žSN9λf[•|*Τ,€3‚`ΠDΒ(#wkα‘΅±Ϋ4Ÿ»ώchͺλ“πpFΕ2έA Ά†–KrσΝμHZΏ|α„•GεaςΓΘιX«δό)₯ξI…˜bε¦nγ°9˜™ν=&ΠΜβΗΓκηͺŸτθ^sŽ―΄:Σ‰9Ή¦ClT8ͺpHάy εjΐ¦N…E7"Y N"― <Χ1W#|Mςμ³ωσλΣ±©ά€‰Kc^ήέήΰνc+F©’#wqˆ‰Cc₯R2θ›UCX›άίψΨΐ¨[U―9•pεrθΪH™ΏΞ^_Ο긞SGψθίύκl—wΎφGΞ_Έ™‘ŒΛ5'vOύ!³υγRœ%#‡ΎςΓχ/§₯‹ΣGΥ:#Ξ²/~’θ,5ΙϊFΐ<ΟQGλR͞ ΄*©j›ΰZ Qε±2αW^ Nžmο‘ο.Ψ\o>8έ” 8–Œ•–Β ν &§ή]%λ΅ΦΦcΔ^\νCϋ!³5<:ŽMΥΚ½…¦iΐ‹Nƒb "|ψ$+ΚΛ):ΝήXΡ6λ·8‹"―Υ!+xg9€X4γΞgTϊό·‚pkSΨs«υK?ρ8“§Π„k›Χ¬j38ι!ΞjŒW ,z!ρΎ!KρGS1ΐχ6uήοs7Ϊ€/τtΣx?ή}χΫ"Ϊ¦JΑG#’0iV£P]7QO䈸#`f1VΑ$ΰΖ{­EtDΡμW7υΧυ)šžΌΛΈ¬:%`η€uT0oAΐˆIZΤ±ri\Jφ‘h8Dœ°„"kŠ<Ζώ@¦O™·ͺXwγsΝ’―VIoΓ—ΖnM‘\ ΧΚπ[ n §Ί“ˆnκΛ8>ωϋίv–₯ΐO{ xhΊ΄%_ڍ`Nω¦ 7­kδX½λ@aHG3€εXυΡζξχL›ΜΔΡhΤΖDΣ, bEΚ¨{(ΜZθΨ’kV2"Ϊ†Φ" (ΩĊˆ•χυ±~šΣ{ο½2ŒρcτAYxΒ¦0΅Ϊ*ΒkνΌ•ΐ\Ή8D˜-Χ(L.9ˆj^ˆ–E8\‘nΥΗTd &7ΖQσϊDσ—»3ΤaΛΓ«¨Š…α($όƒΗ•ΊBεΊϊ­½ Ζ‚ύΧ†ΑΙkRΥΖώ…g«Χ§±^ο@άΪ£(KV”"¬U§ L°[‘›Eΰ―Φ©tψ6„–Vk•t!³cΥδ΄ό9['R^iω6HΦ|Dτg{ ΖφδΠSw\sI-#\‘”J\#ŠQliv€y‘€μ.ΐ*ͺNBΫcrΞ¬šK#2/+ξIΚί›  ‹wt½‡εφ?žŸf—JΆ^/NLlœ^hΆpηDkκQ‘|6,—Ιž#‹­ψ»Πδ~1ˆΰ5―ΣΒ› ‡1 œψΧoƒKατžfς€ξCͺρ3τœ&Χες²υ³g †ύ4u•( ν£°ƒ2’'ΔΪN˜Ί¨ΆάζUнHΘP½Œβθda·Μ84z Ύ.γGbuΚ&8΅+―μ2VΑ?kη€§š°ušXc,Ν$/JCπεQΰ§1 vKJ[8E Χ>FΖ&5S«=>±a(Χσfϋο:3ξs΅Β/?ΏlhvBμXkΛ•ΛΙχ§%αΆϊ^ΈΜ†ΟΩκΆqfο1Ώ&g±I@qΕδ£·ήκίn}γυ~‹υί_Sγ_κηώp/OQŸW7&z―|Π9JόΙ―„vU%\M YEbΊb _;κ$…ͺŠρƒb["䲦γλ €ΕMdΡϋά7ηΨ£7Z|cσπ>―_ΟΒμι/7H²ΰZ2 t¬9b{ˆΔUΚ­ΕΪ$λ!ۘ Ιs8]^€»Ζψ>Φ&ΰΨ%L χ*pmΙ YM㽊59=Vˆπ„R‘κŒ‡¨/΄ŽΗ%8„Τs ΄ˆn@½#K4€¨ΞPM[ηD‘θssΉW ¦»&eΙD:Ιf52|‘ V[Œ”SξΥϊPΌsM—³΄ώΆΕσQ=^œ—6½ο› ˆα»/{ο|­—'gϋYΗvaςnF„οά’&ζš#`Ύ ˜Σ—nCΆΎ₯Φ=…\Ό)bεG"ΑκΤHBϊγ²βx..ω΄ζΛO) Jc1㽦¬ АΜ,wkϋ=ϋ㠇ᝠρ‚΅©ΓΔαΈ†6BτΈΏ).πK½»^W%«±Α{,ϋuΤΪ4 £&Ισ€Θ©»`—’Š’% ΣlfŠds AΫσq­+(Ϋϊή-p(C”VϋBƒDξ½›,9§±» /΅ΰ’-ΝšsΥ5KςΜλ˜₯­·t8QAκ‘x‘hΨ%£N-ιηQG–Ύƒ©*P•†χί_jJIΈH Γ.΅Φbˆ\‚³Ϊ•Μrυ&Εε^§D*΄«=…ϋRӍxη¬λ_‡άvΣΔ1Œuvmίξήs8)ωυ΄I#˜45y%šΆV™šυ’τ΅ͺ:ΐ#ΛRZΙ„€`D―(κΰCK#”»‰ΨΧΩŸžqξγ–—]‡ζψάTιŸz?9iΊ³ΉΫm‡%†‡->ΒS5J΅%•"έοV*QEC―YJη Cψ±ζΡτμzο€Ξ«» JW£RN”%rͺY8œnc ©α]‰LQ΅t%&OV5«3Ω’¬ˆμωxζ:-ž–‹—K“ΟoLΒδMpQχΨm–šκ"-ωΪ0 ފ+RΦD˜: κ† Iϋ¬²")f“—™˜ŽΤΗ―“δ¬i)ναδιε@ΓkeсξšM—cmΦ„&±!)­ Ι;Ρ‚PΑ7o|ˆ–ͺ #χ&_„¦gI«ω¦Œk&cΦlυσε~\όφ]'<θ~r0-υ,>%Χ%έ±ΐ½WH†y‹΅TςZ7ξͺΒ6Β-"’ς8κ0ŠΆ–ΡσϋΌψ† xΎ|85C~zžhͺMce‚¬Ε+ΉΓΓ%ύ€±q.%„U–‡ψΏ{©U;„―54,ε– ‘㩨εωΪ&Σρ‘p\9€ˆX‰…Hδ4ε‹Βα¬X4ΓmτΩ‹s‹‘G3œ›ΖΗ{KΗΘ^ιl€?ͺ ‡ΛEΧ0"’`%WεƒλΎ-5Ο«ΉT†ΫEΠ °ΧΚ³΄e|¦kkwο]|{Κ@»Q:Δ$m7]8ΛXˆ[M@ΥsL΅tWR'|ν¨“1ˆWΫ€•tK~}’ΊΉŽΊwJ‹αοƒvŒ£ζC† ¦ΐΖTΕD© L/v²ά:‘G( Τ9p5.B…Ηnš„ζT‹ΡL_4’R7€bœΦ°¦h―•π%™pΣαc€μΦ„·)Dζά½uōΠΝΰ|‘™Φ.UxŸΡ ž^έ$6,BM]λ}νΥυ‚έX Bšž,!4‹@Ϊ+œK¨ΣΩΉ$Δή„“ΈΨWζPΒ§4₯‡½ίσ(Δ/tΎΛ{«‘| tΠ]ϋΆEλ*›εGύ½φΨRœe„ι-„WΚ#Ό°AK«ˆ%—k·ΐb&)δX;‡` ¬Ή©³OƒΈ©†ΨZΈRž΄M,ΑvšΖ†}Π+jz»φϊΡΏΠ€"…ΞD_ΛΩξJΜφs·\–šψΨ τύεi±x½{Ω*|o.εδ:Χ蔍”­"b˜˜₯‚Η±‚ μ‘ ΒΚ­τ’€¦»ΚΚ˜˜ώϊηꆧ―\mΎΫΔRn3²$ΉŠ€6\SθΙp₯hle4„3 ΒؘmΆ"»­Νυ$Ϊ–O{& Ζ]gΔξΥ•pŸ? _ΩΑΟ%Œuψν]φz>μNΦgoηaΗ{AΩ½/u’IΌρRUš†ΊI.υP^J:HAžJ”“&nέu@?UΉDΑ΅¦φ+Λ}eSΦνιηοKΎ4%ΒΗt`¦/KΨC©acΑΘε\8ΥΩU€\  α ₯60ΎΉjΩ…‡•RπΥF#υͺ£€…AδέψξmO—qΔ lFάα²τ5" AH’S„O 0ο@|V8ιρδ"γ£L‘PAζ-,τmώΘŠ}Vυ=ž’ + _XηΟtL €§7@»p+Σ«ͺžTœX·la·"%ρr£Š|UGίL՚C/΅ή*Šr,kpΕ©Ιά,SwΉ,bO&ιάηύ~yβQ%ΞIyιΤιSA¨‘€-jΘpήΔκ[φ.j@βNdγά’‡ωψSͺ7ΞεT:§Uε^ΖI…¬ΎƒcU©!‚’ά^‘/3Ό”]NŠ9!s΅Ξ„V²Λ@Υ„Κπ\™δώ.T6—Fπp^=eϊ<"_Ά,’U‘ζ^ŒOn ΔZE΄`«R’6Ιλ€<#~ΧΦ1Έ.ύeŠF*.«Ά,ΎŸ€η§²Q7«tsš²ƒκ=²Εΰ ‘wΫYΤa½Ž’7aaφSOal­¨3ϋέs?ŒMnE@Μbή.¦KIΧΆ]χ!*¬Nr"DζŒ2:‡€p>šΡΗζΩ‰΄‘Ύƒ& πcΥ­Z"Κ8΄8Ϊp/,ΩpB[HVBΕTTiZ§¨„$’ˈ@Frγλ‹°/ŒοU]Ό" {{Z rj€E !Ήd[&!δ–,]οL B‹Eκ΅IyΏŽμ"ΥΨ›o0y©Ž’Œΰρ–νξF¬™LEΥ€Π» I€‘πŽMΛP1‹Τ|l«‰ )- vB!zˆ©ΆΡ ԁ'Pmς ŒF@bN:TIr^Δ& mρ­§θ­ΦΕ"R0’ κc’_|>Ÿwξλ‡ΈVΛxψΆ“‘N&ƒΐχΩT Ζ䜫½HΟKΜΤU©Ω8 S/,–³rk=Ο%βkμG5εέ݊Χt]'₯wζŽθΊZνiΫ―ηοαy[ξ³'³cΠ£7ΜĎ aΧ·Ύ%\Xׁ5Θl@Ψ·Ε-λ)IΠΫβaυE,ωώ7ΧΧ|νَIΦ&':ΜΜ(4… ³2΅:˜‹•-ˆKLT›N'ρsΡWƒ WξΰΙ)7R|΅~φΩnκ/qvΆEgϊ›?›ι֍'•Ό”φPΡ#œο,mΒY Δ›Ό €&©—τŽΐ&*‹΅ΦθϋΨόk3΅—γ½ς„(ΆΠΗΗ.ΖΤrΛΦ$ ςM9 NΚͺ“―ΑŒ­ΧœC]¨ƒΛΒΎ0Δ‡‘ ϋЦΩ4uC,̎¦c½:v œ$ Ϊ1²7&*B’²„π‰ΡΧΔ™0XωbακΕž1―χYΚ¬°V՜†‹ŠΰD˜\·Ž$ΫtΒ’muλka K†OO˜‡B;­}έݝഩ“ρΏdπ2|)[ΈŒšJ‚ε!†γ0€½α_εSυ‘²eeΨή/g)MΙΧΕlζo‹M]'pο·.ό’_—wΟ εΤ”—‹nό?πL.«?‘‚P!JΨŽ]2H©λXSζζ§_τχεΣΐ}uη5}_Hf„ά1²πRFuL8ζ]¨ V4X+I1Β$lv«œΓž†ƒH­©ω|Ίm{·κYušγβπO²ϊeψrΛ%Yιΰ4l)5Šτ^hXgΨ4α 3d…Y9Β-„YT1ΒkŸάέMeψ2’f©«ƒ>G+tΐοΦ«W²(!–§&υχ„¨,'_’«Ϋ ;ι‚eI}η ΤIΎλ Βτ;ώ'=?²UN}΅ή±4'M•C‘‰ͺŠŸΘΰ|g_”26EΔˆίŠTŠ6ΔrΐΠΕΨΛ›]ςΰ9{>i—Š‘§bƒTΟ4vE^ΨUvj.ΛΨG8@Αα:†ί2ΊψjSk`¦δ ‡֐YτĝΦΡΦͺGh ½Ρΰ —ΑΑ=ς'F?}ν&•Šυπ( χ³άωuΡ EΥηˆΈΤ Iϋ@­Π’Kށ%Ψ r*wύšι“ΥŸ< —!7@χΖΩΨb+SΠ’(ځΥkƒσŒΕ)ΜIds0C¬j—€€m#)$a•χήOΎςl—I:`ιΏ4ζξ3“Ί LˆΠ”δ‹zWJED N²ιYx‡ϊP1ER&ζ%σcΔβ‘^ψιgβ‰ܝA"ΒzjΈQAΘΆΕΠ‰šί6 Hό<4Ή?sΎΆHNrkrεœαiKi£—c;ZΆγ;X?9ΟbeΡ`’zvΒ)84‰Ϋΐ^*LV΅DέΙ*#Qi $α{ιέΔΡόΙ XνSν«q ŒΥ•“φD;yeŸ”Ϊ¦)²-&)e₯>Œ¬8ΗΞ&jΥ9TΫaΦε*š 1Άn ~|ΐO‹7±ZGΠF©›PΏ~£εΧ΅χη石ο\~σΡj,@n ΨEs‘5Ž\jBE£γ―7z3 —@eώ&χ@‡ά²ΣkώΕ%΅ή…2€₯ΊΙA>}ΐIΘ=;EQgZτΡεv„l )ΎΈ4„γηΧw:+‘QΜrν(­—°WΤ‚L°­RDu Ή―Ξiomι^s’v&(ΗΏυ?/gθmFߟ_ι鬆ςΏεŽ‘ίWΧ$V°§ͺ‘w`"ΣΖ°—’RΫL‚C΄*iƒΩ %„θ­Π`eν£ΗζFXŠWΩJςΎ§ΤίF™~³hθZBϋ€§ξΉG‰»‘θƒΠ£mRΩΧUWς$Σ2EΗTΨhm’S΅*–F =P΅:Ϊn•o‘ψZύρ4[½ΏžώύΟ•hλάΦω₯L š]ΰΝη=ΐ#Ο·’ WΈiŽeͺGΉϊgρWžου&–¦”\qEϊΒϋ欑RΌΆ€œΙ6Ή…1΄50k’€W3Β>LaΤΑΏύ<)Αq†)zxΩV©K’·Ε3v6Ξ ΔΆ)†nΫΌΩ…bθΛyΊ=–Εm₯δqώξ3΅˜m„vE“eΉψώ²ϋξρiQψ4Ό=Ηυ²»R3mAΒ Β>σ~ φ~VρΌžυΙΫSX½*zΠ"y Dt$μ2žΎ\wγξΆ6·JΫΤλI…ωqͺsƒrORŸΆdύΒΟ§Cސᅽ‘ €L+ψΌMυϊό™oΙ’ΚkΟ›φ§χεϋ’E™·ωΑ +~|–f˜‘ηF―H†žΎΆω₯€εώn;8–OΫuέμν=UϋO+u\|°³b­·θ ™σ}žΣ£ρ©ƒpΫ–ϊΕ„9ΖΏBέ›‡j―‡]WΪΔ#Δ?X›α™aπγpR³y0ϋqϊ™Cτσiμ°|ΜΤΨ¬|{|θΟow—$K½ikߝ6Μ†3`·^IxΦ)dοΖUη,PxK3:Ή[p^–(Ύ?>έθΙ7j~OLΟ›―VO³·Ε¬ώψ±k•ΪΧκζμηi24N~υ Vm…mΎbŸΉ΄”‘ό@z4nESςR‹§t­Α:γΧγ'³#7 bΰuφ(Aγε£@jXχ„6β‘λ·˜ νΟ‹_­ζc―|ϋ8šΫΪ«γ„βGϋΘnC\Oͺξ;©£ι2“ω%YΧM“#b]ͺo­-[GΤ»ϊS–)»Π3Eλ…Ω:υ€$”“€Θ/jfέtŠŒο^ΑΊ«Z'α’šΦ.ͺΈ™΅Φ½#.Vτ3ΩWz‘vvHtψAΰ\c£Έ8 =}X±-6›€Ωνͺ[š¨\6­‹ž―hXjiξΉηlΕΙ΅Νθ0ψωυ€ Ωή!—ZγšΠP‘"/‡ΥgΛ¦“FόεΖ!Ϊ •()Όά`Δc2UŠ!¬ΑN½Q¨ς€ΙlŒgγˆΰ– :„@Ο^Ή;σVW ;c¨€Έ₯ξ|SΉHi³ …„|ΗΖ¨1E­©ΐ^ͺšϊfی4?δΛQό-㬋§ΖΑιΉ‘L“f6˜kΕšbŠR Ψ„MΣš‰ΐd…ΰΞͺ"Ή‘gZJ0εξΧ«ίψΗΫΐ»R«7yI7 J¦s*UΙ?”Π=`^¬Φ*Ζψ°`^€I:ψΰ±"ΧjSRΉΞ㸏­ΈoqΏΟΫ%.Ι½¨ρήΙΖ4ΘG+²«>%ΉW‡εh΅}τA †ͺ{λ›ΞΒ`aΘΫ=ΰ=;FWΏ##Ύ7• …T‘ō`J‹eφ{΅Λ4`}»ΡΡy κΥ«€₯ε£xU„ρη_§ΜŸžΏ…ΰφ6HΑŒΧFζβ€Ÿqά΄ΝΎSQπ|M7§’±„₯‘(CGI=_X΄{ώ-·Ζ_η)Ζ]+E°QτΞ{麈Έu%­š”fH‘ή(υΕj{€ΉΒη ¬NmΚ*ͺ·/K¦VD°ώξάz¦ψb –4ΖθkAΤ# λΙtο œ‚%ΰ4΅ˆRΐ ¬«ΟNK)©υ―ŒmSΉO:~vg'gwdW܍Eτ[šΖU\› Qς ‘€Ξζo«o5kxCέφ.γF8αowrσ—Ÿ«·εeeξ)–(Gi—oΨu ž™)ΕLeΈŒN#ΰWπ)7/>n&Σ‹,y¬c»KΫnq―l>q9ypΣψί—Ÿε?ρΒοmρ·wmˍδFΦΟώЉΨΗ ΪΈ_>Ζ‘ΐ%‘¦[-2H©[ν―ί“Ε[U±ŠdkH{Ό1zЈ[S™y€ΜsΎNεȻːίΑ‡ͺΰXœLIΎ*+Uƒ,¦˜ŠθWί!‹ΥΒΫ …΄Ηh„‹νENwΓ*v4}ηΑn»TWΛ}ρjΘ…q.8 (ύΧοζ3Zμ|RοτAεύΐœ°{«m{/•Oΰ‡Ÿ}+λώ«ξ――W«—ώ›π!ύς^ΧƒWΫ_[3u]lψΓ&YΚK!kv΅„l’ΕžΝ[¨"4ΐ«ro*3IAd£)ω’—ϊ&ώφϊ½Ώt‹#ςruΨbg‡Ε'’ŠΓκŽΥΫKvϋ€K‘.Οεή.ΘT ΠbωU!óמ―Χ° X35Η¦,5ΐΎE!&Γr \„ZC)ωΣ› g³—§aΈΖσqw‰EιΈ{!aσΛ ³D τ¬‹ΡY”ΰe£f|9βΪ\nΩ†‚ΡΞ©dfZXf‡ίΫ'αψΉρποΞȞ\mL1₯@;Θΐ‚ͺΑΪͺ¨ V+χQΓ€fY«*>λn&s‡5_Ϋ^aP²”LLΜΕY˜ΈΆΏ»V χ%ΜBΗ•#Έ‰Α92„h― 9>αo(λΈςί5εM‰ ΤφΧ–ΰ±ωβ<όTδ’-ΡιNΛtU •CNI’4ΦΑ ¨ jhLsU…΅ PĘ ˜ΡΕΕ§έΒΕ*³ah{΄-/4ŸO«ΦXΔΣœg”WΕ›!5„{„4π Ν |ΔU€e$‡Μu«-/Χφζ°Βώu―ΙΑώΡη6›’«~2t!>ϋ1Ά0HΥ[™™°ΐx‰< vAΝ%|–Œ6¬&oέησ§SfR3 Πε‰:νΊ³ωΊΏ ζ«5J&(} δ%@ξU5otζ(,h©;ΨKU7…€,ΙE AΞ8Ληz ’φΐCCr(ΌN £¦ s¦DdP”1o­—η½K5ΟςΕ»—ί*`κΐB ₯±Ι0Ε €t,Μΐ‘ Ή΄š`©(;{“6πό‚~o<ϋτόpκύθ l4§›ΤW'ϋ `“ev±NΤ&™9šσ€*ΐ|CΊΓά§ΜmΚ΄B’ˆίιδ―‘ΟlgΖ(fΪ·3I‚€J"‚ *² θD sf©‡Ζά`‰& {jψΏ¦ŒΉ‡ί;/ΜΨOΦ·#N»λ¬ς±όYiχ½S/ Š‹d²CΖGΆͺzb•Z©uae8S*φ&M –ώεφNΎMŒ·A»1€;Ό±=²ξgτ|λfε·=ΐ½0wgM™ζώbΉ\ηξLCN’J’ΠΑρy…ŒοΞx–™uEσ]0^σί,SUΆdψ.υ3 o«΄9\ω?ά04{£*ΉυO°­& Β*ΐύ‹H‘9<΄ςΦ{œΤΤΜuΞ!j`•2'FςΆIεηb³}ψo!'<Ο€ gΫtR|~SvMD<,ϋΦ α4B€[>²Φ•ΰπjφω—λzΪ·΄υaΐEXͺρ1}ς‚9a>‰o£Οx;Hm\υ)ŸΒ²0EΣ1«Θ$“ώτΙxπwο=œΘΝFk|.€~i@ΘIYΑPΰ„cHl5FΓΞ\؎E_‹ίֈ⁠ζκηšίΞ-οί“Ÿ±Cΰ ‹₯ͺR•NhD«”ρδ΅VΝGšΩ«dSŸLφΪ ΕΌ#fϊϊh χπω")_=λˆE`1w―’Gp•6ÍΎ.Γ ΙΈœΩ °Xγ"4!β›…Cs`WX;Ύ8Ώ{€sD±„£‘‚ ΫΔsGFγ;‘ΰ±#r0έ΄L5RV•/»ŒΜ©akΎEsf‰ψΊΉ{Ζ³ΈϋξxΝΜ=₯2ζšeδdΨLžμ™νQ–TΥ§‚ΉΔΔ &;+Όΐ•‹Μώ'g$;'ώώl›ΔPL·77τPœ=τΓY―’I(5Α)’S³Λ*WLΑ΄Žΐ“JcEΧvΪPλLη˜HrΛΝτ₯καΪνβ0ΣH V=€‘Χr/%ŒFzA:Ζ b‚@2MΩX ~ZΚΘ©‘'†xQ+Wω’΅M;Έ΅Π%χΎ€4@ ,2ηŒ xH£f₯"Φ.ΐπ usJ#κxJΆ:‘[|4ρΜpꜚ5 ρu΅ω–^–Ϊuœ©Nέ{Q%`R‚‹cζ έ<ϋΊ(‰e>ƒΖϊΊh™²­—¨„ˆ₯μr?o–\‰Ήn―Ɏˆq ήέI,«·"Uε”΅Έš±S-)­ ·-‡`bp1{eιYfΕΦژ*―ŒeW+τθ³ίΒ|£Υj λBmˆ²‚ψU›TR†Ε ˜KrZsFD¦γt‘Μ0›ΥΕA|œE ϋΧ\εZ5,Gc² ‰)Dbρ•ω‹πˆQJp00n„"„Qg]ΜφΫβΐqπΕ€Ό«{’έκm.‘€€%KρIΎ3fPX8B¦ )FwͺBΘ SγCCδ"Ar|GΎOHό§£^ΰTΈhFίΫo皘ώ΅όH72ό4β‘aζ₯Ίλ}bUΝG»Hw•Šxa&ΕZŒ  πunVt1/ί6iσσœΡγ8τΡ:^œ‹iϊϋσ6Z%ad)ά<―3 6^΅ ’Q-ω΄J¨ΤɞΑωfG“ͺUšΒ0Ti@sρ9&ο‚±ΒxΈ6€‘nLkFŠ„ /ͺ妇ζTΆ6WBbŠ$T8]]ψ€₯ΎεN:ήjgUψό ΑgHΌΙHžωˆ,Ιε«φ„Vz;ŸΈγ7ζςtξe~\”'d”υΘαQœςŽw€1sŒxg}φγx\Vˆx4Œ½ΣΩwŸtfVΘtœ}Ÿ˜aFqu–εε ~Ϊ₯<—–…>ή(­ώ[ ΟO­~~ŸΫλv»γΞθ·³L’*\_Ύ>Aή9Υΐ}αΑΦnŸ„`y³¬7S“MrΒμY`žW/ψπΣsΪ«ότ–Ά_/σ‡ -}>eΟΗΪΰŽmd¦7\³ PΖ Ν,ι嬔1 ·€—z™"τZm»ΈQπ΄ϋΊχž7iύeYΆ§wΈ]y8Οcώ―ϊcs萒7 i‚lCΔ·λg΄`2˜ΥzΖΌ/σχ<xΈzFΉΚάύΛ5 vϋۘO« &Θ}φό<έΟLv3tm‡β›!ΝÞ1Ϊΰ½ΝΣύΠ5{x:#ž΅‰ œQŸ2c‘hω’^_χΖtn~mΦD_λΥΧiO΄“―™VΘ>Lχ§ζŽa φϊ­zΡγω;ν°Ϋ&¬.χζΠί½€°|~]πnΨήΐ’wΪ!='? ‘λΛ¬ύdέ'“ν»¦ΩΎ|ϊΙύŒb>5νΕί֏9°ρξΏrέΨηiαώ1Ω!vš%1ΌςΔ½y9e­₯ιΉ™ΫΏeόΎiΑΒ1I›h“bŽcΏ¬—#ζσϊ}Wμy&.wKΊσά>°ΪηΏe7Ϊ«’ϋŸύ­o‚‹τ­M3-₯’μJΝ|κcΚχI―dΗ„ uνω)½,‘…‚ΙϊηΛαΰfBΪν5=§BDή‹Ώβ―‡iH7o_ΛιΕaί]šθ/iB―Pώζω0u˜o€­ož~€8rP=―Su=Th_τH/{j*ž—Ξ_UΪ–Νr}hιYΎ"Ζ"“ΪΨ―_°P«ν‚φώ‡YAW‰ρo;ρΈAa§_λΨο}ό³‡+Ύρ΄‹žΫ/Λo7yO<Ρ―FΘ~L<–™Vι΄;OλsςKz;Ηΰ¨nV¦5n”ΔwΐΡ–"ηŠKΙ…/₯RΒ y%η\΅kΑ­ŒJήΩz‰ςpŽ—}nΘ;cG³{¨ΨtLΞ.qL¬u§ΘF%#DΚuŒΚη$έ±l [UΘV)γ%€₯ n±.ϋΉ]<ΏΎχ/u>‚{rζό'dς>Ί9ƒ/N;ΕT™΅Ζ£$[K©±Hπ= Bl]ΨNk|”2Ks湏ώεΦ£ ΣΌ –Ιi‚΄²ΐŒ1‚ΰ;RuVόSEƒe•J香€Θ†;ͺ$}Έ°ΞW—lz‘½h^*RΚ#«°Μž@²TΥ²R-yVβ4N& ¬ί‡m|€bTiEFln–xC οτϊΖ>οFςς½w\k.Ξ†?ϊγφώUYΚ'­Ξ€―ίbl©ΙΑ·ΑxCs&ς7ς\vŠΝ;@*‹d”ρΒ€OZΔκρ·˜Θi"\RtcRQšŒu:Ψ’[$§³e&=(&(‘kaZ4΅Oφs;CGŸ!w>BΔ™ΛλΖmΟκ‰ξN |ΝΒa”ζXόaΠ™Wηπ fΘp ^K%)†ΩΦD#„M„‘0Wkƒ§―T^ή JUgBy’–Λ$Ό›ˆΞϋ¦€rͺΙͺ°φ–Kn¬ΆŽυΏUͺNΆ‚›iM>άψ>m.δ)»£½™iΧΕ †°½Gοup'ο©·#ωδ*Ν£"Νήπκ’(VωζQ±X0ΰ'\JΣ¦V}z„;΅A‚έψw“Ώl/Ο3ŽW³ό†όΪόί4Gώϊ#Εƒ4-ς"c«w’¦e·θoZ#ύίγ#…§;βύ%ΝΎδΐΥe΅(XΒεϟΪPΕμνψΐΆω’}‘0QZ„ ϊh)+Αύy2—EΊRB /<|.š'&ΐ%λ‘ ‰Ω/o3 L•?a*ρ¬ˆoί΅”Ω|σ{Jϊ¬—3ΎZηe―ΰJ =ŸqΗϊ’«žKa2ΣΪπ=—™³Ÿs-qp8ΨjΫo‚ί` lŸ@ -f ―Τ{vΰMύžΒ@κυm%`fŸe:α{{ΐΡ*“Eρ6c9ΌT kΥ'η‘T'πžϊμ{G˜ηdCbψVdk‰ύ¬dχfχχHbΨ.@EυšΞΏy‰‘ΎδΏ}P—Z]†Ϋl΅ΗknΐžskΟUθ»ΕΗ^fΟ,^wώͺqΫ6ν=Ξk½š0HmΊdΐ†ϋWάΆMm‘ͺ‹ωz΅J³βΐ£e+έ—PAθΟΫτ…e 05 ?VΔ^σ<έ󇇉υ4%ΉΘt»h~x(??U7»φi¦gύ“‹΅`“ΝŠ_&Ώyγ¬Θ0_²(ΖpΈNm@\ρδOΐrςϋ₯όŒ+ŽΥΧM“ocΜ"Ύ(`ξΟΰλπxyI7ό±ψππIα9›“ͺƒ bŽΈ„ |όΝΰΙ”―—ΐ‚YυlΌ7rΠτtwΖ’[ι±ož4zT¬ΰΘΒκ2Ι„ΎςηϊφΏ§Η₯8-²°zΡΞZ΅½³’r‘dτͺΏ}Λe‘‹V$ƒŽphΔ:€„‘”Χ—Q‚ݐ!~IŠΝ”λ\E@d)—y‹³φ­XΰTU±› ‰ό-α‹m…Μ²4+?cˏΆύΘb‘₯“)ε—%K&ΏY}μώ‚%Ρk_„ρΏθœhhN)ƒΌ WL]%(]G…άΛΊχ2Δχfί΅Pτ―2 θάύŠ8ƒbρŸΓ€yΈβ pΘώCμ6ύ2Ϊξ‚;υw€ρlvάkμ=€Ψ:j¨L;r™>Λ™ˆ²‹γ=Y9;ΪιDΝ£v»Gηφž:Ϊψ3:O΅ŽΕmš«#qΧ<‹vήq+βνΧ½Ž>'t‘cηΠ՘εηΧΑGηΘΫγGd{gψΙΛ&-ύŸŒώΑΘž½­ŠtΊ`ω’ςΗ“ž,dŸν”d7ΐ£Χ‘1 α2­ŽΨ«τβ{λοΗ/d֏˛κ¨ϊ΅μ“ίG9¦E`‰LΧω€:ŽŒGψ'λ\ŠIπ¦ίφx]΅<¨Ή–JΊNΖκο³§ν―*θλ―}ηd±ΖΘ4LΧ‰`›ΤJ;0ž‡W͈1sgrh†}ψe° b£cη.#½pq:{Nζς4ΙΣΝyάνiΫΎ°“―ωΰλιόt?ΰ9φ_cŒύ‹ SEΪ‘Λι.7ΞΊYDtΤ ?μώΏ4ΐ9ω¬ρό½ιG«ΥΫ;δ¦Άέ‘Ϋι=ρ:ΰN-„YΛ ΪΌΩdν΄'πo“ϋκA%Βδ|ΈΔfq”ωnJ§Ϊ–ΰPΆ‹;Έ£9ξΟέenGΤ—ΦjΆ”]‡U©πΠΑ©Bf¦‰|ΩZ΅Ϋ¦τ(œ©s3[+wΛxΧώΆV\7šΟ΅’­“Θν ŸTr^lςng½Jؚuu£,ί©JRβ fYG!ΠbΉj)Mξ9Η|υ3ozbΈŽγΎjϋ3{ν,’§ΫψBŒΦœg•v c)WCu/ƒΕ0­Vfγe»χρ‰ŠόΣ²fš©{κΡFλΟ»Λϋ©ηΡV±š^”³yI‹Σ«,θUŸͺ„?ΦΊψ»ίUΡ<λy”tΦ _`Τ¦ζLτL`.η4Βz‘Λ%΄]EEΘβX­ΓpΧ¦ΡC™{ΎΘ7<\ŸGμ—$&ͺRέΐ^kμ¨^±Zq€lR₯{δβTaκΣζύ Όj»[BoΈδ”iί~)sϊiΞ³‚UΊ-°α όΏ[ώ±ώΣ θ_ς*ΰ"gCΑƒωŸΪωŸ]BΗψ߁ι-δƒΩ–yΊNŠͺ εNΊe³Κ4sύ6°L‡ΏeΡ8œΦσΜΫΥή~IΎF{Ε)ϋ\QpwΡ;(ϊk¬zž8€·₯»Φ˜iπόΏWσ=V§9]ςΧ9( [X‰„)θƒ{έΚ­εn€¬Ω0*얁¬ς«'iΆdqτΛ&ΪXΛ•^]C½šκπ tQ‘Ύ$SΎd*-ΚΡ‘ZήωJρnο}fŠκ‘jΘZ₯;₯›Ά~Ύ+'{W~rZΩEŽSΔΥDv+βέΚΆ~ΰ4e{;_5E[ΏθXEϋ&Κp7츍jΌ±›ϊπψwUω<YζxώkHτΧ,τ&ψΟ°M«EΫι?tόΧ†y]ν˜m °_Μ_¨ήkHΧa@ώυIΈΣφ;ςk΄ή™ώ[ηίmλΏ³#‡1ςαλxK—TSώξ( 7Δ( ζ²}5―kΤΎλ9Ά±ο-θΦ8–1^ŠΣš=hΑa$ΕtΫ+Ϊ²$?œ§“—Ώ5ΝΧjЁΜN9.•n‡ε¦Β(.T]τ‡| šγ³δJλcΩxύ,NUC¬7Τς²Σσ«ΨΦφuΫΖέY ¦ς΅/ζΊ^π¬H퇽©u~ΐ±ѝωϋΧuνQώίƒώeΥ–'<ΐq•βΏΗθ†ΫςsτΌΗ_gH[Ζ±ζjͺoΑz>ΛdXV‡UYρY΄\‚ -hΖ]£ρ‡ŽJˆi?΄¨KGΌ¨2ƒl/5L°›τΔ·Kτ’Ό«πžΣ-‘˜γ°[d~ϋΕίΞγ–αŽρχ )υ³'mΧXFΩ ΰn’o~ρΦ?μη'ͺR&² œΛίΫΛpL%s―ύ~ρ_cύχ{ΣQαA­ε_dv™'ψ ύί2Ϋρ_ζh:o"sΨ{}•|}°ϋ"OπYρ?ξˆξKu'J`zβψ2 p°ώ³λΆλφΏwω;`'˜0jSδ@_Bχz9γ«΅‚όψ=cou£_M]ΰ@—.0Ϋ±Έ―ΏΠzfη2—DΓY€x΄u•ψ‡Ό*D·­ό•€Ϊμ€#ƒeDΎ6Cžχ„ΏΚ,[£d^¦*V_«ΌΕQ rY4+iΓη(εE\~Nнα³Gο $ΐyυ?Gϋο}ω?ϊρDΚω—›ηUΉ>[ωGω?tόζSΰ:šۏ'>p‘Ν¬c{5…ΞΚψΡφ©«Η•œ/βνΑ3Ս͒uγχ]ςcόη}ιΈγΛUΜ?‡ν?iλγωΟΑσ]6ΎΓΔΟεΟ΅E7rθαμ;œλ?ݟώΕΛ¨ί›mόo:cύη‘σHΧ 3Ξ©ΘΥΚΉU&/+‰|ΕσΦπq!Uβ­FαhŒαΔ[*^}€ι—Η#oΥδ^δΏVisΜώΏώ7ιθ»/ύ—Q]ηπαό-―eτΏύ_&Ο³8Ολ#jUr*=ΛAthvκ—5™·ˆ½ύε)JΓNwiΗ*)†nλjϋΎ:]v$¨,D_–Œξ²»ΙKτq§έϊΚηWΐΨγ‰ψφΥδ/’-» /$ ξV°•|‹υα„U&±~ :εΑψώ»?OΎΑσΉη&²ί>qLα©σŒξρӎ'”O΄dε%y².Ι72j„7εW9~ΞωoΣν?χ uώ_§tP‰nΉFΫώgΩcύ―»Θκπ {Q’Χy<ΘγφAuQΧ‹ ηΣ(lKI ০i8νԀ̐­€Z3 7ζκΐ›%λ?:›uGެ†ΈύnΉŠεV•LC-`ΥΪΟ'Ο›¬²”Λ<Ÿ¨_r°Ά‘†”yδ˜ύύΏχηkUϋRpπό·c·θ―τΏ―xxΙ–?_&ΝΠ1±#ΙζKυΥ+p|X κΧEΙόr–_φl Ω¦ŽΪ €sψΏ3Φ½/ΰ£³»\nWŒ5Ϋυ?©1=ώ.ˆ:/Β·½¬Ζ@ߏ²Οηδ cώηΡ?—ΩσωΗ@ΞβcώΧ―Ÿλe5ς²ί‘Scδw¦œ_©Πϊ[ΔlΕXΤν?w΄θhM΅TιΟ­φӁŒ!ΤA—1›Y-"Ω:†Ωb΅€<l9ε –$²–€xμͺΐc)¬λΔ-el«,$Q!3ΥΕm€2FΙV|Zš”΄»Άsc'„Ή™Ν+²£‹wϋΛυ‚Hυl'»gαKœOk#φΛK “ν@ρΚs˜έGŒmBυκ„Ό:£Σ©7―Fσ€ŠwΦ9\:«(ΒNίv΄ΚέήΞԒ諈?Š£SšgςΫzBΨ¦ι8ΐβ]Σ΅,BCΛ1KZfθqβ›AϊΪ6¨πI9κwψΉZ΅σ£P}OβκQΑ,.±Ο¦ΜΆ}BΉεI‹qΓγγ¦Ο¨°X–γϋ!£†°„ΘWΣβm%;Μͺ«,]₯Ήl›SmMΝ` eΗ‡UP ΆΧΡwΈ0UΜvε;φΨϊZσΚΈ l­t@Gkκo‚F=–`Ό­r5^]m>ζTaΠe1M’ω’ˆίN"œ.ΗYˆz°4$‘> C“Έ!#Aΐ™o”Z”H—sα‚j"φœ+ΐz£2ƒ ²Ϊ,ẚύ’› qy*$ί^Ϊ93§6β—(ζE¬r»eΥΥSjͺXΓ‡"ZJ1Hm$UcTΗ56k.θς¦κ·7[ξȟRj―I=S;δτNΡΥΆvkCι²μ΄>"‘~_΅Η₯ƒεΒΥ2ϋ‘Φ\―©jy=•ŠΕ{ŽaόkLφ ”dX="αϊΣ–ι/Q3]<βsYzξO½¨§‹RRG¨><ͺ”΄œržfΡ¦¨…zc¦ŠuwχP±G‚•ΈΖώ‡κτdŠA§Ο4D –έΡ‘J,HΧE­”₯σŒ-s<ωέ?ώS>Aι”ΰ&ϊ—Δ,mƒ•žΎξ/5'J¦ž=%N)nπΰ%£ϊφυΰλ<ηό0άߝώuΑΎ2xπό'mηt1ώο=ώΪψEiΣDΎlE«¦ΧνθSu-θΏOΊυ ~υeW# σβ”ak2λR0[ͺa»άν}(ω]ͺV{ΰ ŸΚκU%ϊΐ!>m ZךΔΫ»%J½όxζ(«ηͺγ€% ΔW Fύ&Ÿδ ˆΏQ« ƒ:‘…|ερZθYQeΥ΄όώφ‘ £\\‚>6ΪȈ>nΐΟgΕXcόί0θϊΤMσΏελmΖ›cώΏ»ΘN jύb ΠΊW3;zέ¦Πͺ%¬¨£Τm,ͺλ“Ϊ2uVαΘ¦ΡAwϊ‡‡ŽΑ<•†…M―Ά­Άέ+°Ώ1<ω~0EΎδ_’Ιο_*ύς‡ω’Eρ%ϋ;L1­N’Β‹–λ$βΪ*πΝwώΗίŠyƒ^²x‘2Qζ ΄T&³³m₯₯ξB‰<š>>όΆ;ΚaΠ_X/A‡δΏCΫυ(σέEώwjΙ;ΪύŽ/t(³­“e? ΠΥvΰΙ‘ˆΌλρ±β™Ηα–½Ψgλ9Œ“Nπ³μϊTjξυShΘ('?ͺTΖ œ°Ί›₯Œί½!γΫIαiξIΎˆ––₯λ σ _ ΏLΦΚΆ±kΣPEΎΥ9οΖ·σ‹’‹€R΅.ƒJΞ ±όpŽώOΖψŸ{ΣοΉ„ΕzγϊOfWύcΔορwIώίZ͎M˜fΕTΪqΟΝΏ»ΫηωΘ¨WΎγώηϊO¦=ξϋΣΣiί>‡ΥaλŸ—ϊθ#ΥεŸZΊ£ŠZ[ \F§Δ’ε’e|Ρ &³ΠΧΌηLx·892YS΅άeφΛ#φ}ςŒηΏοB*―ΓΣεfΏ£ν†ΫΚdΩd<3xό―Ξ%`ΰο\&³ΣΉΛ»ŸΠχ΄ω+ϊς<ύY.UJΑiώΦΏNV™ £W)fΊΩ,…[―ViVΐ΅UΜ £ΝΩΫtzϋ֏²"͎°ZnΗκ%ΪΎΦ‹Ξnό–Š›‰Ÿ—Ϋ*ε|<αUΌ»d―³-d3 n·Ϋ½ί2ϝ’ριRΫΖΖ\*ΏJώ·όο–5ΖήƒώUώ½ωσBΤΞ₯)u$8h³šρΏΤ cύ—wωkŸζά—Πwrέ‡‡O‚G«€ΡŠ—ό&Ÿ€/IyhΔ^!—Ÿ ρ™u{Wgσ4Šο’κΚϋt‘p:§2ξΡζΞΡσ«EΓγ?ξOΖ8(ξ―Ί82Ϋο34‚sψΏAΖύ?4ϊΓ·³ ‚‡ω+‹λ’ΡsώlώχAqμαΘόίcŸc:'—3β»ΠΧΧΜJtž?θPώ/£e!mŽφŸχψ»ΔδEΦά¬|όνbΌD‡^o…L3!χ<‹Η­„ρ:z›A 3ΤtΈƒ6Η«ΏοUΩζΧYάνHΒx]<–ώ .™«oΚKs„ί¨Ϊ¦’ΥΞ{YΝ“Žωpύκ‘_6Ϊ‘a€L­„gΏ¦ͺ=vΎυdύmς΄G0Ό†HfΜμφ£› Μ8O•Ι­"ΦVεh`/³g―UΌϊ: 0"\ЬΫbΡρF³μΘΆΚtΛ±­ρ]Kφ6*υ§Ξ[G‡Β4:ž>VY—δ+LήώιtGΟQj|ιΣεΊ›$:[³ή΅ Μ±‘Λ«Λ Γ›nRόπΒ.Ξσψι63f„Γί―φΔ“n7Εο;ΧΦ!Pψm vš&Σ4mω―‡ /ζiΚ‡ΦPψ°Y|:I‹o°θYϊ’Ά―u9…Ηœef—…ͺ?λ¨^ήσnΈΝVQαœš* ―° χCΐrYδš„α\ύ“&yΛςΎΜ²lΔ8JζΥ•η€ΐ qjYFτ΅Ό%"Σ7ŸRΈ ?ŸNƒ²©ώ€8ε—θˆΛ\ͺXΘ9γ”Α·²iΌΔ©=$—iφV^^FI^&€,ΏΒ°q0κΠn­τΗ—rΝ™πSφΆ*ΚΟε”ΐ§(εE\~Ζ)TΤzΙiΥ"§ΡjϋYOψ'₯Ζλ#ώ―α³βΞΡ¬±ώϋ]θΏ1c«ψω…%ΰΪl·γόο˜cπϊ_T„1›λΌΙ¨ί=\M_―V­Ψ1dνͺϋ’8°³ΞŽφΏAΠΠ'»uύwΛμΘdόθόΏ :f›εΐŒωΦδЎθήmt5ΓΛe’χ―\P΅οR}δC ^άόό'1ΪυΏlsδ£qslj\($τ΄l½v?€n՚Ζς΅οX‘ΊUkͺ<*=}Ρχjs˜ GΏΘξφ›ΫυGtΊγΦpg 20U₯QΫΛοrώΧ$ΞΘAYœΎΐ­d~68$©kΆλ9#ύ‡.{d½ΊεžΦΈΆ’•ΩύΫ A,ν4›­2Yo½­ΛϋυΖ—A™e:‡]ΗSϊ^­ρ"κpγ<“c^ώ΄>θ›§A²ŠάΦέέjͺο —lΟP†ΑΟgΥλ …ώ+–ΓΉΐ pPώ«]gΜ?xωίQ¨άPΞ³’θΎxηN€ œΠξΦεΝZσΛςžΖκΦP€ΑΕ"]σ’Q @ώΎΰ¬ϊ?cώ―ΑΠ_qάΫΙΓtI[ώ;£η£κΗ ϋƒ’ιra£‘Β(l²ί—»tάC ?@θ‹ΐ‡λΏYνϊ?Φ¨ ]6άUΆ!ω™―¬^&xQιEξΧΔ/uŸUΝωθ€ΐ&_ψ—[Φ£†CΫυ_Fΰ忌Š…NυOu€‹π*Σ$ZηS™Μ£€* cͺζ= $-fς™Ε} ₯«ϋw‚ σŒ­ΟΡ/έΝ«»7υGIΨ?Τ­3‘J$Dάƒ<τ½Ζ™šΠ+­υ<²m1,ˆs’;ΌΌ€χαΧbΙ‹ήΞ45Οχ<5°ψŠη(n”ωήυΤ™ΠQώߝώλ(.’€TSΟD‡μ?6΅ΪωΏŒ1ίΧmzœύςu₯k"w5VχήΕΜtBϊ>Γͺ(¬ΨσDΩb Kάb£~ψ €Σψy(ΰœψΏΡώ?ϊW΅›°τΠ­β)iΫ\:ϊ/wΟ‘A‡λŒ˜έπa“ ±όΆ”,‡ίΠάΤάW3˜ͺL"‰.ΉηTα N‹/Ξ­zφž­|†)2{†ΎySUYΕ¬ Ί`%³š%I έcE*οžk§ϊΫZfo3e°ϋ‘z‹m§Ί;>ͺΛ‹Ρ~τ•ΙχώΣω8―²λ:~·Cπη4Ιω\Υ‡XρΡFdˆbNDaX]ThΦβ«~Ώ…¨P.W˜΄―˜ cΆpbό,yqJνqLΜZ%~q¨e&_€*/l™ZZeτΦ©“±R9f¬ΖDͺ0W²ηΫ)³xοdTλ™eςΊΫαΦ―€rΤ"’’Ο=\kpn=)^kΔ‡°kώΆ x¦T<½9»žΩmτ‘/*|ωž ΟvžƒŒ1ώkτ―Bmnxώΐήρ_;ώkžΟE±Αu{ wΏtΧЯӐ̻]€h>nΨ…ΐbξx}\q<ησΏcώ!ΘΌIύ7 Ύ£ώλXνCΪΒω4 λ@»θπ+Ϊl”0[–ž=U μ?α‚ε‹ͺ2^±œ ™ΙPsέmi'u—ٚ™Θ‘&#–eμ­R$ϋF;ŒΨU"bcٚρŒ•$έ”DΫάn²qR•[±μ τe§E³΄ͺκ³½mδ΢ښšu«ωrσ±φά΄Vέ»λαiWΕΆΝΞ‹}―#›έί,‘Νη+[dN2}άέlΠ„™έ"Ύ«J™Ύ6C$άψλΓ Λ—&ύλCoΩ²₯\ΒΞ£›rŒ—W%λͺ™m λI}}ςέκ?ΉΦX}τΗjœ—f8@“’VώWΗpFό7tόΗtμvg΄W «¦E&7a]ώ»„ˆŸ™u·C‡ͺ?ϋ¬IΊΑ;₯58\ίφRf{ 2 5κ4^•·λ!dp±'„ ξΌ›ξ”Πϊx=’Y΄\υ,€Zƒ:heΟrΖΏεQiwš| Η)ίV’ιi¬ξ©Ζ[­©=R―ήbš―¬>”ΦΡ#ώαRUO•ΙσΠl‘Τ³‡J-Pΐv«•)‡’G]Ε͝ŽΛeδώ€βγΰ%Kφ:‹ε³ŒΡt›ͺ¦εhžvo΅*-Ÿ¨e(9~€rq¦.°[zXΘ`=ίΧ­κοŽ:ΑGΔ—e9ΗώkΠρόίθ_ 7‹3¨αΆύξ¨ Ÿ/}κ0v ¨ϋ}γΜ1ώc(τΟok!k=6λŽρ_Γ·$IZ°BNσ$Z­dQy{ΚϋΆk½gΙΣ8ΝΆgρ’VZ΅ ¬Λ·N"δ=Σ—Hh[ZΧͺ*ˆ&„h‰yΏ…AέRΙΐ‹΄ΐ8tS-pΑ±Qσ·„/Άn‘€εrΤ? Ώƒώ7ϊA•ΎδΖςί‘]τγΏ†.―G•ΩγάΡεbΖ A§δΊ5¬9©XΡ\7ρΑ΄8bλO8…ι”PΓ0„Ηο ρόοθ_n—Λΐαϊ?mύŸ‘ώC—Wš·Υx+A:Z/Ϋ €sψΏΚ 6ξ»Σ_ŸΏ-§†9ςασ Έp™λaδΒuΏ?λώΥyž[ΦώouΤιΥπΝ©°Q|ΤύξυœΡ?ϊ/’ΛΛŽhΧ°Mk¬1tϋO;۞Xm+{ΝEόΦvό+ξ’ΧθBkΣ‰^—[%»EdΘGΛ—†ŠF<πψ₯ε?Οͺi’QώƒώUύχ›ε3lΔzΝόo#ώΌόΏύYή#O£^W6^*Υͺa|αvόώίό_.Ο€ώ΅\Κ7;E¨Σuώk<1xώ―«ή©όWŸ/Œp^ς[U{Ύ]rΞ„έ]$DλάGq(όΟςτςυR π!ϊ[v+ώΟvΗσƒ—ηgΚΌ­ΙτBΩ£sRώJ€ΞQϋB ΰ9φ?ΗγΏAπβτ‡υ?—Άι?ζ<οΡψ>vu…―Z+ϋh>B]ΟbTοΜο"ΗψAΠΏΚXx8@Λt–ύίΆFύθς7γo³ŒΐΆxΐQeΞkpͺ2N_`P}uλ-.>¬~μΉσ \σ— ΅Ί[`ΕE”μ+»m:$oΚ³§+Ι*ρ1ŠαΟύ)“uΫ?ZͺεcQ₯>υάΣXŸή~―²₯I€ŒΕΌͺCο=΅ΎΤνΖ#°Λ“ΜώΏCύ2žύΛΈΑ[ζ₯ΔvΫω?ν‘ώCη»ρίyΒVηΏGfΘA:{NŠ$Ύgh›Β©·uΫs6˜ϋ˜ζ6qή7 ―„eΚΌΒ/‹»Ž—_ΉόχόίΖ9ϊ+ž|[ύŸR»]Α #ύ‡Ž‚¨c6Ο΅τͺ=_°ψΛT!ΰόΆ­Β‚dT,dYϊ]_™ηsQTΪ8’ΗU§I΄Ξ§2™GIe.0Uγmž9O‡ο³Χ4δ’κλŽn·οbOvΊUr«_κ›uŒ™Ι€η„•Ίυ• Φθ­δέ „κsTω[^ΘεΎ“VΊΕΧ¨τΆ’³Ύ9/oΏj`Μψ0,ωξφ?ΫuFϋ θ_μ½aόq,{Œϊ€ψoΔTwΝTu«8ξ_Y8φ PO•>α݁ΟΡόέγFω?ω ˜φΛΩΰό7νvώgjŽτΊόίk³‘s%ΗΘ½K Α:1z½n.?+.5ΪnΖΟ…ηδ'ξhύ7ΊΞ‡ό?†ΣΚμZφ˜qθς?*dV€©J‹œΦΏX­Έ>ƒΰ1Dmχ§ήۈΜ_³kδΞFƒΞ\9<…Ζ…f˜-§Λ·…’ΈjτTkt ΅MΘ8"©QώοΘ3ΰ9ψΟλ‚ώ΅<«7³«UΧλ?XΟ―gύκ /υ4Μ#\ψΚω{ΪθxώsτW»n]‹Πϊ_cώ‡‘Λέψί½ωΜωϊ?+j§p y—,€ŽœΥΉm»Λ;¨L³-Π¬‹)ŒWΒο’wΤ†B2cη­τΓ΄ό7Κ‘ΛΣeΨν…R•]v”MΧίοͺφΏaΠ+aέφό'±ΫϊŸc8# φί1£ϋ{gt?AŸžΡύΈrzΝ!PυΏŒqΏCώ/:Ϊ‡@m]ΛσAΐ!ωoνψ?cΜόAτΏ#Εύ-άΊ)Ž{cΣlUw7dq.?Ÿ*ͺj…iGxό»€Ÿ Ξэ±ώΫ θ―‹T_f8θuΫϊ?σνϊ>₯?Œ ±  S’ό25Ή¬p?βŽΟ/2œ£Scδ Ώ>νs™ϊψόΏΩΞγΪ#ώΊό_J–ΓSšεϋŠ―Ÿ—„ρ]ςά;όfi²?ς™½‹πΕ–9γφό|pŽόwΙh ύ5ηΈΩω/ΫpΫηΏΖόƒ—+–}q>‹Σ*•39\=ΰ―ΚύσΪΈΏςSn;πι+C§πχŒ31Λθ;-…½w[ϋ?€½ΆύΗεΠεWύ‡w“π§/Π?υk=„U‹―2ξpΕΕNA)*c°£δ½·EGς;ΨGϋοδΞεŒ%,~Λ£όFω%ωθXsθς?‹σiΙΡQΨcώ?ΌTςV,„eAe&δμηΌͺθόωΗ.”Κ·¬΄y«ΨύAYκwΨΘh¬¨όσΏ™ξ¨ώ•9π†υ Λiγ?{Μ3xω―4ΌεΆκχ-S’ž`ιΎLRmμίΏ)uτώηϊ/6υΏAΠ_ΕΫΪM=θό.‹tU”Ωί±ˆo²^Ξψj½/!ΨΧβΕ σΩΊˆzΟ—7Ο;Π62ΜϋO΅©ΫοιόΞ±λJkυΗwηοo%£oτ‡=~iϊΟΓ翌–ΧΆι¨]ώσp>Β*›'€œ§+)¦E\ƒω‚Ρ=bͺ ‘/‘ΠBίeΑ₯°KaRΙ‹‡₯˜ΪMξοŸWJφBh1ˆθ,˜Yœ"Έ6%]st™δEQ?Šέ_)Ώ0ύηYω?­Ρώ;ϊΏ-ƒ4>•ΜAω˜ŸζιΘιΪcώΏ‘ΛΥ:yCΩ­εU;ώ%€Z1rƒ φψ}ίΗ7ϋ^'ͺ>jJ³ΖF…ύΘ»ψYPΰ―KFω?ϊkζrΫό―†ƒΉΎ[ω_Gω?tωBόχΧ nΏG T)ΜίOϊ·οs<{ώ”V5Ÿx­VoΥ:ΐKΚ©u†,8ΘΝ¦—–1ςχψk2υϊT“9;oΣ–%ΐΣ•tψ±Αή8+δ<Ν’Rvω,γt΅”I1UkΓ|„Μy­ͺO*Lh²ρJf“"Μe"3xΝ†ηE‰.8€ŸαΣd•‰ƒG·υΔƒ+_δ°V‘» ,ΖαογΏπ8ώSΎ?.XΎΐŽΕ—‰Κpύπύw™ό۟'ίΒο,δ”*]ΆΑš7[₯šdBίόσ?}ϋίΣγR¨««4Š4Γΰ‡EQ¬ςί==Αο/ΦΑ#pV΅™¦1€iύIo±&·§ο©kΎO—§σj˜cύŸAΰέτq·±Ωn‡ύΟqGϊzσ?ž €0λ;ί‘n½KЍzŸ=υͺβIέ:€Γ›ΝΌ›C΅§žΘίΡώ7ς‘ΠΦυŸΜϊOξ5tωΟ,ώ2•Ι`"bΛ&KΆχyRΘε*ŒτR³ΛM\^˜™άœ3Ε.°,coΟ2dλΈ¨0dq. ΡUάz΅Žc‘Ύ$SΎdΩ—Sžχ΄xΐšGΝ„ ΅rHM6l*6¬Ε lΆ)NΚ9n§hΩm‘Ε Ξe[Ά Ϊs[œθš±γ‡F‰Q=XΞwΎ0œ;(QGkvϊ.UΆLž§@Uθ~«θŽŸkΕ€π+Kς¨1ŒŒ&ζž‘ς„U1-€B•εˆwγΩ–ψ“)ο e?E²1Ί„*l€z•Ε\Uφά_ΚΩͺUΥ-ΆοVC$Ώ4υΓΉςί²ΜQώί‹ώmns[ϋ―ΚυάΐdŒΌό?]ότqξ6(ΈŒ7ΧeƒM“ΡCyΖώwϋ―αŒηοE}ώ«ZΕB./“‡θOΆύWύ;Hό~¬ΡΘ‹?ξώηόοζ? ϊ_Αx·σΏΨΔεΠρΉBšΖ*ψοΦ‚ A― ¦OΥΕ‡ ­2ΣςΤ•x­ύΉ θœόŸΔυϋΣ?\’G0 £ωl•₯₯σχd‰p0'mηqΜ1ώσ=ώΪI=ΞSEgΊuΠόm*suε―yKΪfŸp«t+ΟQ§[N΅#5Τλωτ%*ΣrΩ*ηΚ;qNζšίύ§BŠuΖb=!S³¦+§Ν·žΖUx+$OΧ*r„„ƒ'ωqEΜjžn2φ4‘/ΫςΟ" ΓmΜ†ˆTxεˆυ]&Ο³8Ο«€|{«ͺX4Ol“dœΰsΘ%?Ω/o3 e•a$ΪoίϊΊπ\2K_#qΑ¬’^iπ³δΕI}`1Sӈρ½q¨΅πEͺ’zΥΥ5ό, x)TdoΖ%άί%ͺΟΏ|r읱 ΝZ'|j·jMΧΙ b+lΫϊ‰ΦΓΊ±~:KΓφbΪϋŠζΫsBυ"H§―nͺ‡7gB§’€γύ΅NΓ$ΒΗ¬ΫωΣφ7ΤOΦ&―φΜf–ϊŒΈS•Ατ»P>αγRυn-γhͺ+Λΰak\Σyjuξκ5Ωy«ΆόŸΊF]±‡iEŸ©v;*τΤq·ϋ!MH1Exο}ΑN˞—©Tͺ{^!—έ&ι”εϋŸΥM”ϊ³;Λ₯ΗΟΛ)p£ ‘ρ$~|Ϊ½£W li­εΞ~©Μ’εtXI›Šjf&Ÿ:o«ηΚM£_ΪΪA?Φ—ύLΔ0†Ω\lύϊ¬6αΫΫOύ-οASC ›,Ӝ²ο%υf7`7gQΊηα²…zN%ĝφΟwgƒ–χ»©:.€Φ£€νΖ21ω“Ζk‡\ ϋΫλ­t’&ψ¨³κ:-τ4zζs}žu!Ωj–λIL‹Χ₯šLPŒΰΦ"Τ.DΤΞt>NψΦό7,yϋF_Ÿ! ƒ›}xυœ™cύ­,; ?α­ίnξ©c­}°»Œ ΈρΫ‡ržμL7˜² :‹}]rω©ξ;τϋίμα μV“bί“΄ψf·r©i/μ§‚RU‹gθ¬2/ύυ‘šαΪψa «[0ηψdίEΌά’³SαٌOa DέΏS»sπγ—φ"όuMόιf­“/ αͺΦ[«7υy&yMeγΊλ±wΡrψη<ύίtG½ιߍ―_‡Ϊ–ΣςΡ1γ»όLΜ«γΌ° °QRΐΓ*τΨb―71x»8a Κ£TˆΦ›R`ΒϊuωΡ/QΛƒu”HZ š~.e}9ΉΝ‘ Ck™ŽδVϋ\5ΰœόŸ5κχ ε)O©Ό‹ύί₯νϊ?Ά1ΪήγO₯²hΗyςMO² °EmW lΙ~…άΰt¬λwDV΄]ΤϋάΧ‡}ΤQΒγuιUΪ<ϋτνΔ=KωΓ―vόκdAw`ί―ώΛXω.όZ9ާ?!ΤΆ›τ'φ(‡†ΨάψρΣR.©Γά?M&Θ&&9¨«‡Οxi·€ΎV .ή½ £|ͺ7uq©ξilͺz½ϋPy#ŽV«·ξ«ε?3!Ÿ[ tg»ή¨yιͺ«³€Ω(Ž’/ΚT.»nSMk 8J„ΦΝλ ΝnνΜn^ΫΊMvοhΏdIvŒ.“K˜GU2m Σ#“½-r™=·G¨XH„½Žγž»U*„¬“«ΘsžIΐEΔb}}Ί½0%+–ηx@ΰμ7,OσιωΖ,JΞ~ ΘJόΦ5vU)q9ξ\ *ΉΦξεe”E]ΧΚtέnVάh.N£^kΡΏX"¦olOaχγ‰–fܜπ;ν·(ΰ‘žΝ¬—+@l©}ϊρΣ'ωΊPΨR-Φ.ώ1Γ^Cwg@ŒDΖQXμm5ηυIΗPΆjZζk=c?ω—oψΏΏ‘BΌΏόeε<ƒ/Θ'0wΆ΄•?iϊ΅"‘'jWӜΙPΒ aώQk‘V)ό"<%₯Ίέδ%ŠcxpΚ(|Σ$nj8j–°zΕeςoλ(C/ |šΛςW‘‘κΌ³[γ€b°n§/zšsυσ*υ˜‘ΜpςΗΙJ3.1%χΫDD9RX7‚m›©g›ο‘_-Ά~0Pd֊ΔΠ5θe2ΕΊ+lχeΠF&ψSBe»† Β wXT/iς›’Ό‡O&κ~‹8ΘŽί…δΜι₯,v {ΓM5G₯2“Όˆί?ιΰ΅Ξ”šγ§jtΣrtΥuψ­UλΓ–Ϊπk,~ao9nxΨΏ‹hΎ@K'Φ;MΓIΙa0g‘?–kfž²XΟ8¬bά ͺ§“«Vv”("A_’,Mπ|ςγ§r½LΥzΑτ&¨ς|λ&—»ι)PΉyΨ2Zb‰―+ΧEΔu π’ΝιxAdΒΑϊ+0—hŽ|FF™ήϊΜοDI`*)¬(άOΈ`p^a—H|α7ŠΤ*€ξΐΎy©fϊ·Ša(‘€ύΥΟŘt$Ϋ°§LΣ eή·\Γ–j„QQ2ΎΌΜ”JG’ΈβR?N°ώ2ώ«I’ΦzXΌ“π«ί†iΙ`{kΆ€'BqΡΕQQ)`ν=φ2?mςM=jΞωί'\>Pϋ(ΥΎΧRMΥκΥ_»=όΏΐ³π/σΟϊμ+ςόZl€Τz–›β7ΟΘEЉNμk;ϋ ήV³ Α‹κΌX-4$ΙW+­wGЇΑή4½‘=Ό{„dΔ§u» ΉŒC΅dT#½6ΥͺνNπ<*j]ϊτχ%nΠΜς§V¬ΰ‹άϊ»9z‚?§ΝYυ)Ξ†+N)©YNOWoHB|ίγ~ƒ˜V"~ό€ώέ±26ΙιF*.y_Λ θί΄ΖgλN…εQόG΄|UγK,ΐ%ϋ½BΨvψ5bώTΎπ§Š½ΓrΙΝ Νβφe(΄`χ|Σ±<ͺj°œjt‡m^ ‹Gς΅Wμ^TΏ}όΤH)ά3{Υΰk³₯§r₯jB€‚XΘΝrμΥO»6sq?mŽc€Xς „Λ<٧‰b™όΤ“Ζ{ΣΑίμ•ί`o;ϊVΟΎ 'υύψNύφ±79ΕΡoR­ϋ^Υ8’ΈχEπν7'νˆiišmͺΝ0hΙϋφΰŽΑF΅}Έοh…EςεμΏ¦cšŽΣΆšcόη{όύ½dJύ@{ΕΊH—x8GΈ?”"!τPψ›’6¬2τˆRίt †φ“%σΗO[η” |β‡ |ύψ©r~mPΨΓ§vςΰO9ΐ3ΰΘy”ΩΫۏ”˜yŒ©2Φ>|ίZf0₯CBΈ‘o Κ]AΓ£ŽΙ8cƒ%˜’ΊŽg8άρXθΣβ–ΪΤ BΒMθŸ:ΠΐU…Υ§=Ή„>νΛλ£Μσ…ΤO W§yε©’’2KrΣ2‰οPΓŽν[’ψΆe2ιΉΜτCίΆmZΒ%εQΚL&gΆλyΆg6·©/Έλ…,$Drιΐƒ:ΆvNΕR.ω"Ϋ3D΅B>΅\»ΗOk9…0ˆχpfΜΝΧΩkšrTφΣΎ,—i±.˜ΚέΩυ|ΙΈgΧ­ΐ Sp[Z儇ΘxRςΠA `12[8d‚ΨΒ7$3ƒΞAλ³-K/ΕCν΄‘ϊΎd«8*ʏٗυJ5e\€Λς* m6@Φ–πΗΟλ,žPΜA±gښΥW4τ>Βυ$3ˆiΐώ΄%s ' ά°CiΪ!°‘‘ŒΪΎoxΒ°Œ€Ϊ,gξΈ”vηΎ±$¦XΠfίPσh¦š4χυ‰”–GζCάΐ³MΖ<α[Ά¨!jzfΘΛ&±€qF=Γ ,CΨ‘Ύλw/’PxWΡγΓΌ§W¦‘M™δ-ΟβΆM<Σ`.€tδŽεJΘ0°ΐ€%₯ι3ΫτΜρa§Αa¨i]ypAθ ؁ (γΨfwah––c ,Οσ¨„eΜI;μ#π±ΐm €ƒ`έόcX’υ Β= ΦaΨψξΥyΌ`ΠoHhΗσ©γKbΐ’3-Βy"p–a0ŽC%(O°β<―[€κ¬€Μ ϋ© …εΦΚhΥΧ4%0«*°)F8Q’Υ:kzό«―‹Ψ”'D˜/` Ÿ0ΰA!loΪ-¬ ΰ•ΎͺΘα+(‘q©οJ«szZ㡏·šΜO­Œ’Wζ8ΜυA‡Γ'!0Xλ¦/mSŠΠσ„-@ΎΩ‘ϋ•mΪ€Ώˆy°3솑;Τοζ&bμ8mGE‡Μtf­θhΦΝ—μ‹VxЌ‘sƒͺ9WΉζΤg]C²S'ΨH€₯ΜζΊ μΥ_­υ£iΒεŒΛX+˜ΙΈόυU&A ΞΆNguU>ά~R΅#΅:Qυ c0Ž9LN[Κ^›€fΕ9 EB6μBl§†νILΝ³—G”Δfά€!ΐ7Γ1(εΆη9`ΎI:IΥRΌ*₯WuYΎNKCΫ3ϊέΐ΅O­C=]Ώ["[΅b4Uςu‚%Žh›Ί°Kϊτ._0ύ`Α²:χυ»Z₯½ξyhuςH9h§z•#u—:sΟBάίύνΖύΤ¨zpm¨ ΝΐζΜe†εωVΐ…EΈop°©eΩa«Ο'ž  Aeΐpθ^υ`Sη³1θέΈ€stξ9–ο ψT!—θiΔτ€KωxœΫ\b%  ;Iz6s-Ϊm*ΓI1ΓΪ€3ΊŸNZžξ":σρΪ0άπΈ TB…εIαƒŽΘά΄a€Μ—¦τ Πξ@1 ™)§ r‡Π€„εRXƒύΘ[pϊΪk ΈšΑ₯ezΆ€5ƒ™Τ 4ϋ.·ˆαΫχΘ:Ο₯hλ€Κg’ΐ}ΗβU·ξΏGρ虨ΜΔοΈ0ÎeSjΠ Bh•š>,Σς-Ξ‰c F@σ  ΦΣνίέΆw˜Υ(Ε―‚sjR^ς*κ€vIE —U‚w/V)Θ·—•“]}KΆq—ίv“Š‘EΝάεψašΏiΞ^«-­ab Τ$Dψ"ΠθSπ Ίω0έΌ|§A‡4Α¬ζϊΓd•Κ‰^V·ή…ΡršiYΈ-^ Νͺ–?§Α6ΊΊQΰϋ‚l †a«Γh›ΒvΙl± ~Μsύ>SλΝSœ­WΥ Ξv*kfϋ]ϊζ3ΦΕ΄θY˜&Ϊ4Σ%•τ ‰nΉ #žΚœ³UωD‘E«©²Oκ«ωX–Λ·ό’-u±λΘ΅SY{ηΚk$Z–^€h:έQp­~΄πίΧ~hύςωdη›‘ρuφPTΌMΓ ~ —Ν έ¨"λ/ψύγθ¦bιϋX’ͺΒαύΐgΥ;˚ϋ Ω3ͺ ©΄a΄ŸZUEΊΊ[ύΪήwΦ8υiΛv‡›Ÿ]ϋΕΔFτρμ-Ÿ8s'gmςR<Πς,g@Δ‹γN€Όa(έ<δ°/¨6‚攐ƒSόp~*Κ³”}o«"bΪφ”μΚ£† ΩȊJ6DεΟ`ŒΧtΓ.[Όv‡™žΜ7IA[>°«Cpΐi¦ \ΈΒ΄]JMQ%‘%y†g$p|Λ1|Γ΄9@=BΒ€\˜Ν-κτμ%΅Ά°‘Ήavc Ϋ“˜kߜz}Η ΝμΠ Ι’OΠ ©ιΈVθΐ€xλPΟ΄ Η£·ΰ˜ΆIΗv\ŸΩžςλΫϋ'…žY9bp§Σγ9 oαkΗΏΆκœΓDQξp‰PΫwL]oŽ seq‡ Γε¦π™)aι‚SΒ|ί—A7Λ­oΒΎιPθΫμακζLΧ³Aq½Ϊ (σ@ƒ p97¨τ@›Lά(–t%ήrΈΪχ)3ڏGιMΓ9:&α>•€‘SΒ2Mίuˆνyΐš+‡„RΪέ΅Ϋ ,‘λ‘ ”e„}>@Fρ—iΙ Ί”}ύ&ί3‰orΖ…GB#τ©Εxΰ8ΈΑ₯ K€λ"πAw…νψΤ0₯`d—^ΰπncC–r-y΅τψΫΆ¨ήoIυ/t|Νu₯^Bͺ©ΙΌΝuƒ©0lF\Β₯Ν@6BPԝRΒΟ€mιQξΚΠυ5γΐ³ή¬p˜ζ9Μτ»™ώ5?o.”bOΙΣΈΌ©ΧϊF γ νψΨ;AQvϋΙa6₯‘m²Πw‰tΧ Ρ Œ^ΆITfΕΐd’:Φ<ƒΐ&a& ΅B ͺΫτ^Ή?wΝΤ.ΔΪ;zo> \ΐΧe Ψ€e; Ì\Ι=K2Ηφ°Ύ°f†Δt€°j b ΣβΜq\~Ζ ‘ kΠ ?¬d1ΟΨj±ιl>ž°,[P’Έκr‘Ι½{0K“&|·°ρuηΦq λ‰ϋ†ηqΚ@^2Ζ¨ορΐt|…fˆΛ†ύ)©€ %†t€aψƒ=λšέƒ ¨bR1 +­Œ Ϋ$c»^”ƒ84nψ•θ£i^έ—j‚άτλΆ4\Γ–˜±2ψ—p©>H RΕς=Γ₯ΆmΩnEƒφ(eψQlm-oυ­έΟ£e‰Ψ_‹—2ύB‡γYb5"}WλΖ*Τή7‰*fΏεtϋ΅οm=€Ϊj“^-ΏvAYςJ­g“a¦›?θ6MδK[η‰ΒΩζΔ~·Ϊ·•dΚαtŒ’ή‘ϊ4AOێ«φ–2²ayΚ‹½ΐo›…’ιφ$½TνΟΨ±ŽvŽΊfβΫ»₯άmυΉύ}ΤτΊυ·Δ>L½Υ:Žρ(ΰ”cœζ€¬‘Θ cΊδ3―σ/ς­ζRj¬NhMΊΓTμtmχP’fK<šΏUΗ«;ΊtζΡFϊ49©;3ΥUίΟ(oxσύΦΥ½Bv(Hβ2‡ZHQ΅˜ε2Στ@ͺϊ€Κ< Λ2ΠηŒ8jR½Aw ί‡ΠΣ°[(  ϊ8‘kϊ20r€!ΡΧ- O‚EθΜ65 Ο ΅ CΙY`y BέG6ά»i:(ΖRŒΖΦφŸV,ΐΥν%ΐΛNΐ(@li ‡πΐπα?†΄|Ϋ·Z£γίsBnΫ!ά`yFόΐ&nŸΈAιͺ8b¬ͺε­ΗKB ˆ/΄V-sM2 λWΑ§u}A=β1’kz c0ί‰ξ† ›’ξC2ύclhΞ­zmΌF€X¦'C‹rΗΆΗf[T)Φ0:¦MOψt<_ˆF νί©g©ό΅TKΗrˆ7."…a+Έgcνν©¬ž»X ι«κ“‡:HLI0έτο$“ι.φΉuL°c9Ύ‡Ψά2m-/“,$”›·aυ{Ψ_ `HΓδBO3@WΞz|"εΐ{C°z‰Σ2MwΙ.Α±–Ψ>Pv 52yδΚά9_³ηuusώ­ΓΝΐ–Β“.¨ώά²}C·€E‚yΒ Τ\ψρAϋ α@‚IΗp¨οƒXλ‘Λ»ƒΨzœπΊφS·>γ3J@ο"Ύ ΏΑ`°^Θ CA3‡Ή„†ŒΓr=[ψ‘幜{>5,[ΐβvϊL}˜Η.ΝΤ&U³Όk‘t?ΌZGΣΉΕ]»λ†‹0€ΒM¨Ο Sƒη4 ΤΕπqκΓ~n1PZ‰°CKΈ61‰cŽα20¨ƒ@ΊG°‰ΔhΔ„™'D§ν‰3θe½Ηΐκ YCœΐ…€j` CΫ6 ,Xh–kYLψ !&jωΜ+Γ04}J:žEEΠ­έ•‰tK۞QVΡ/ $‰l.₯λ›ΠgΤ‘Π{O "Fγ†izL<ΔCirΒ]Zœ^Γ¬ΐ$@ίή7ZmδίΥsp„όΫZΆdε΅΅<R ωhq›Ÿt=TZωaΣ€^c…€–R†Δ7©OP_φœή BRΎθ™·tθ.Ω[ 1PΗLŒ~η­ύ ,¨kqΖ€τ‘cpΛχέΐΉαΒΨ*³l‹….w€G$*I’ΝΠ5–²ξδε›Οϋbί΅yξL™ŠˆJΓ0—ϊ[ΞΣ•œ―™Κyp>a™΅ΪυO]»0Η`ΆΕ)1,a›Ά j'F]ϊ\8ž –΄lΓtυ@ϋ΄Έ'œδšOmΧ8Š·\s™u™1ά«/3nΒBrMF‘>¬-P>™α Š„ Λ΄Š8H3Σ -˜Ψ§π•JŠΐφŒevœ3cοΘ$ΟΌk:a`hΊŽ+„θQ[vΜ+Ϋ`³άυ0ΙƒzCΧikg$ΰ$βΥa&hgžοθ ΟΓ’ηΔ3mβψ‚ƒH]bxG<ΧΑπΰ.@βΰ$'pί@1al+nΑΎΎ»Ϋφ³Ζ @Sΐ…°P[,ΟBε£ξ-ΈΟa`.μί΄}/„5a2ΐ΄ΫΥtoχ!kӏf^›–¨Υλ+; αΎiZdN 61`y!΅$ xαsj›.ζβ¨ α!Η&=«½Q±Λu<JrηJΥ4―`₯ϊ’ς/² ;Έμ«lΞ—εύ7uΟ}tύ«‡Ε£"η2Χtjβi=ΑTBΐQ@|Cςd s€γ~€Ρ€ε<'4=Α ΉΟ¦U―NζΨGZŸΡ_6_šsΈϊ2Ÿκ‘ΪγΖαΒQsˆ“0Kη-ΫφΥ§Ν€ΝΑžAb8Άƒ!LŽΏ4%(¦i»ρΈΫXiH#4›pι:Ζ^uχλ©kj%Χή4.Z} ~½, tΗδ6že΅@Ϊ™hM—1Ι™ο’©Λγ>hϋDψgEΑόΈoΨ³eΫ`δϋW·βϊžο{α‘Ψ ‚8•έ‘°lΪ\šHnΚ}J`™γ)~Λ±t;W8ϋZΰκ*†DΗ€½? 6j0@7” `²ΐ`ƒΫg1b˜˜{tŽΐ€Ω’°€ύήΕ…e η›»’ljρ΄TŒ¨Ka †!1].9ΐšΜ°C+„ΎcτjΘ±= ¬eωX›ουŽ`ήΆž{Wg‘) ξqΟeƒP '2e(Lί C̜ψ‘gC‡Y„Δυ©G₯KaΙΉ†εΫ ¬νγBο=ψέ9λΫL…)„c@L €Ή@ΐ’2ΥP€aζ&60M“0 ”ρ³ŽB“£}-0η GΎλg v/WWͺ€γ;†KΡ5€°¦o»>ŽPuCŒ˜¦αyžΝsΈ,\*l,δ»\ͺs—έ‡"ςύξ=lΡΪrΧ1™d(¨@95ΡL7  M§ΓΑAx!άTˆpehYΨn΄ _‹Ϋ;¬}Pό€x€{Έ)H@©)‰MBίgV¨k ώ€€$–λš¦o„ά£ΦΙ=šg¨«F¬Η΄Ψm8h>:WOΤ!0‘%AΩq™γΪ rΗ#°ŒΠm[& [:!ͺL°›y ΰΒθγέ…–I‘ΎΞΦΉ,c‘"ΈΩΉ΅•ί’huΑ‚UL_F ΝΟ 9 ΰd‚‡Μ ƒΝ *’D+γažqε±Η˜uΧO-cšhις C )8³οΉAθK A±-j‡. !ΫP‘ν0#D‚’ŒΎΛΪΦ ‘μΫΙ8ΩΑ-a\­SΩΞ "\m ³{ ΰ3"qΫ·=τɐΑψC‡›oω.ηC&-‰„p•§Κ {°…ŒY^D<^'Ω΄ΕΝ«£Z€ ]Γ°Έά–ΠQ½AS1φ ׁi`θ(πtK:θζά#’ΐ?*ωD-ξhο1ΖΌ/·Ÿ*—_?Υ“ΦΉλ ,ΣΒ©V½kRP„ΉπL_p-?ώ‘~ˆΉώ Ά 0ΫMXέ³•Ξχ Γq‹²JP3ŸΒΥΧ΄λ3τyFˆ>$Σ°‰Α]ibώ?Ψ7ΕΘΙτΆ€ΐ{²κΤ¬>Ν€^=CΩ9Ε,<7‡σC«)Œ‚…κ8(/½ΰ¬bΣΓΝψή0}Ο£&&Μ³`[‚²οxβ&οζ‰: ž›fe‚τf°½ d@¨PϊΑμάT©ύ]ΜιΟ†/\‚:T’žDmδ‚Ϊ―πRQΒθUŠ ά7*6]2Κ΅P”3ΠΎ,i ΓδIny!ΐΧΐvlΧBΫ-Γ€²¬dM+ {©©΄6ί΅υju° φ·zΎ U/°0ά CPΟe>Βp“H£‘ @&4χlyt B΅ΥtΉlύ+΅ŠK{H›<·&Ε½6IAΑTM“―EΖ«ψϊι•ν2‹αz΅(` ˜w9\p<ΐνΔ" d™– Φ—Žι3κΒsAραŽkυφΏhΕΨW7ΎψΤτ<ΟD}Δp1A l9Π?˜kΫΒƒM‡j6¨"nθX>½y-F’;}·p]΄}©Χh.Η0i† ½"¦AXθ›6' 3]€Σ‚X\ΐ=ί°, 0}*μ9cΌ§ΤΖ’•'ΆεΛLΥ?œ­“L2ΎΐZr{vΚZ•šo£κkΫIಝΆ‡”žγšŽ(€1`3Ϋ!‡‘ΪœψΒ@ΐ\ίp€ΪrΑ:ϊo^ί-˜ršš μO،ω:χN₯…¦ ȍATX(-LX‘.ŒŠ4ιΦΛήOλα>›kUΒκ‚. XζΏͺ.–ι«―y”|ΩΉP°|χB™Θkrθ kΏΑ΄†T˜ nΈ€xX!p Ϋ₯hx!xθΣυ=‡˜>ΐ8L d3i ΟΕTœ–³Z›SXNΟ‘Α·CHn0rΧΕ 'HO o$0=ΐρ €<σΉοΠ³:¦O4±ƒ$₯<TDΧyjοίΫΥrσ€^iϋ!°VΓgV€ιfƒtΧ2lx‹Zάπ( ž€£κ³Ήα‚κ)~Χ —„} z'»ζ·OΞ\V¨`ŠFŽG”a|aΉα₯-€—»΅₯0Nˆih΄ν °Χ8,mΓ6ŒδνJxƒQpP/ ]‘Œz~θ³0B;W%$χ‰ Ο1 ΅Δυ\ ΊI₯Βp½P qΐΎΝωp¦}|gcί~6XhsΚΤΈG₯k™‘ΝΫφ(F«˜ΎM„cΓV΅(ΙpB•§ΗςΘT8hͺ–φΝA°  š§Δƒ3²lЏέΐρCΜR’JΐC©ύΜόΫ{ΣεF’\iτ>JΫόΊΧΞh,φεaΖdD‰_i;ZΊ«ϊι―#IJ$3“‹*YsΜΎΣ³΄DQTΖΈ#G˜uΎEAφ’H—¦-ξ9ΌέσzυQkJj€αV,CΧ€:«<›€H©žkν '}§rLIiW₯?6ιŸ—zπgύ©±yΪ}ο¨?―%uX:]ίά―6§D^ό”τ8~Βn₯ώv£ς{_κ‘5Ϋ1_›ˆΐ)hΉe‹a ΩuψΗ€T―%ΉH › ΄dhΗ€#Zz‚[IΗ[ϋug°— 6…\šτN=w+uάR±hΙF›%‡­™š¬δMU‚₯…ΧW`Λx#{Χ@ £Ζ₯―uΆ9:H·ψ ½.Ι(V‘&Iΐ‡ωΤΖTΣ8ρΠΧ/YΚK"Vα- hΠ‰A ½2€ΫαφΊπύ0Ψl– iG0'{©%5Ρiι˜ΘALm„uυ2h«Ρ0A:%ŠB&FΣκL’ζ‘πΗτρέ€μΤόμHιόΣXΑxρ«‰XjKDΙy*ΰ`g©–βμkΠZΚΖμyό‡ ςg€Ee ‘εzf8ϋ³Xy]]>ps…Ύ‰π+Ύ t &¬WτM}MΊR„”«ά+αΨ€Σ.:¨fPΜkέ->ξρΥΛς‘^xQkRSΊHoZ¬&N΄%°fI3*Ρ–ͺΔά Δ:ζήΨΓΤ› ημ•;…‡[ή_λήΐkΏ|”°ƒiV₯Πιb«‘κz*½ˆϊCθQz%J3³ζ¦ ΄ΧiΘΪ9ώb€τWz’ήϋ`-.~c‰Εό„m„ΛO’Ν``O1rTEƒ[DOηD§Ž‰σ†IγLk“Σ"™'»4œΙ:Cόΰ³EΕΘ΅.ή‰$Y/}F—,NΣφ'R20oβlc­ ε›rΞε,ιΕΕ5i(Σ-3α¨Οξ[1χντœ3xΡύ9Δυ‹ ŠΤ¬sΆά3J΅žl*0\SŠ₯&eΘ €_Δ±08h—Ύ‡‘ͺaΠμو΅<ϋΨ$.΅Ž(¨8«*E“4ˆlŸs-ΉΦlW’½”nHM•² ΄±w˜ΠΤ@&gΤ=v»pš”Rϋ:°ˆΗ?'“hެ €Ό\½–%[E\gœ”§²uEϊ ƒ& XpiSsޱυDε£ΐ(j½±*n§ΟϋN«—“I<ί^ΏΡυ³ΔE:††₯ Xπ―bŠΞήbG„ήsIAIv'w…Rϊ’|—P™ :&γΏLœ”ξΉ–ƒ¬$wMQ°Μ΄:τ¨ΤR (ι’ZU/ ͺpWDxSΗ[€q]b“KT-p8’ +—‘›Μωb7MψΏί±ηΧ@ΰσ‘šr™Ύ”ΛΧ—§Ώ―ί>Ϋ€/υJ³B’€)I$Ž?Ί’έσN±‰XR hό λΪ-θ€ς}c"ΐ@S«\žZgαΫ\ŒZ€ Θ~Π]ƒD¦Ž ‘&b±ζNc’¦ηηC”Ώ=πγΫV7tvœ ‰GψxqιfS]ˆ2Bqα.Jύš `2N.j΅Ωƒνχ”²ZΒΖζ Ξ\IΝe³φχTPάΙc_9&ή°"RΪ‰”€UE²nΩ ''έCΡU‡ΰΊhγ9#χBAη"½—)Ξυ?Ί[όΡρΰt>U–oΑύΘ)ρ)&i€œ@ΕHœ΅a1RψsΆ ΎOΆsΧ8C#³Γςm»8CΓ‘βn8ΤPz"¬#&ΥTΧΐM²ωKŠ`ςFΐΉgΰΐKm 3%<§²ξήξo†§˜ξΘ9υ‘§\Έ|¦η?GhόςEϋ₯ƒΗ§’₯)‡NrT P©a]Uβž‹Δ}ρLX^U’ͺl”Τ=™Ϊ™B=κθΆ—ψ"³όώΌΡ/܏„κQWΚΕkaΊ υfύd’+U|.$Αލ;IgEDΫ§8ΉS‚ω.v¨šΤωτξzPyΊp€Χm°M’ά΅΅¦ΖΚŠjήΦŸώtׁεzd’,Ίτ…LAΚ)fΞϋŠΖ%K‹Σ›:X‘ΤεKΏhίIεttB ΑGχ:©_ &Ή†˜­—ΐTrŽOf­m}m]Ρκ¨jχΏΟž…εƒqJΤ¨"φ‘’<”κ+– Lڐ3u*EŸιΒ!›Χ•T₯J΅+]JΎώ,leΖ―έ‰"’Ÿ3ΌR1ΑΫ±5€B%eώΰ€)+ΥMWδΥTίLU V=·—ΧδkΤϊbι°Q…‹ν~5¨Zπƒ’šcΈΧρ”’2RLη’-Α7ƒ΅ž€τ°αpΞν„ΰacΣm`R>wάμs§Ξq―ΉΫΫέ ΊίvD‰ŸHY7/έΫώ »ΓΆ’²Œ‘$KΠ7 0©ζνΩb²Ή€šΒJ$κ€’Φ 0:+x8QŸwέφ9–ώPž·έΎιVΐ玒ππڏ§Χ»ΥΛΣP³‘t«Ώ™€ήΏo:\~ τя{XΕ+€…9XWd(m u!G+HͺLM0‘@θΒΨ’%E4˜βOΚΓ}RΦž€ΌωρΉP»b±Ϋξ;}wώLφ‰ΎŽΫFŽ“bάόγΗίζΔ ΗQš₯λ-|T‚Mά<Ο‘ΟN™HVϊ:t+:ŠmψΡ€α&lᔣKshώ£«ΖΥ•@;½!U[OΞ:ψʎ«$ψ–NΆ(•œπ3‘πIΐzv­²..MCϊMύόκΜ oωDΏSO>xέYkΖ`²pέΥI")ΦΝψψmΐ½pΚtζ.ΘTΓ•ΧE‡§—G—’._Αχ{&ζT`2€‘ξ%WΡUZ>@³ψ†-Ω•‡³Τfς\ϊΗχTFή:,.`Ί-α—΅.`˜*9Σ{"§04ύ δPΔE燬”hαμuόEžΛϊμν8 ΰ.}y]Ίρ@ΘX…{”Aθ}³Ύ "©†LΑ¨ ²c(΄hšƒio`сD”·|‘?ΕΉΌz. N ›$Ϋ‡€6ΓIσzV°x`ϋΐXk/ΉΪ.‡^ΐπ’ΛΨ’]L¨^mΘ(OOm7œcω›’ΓNς1ΟενξS5ͺΙIμ6,Ώ?vΩ±χ±‡”cρ2>m½α& VD#ΰNT¨™Δ)•;ŠήEφQuYΥjccι­3$ρ m²6οΆeଋαwqιe!qωιΛs»iχ+©A’,‰Wι(½ouΊθ$ΉψoR‘ ¦ΐϋ†²‚σͺΰ‘lΊ'˜άή©Ί…οκΜeh#<ΣcGπŸ{y|Cζαv— CήΎgϋΒσ{}}―{/­ ΞNΊέΗ=E:«Ώ=}—Α=·S­­ΎoεvUo΄ŸO-Ι!³ΊΚ*hΧaβ†Ψ Η¦l†ΉŽ]28a· T` …ͺfaΣφKύίΩ“³~΄΄α#±{n_Ψχyw 7[ϋϊ3 λI+·J₯ZΆb5CΉ3n*zΖ^dόΟVε©εR†‚ŸήpξLΞΩ“σ1!«r•©πΐΙΨ0πΙΰ¬Β³Df€fηBΐ /ΡJg•£κ‘γtίεαΪW™Sω@Γ•pιvBVgόϊ“tW«2*XΎI‰@”o\R ‹γ…o’Ύn°΅˜A°” ΄žfšƒ_bί.3fxρϋκρΝΫΖ†ύ…_–ΟX5>=³czυYYr‘ͺπ’QNέα5€”›2Mτ0aΏ –S©¦¦[ΚΔΙ7L1θzΥJλ/Οκ\\θpήφz€π“kuυIj›%|Tξ« ΕρuA‘W)₯*:a₯‹E“.,ΆaΧφB©wœZψθfΫgΎΞ9αέΫΩSϋιFΧ[£ζς°σΒ‡‘0ly=2Ο»b?H΄ΌzΰM-dl―ΝlO₯Ίι&ΒΝ:j`±`΄¦ŠΫPY *ŸΊσπ€―7Η‡d6ΎφO²BPE&CSvšC΅*8ίEθΈϊΰ¬4pNVtΑV‹Μ«d‚¦*xΝΟEJ>tΗσ7ο pΙΒ8-ΖΖQΧΨΒΥ•ξΌ³)i“Μu°.93[o,’@ΓΕyڞμG2βˆειτ_Χ(΅°4ΠU* p’>ǚαtŒ6r ύN|Y±&'ΡΜ /*hUυΚΰΰΐ*ώ\­φΧΧ»―΅ΟΟΤΓυλ²;|@1l­R( σԝվ’μ€]’jΛπ’g‰}μΜ\#³§,·Νoι]αϊΡ(°Μξ %56H»‚€­3k©ή—”,,Ά5ΙNl³JDΊΌ€°n₯av \_:cηΧκcρGbGyρ’< ,‹\ΏRc·d`g`›,,Β~Φ&Oμyγ4˜7Gφb€.£ςαάν|qŸωΙω{43rΞ—Ξν φa.―5U5–ΑΣ”₯ZJg/©•Mš\D¬Ό6ΞxμvŸ[¦Δ ΫζΌ‰Ήtμί/Kό˜υωx¦‘ύΝΝα5Ο5²g‘/“–‡p`w©gŠ΅’j·₯'μK£6_  R9U ^˜jή\€ΏΡS;WIξX£Ν“‰3χOνϋ­άΐŒ.kά[σ“`Ε{(Β–μ¦a²ͺwJ΅šc*&)pΤ€›’Δv †ι»ΪsZ‡έ4ς·x‘›ΉV ΡΖΤπ«¬KΩDψμ\…sZ•b6 ψΩϊK°ΡΝD­Ξ‘\›ίλσ$΄«ηήKεN&UαWb(ΎηK=_…i)Ύ…Ζ©EVYΈΑZ½€κlYq Lf¦₯ϊ'˜ŠŽΈ—±OΙu…+!Œ„Έ7i«N¬{”FγQ…ξ,g±ˆ…š‡;’΄9lƒ‚Ρ 4eǝN§¬ΟΖ ΧίΎπσΛΉ₯χ?”I¬±Έ>]7GΰdηD3Ακ¬=Ά&HλΣΨ$Ύ|€rθZΈ‘ΛΖS‹ΪQi9_ξef†,™sΧ.hk 9JTή{ ‰E:vχT`ŸTξ“\WεΩu"— ΆVμpd0C:Χ2W|²Ž^Mu[(A?‰}Π0“•¨”˜€=8˜kΣJ NA C2[I³CxΎ_΅H—ΎάΆ,2HE# €ΔτDIQi₯ͺιξJΠ*ǞE`Ύλd sβ₯ά¬μΣf[Žnx—·’,Αr ρ†'₯Cg,ΓΧf“!‚γθ^œ%v…5ΙEi*ΗσGŸοϊφί·βΎργεJλ§jΟ¦‹χHE»dχ%pΨlΟ©©‚c’ΊΦJ—(MίY ˜‘ΘHΛ5Ζ$uΕ3σ"=QWeτnnήέΛΣγΣ~šήA»Ω¬€Ίΐ3“Y%θ±φ,οχχττΧγMKΈΣ±ψKm=6)¬φε˜[αςϊώΒ©ώω %›1υXœ-HΒYι{Ξ^eW@ςŒ‘+%JΓπΜέ6₯£¦œzπ IλHΗK=ψ¨ΙLή=σKΏ'y|»‘‰5­#ΜCίaϊ€Σϟ܎ΝΥ°‚ϋFlyro₯ΒζΚJΧI’’g€γa5ΕfΟ8ί“+,@Ϊz2ʐ‰μbM‘\U v;ΡΧ(bς5GE°tl ˆo„•†qJDέtΣΊyRζ-ν€ άLB―­…/€‡}6R?ŒuωΕ;ηT• ¬Εσ€’mδμ@ϊƒκτ―α«"#ΪάMW2tͺbP£)Ν³γ{ωΖWGZΑ$ ΨcΠvνΑxjsžΉτ\΄°Lg° \Ša\£k€υωŒψ}ΧτI'›·—²:–‘±χKΧΆQnΩKΩ)ψT°ΥU“YDŒPη)ΐDŸƒ¬+Θ֐-dωΝ«Λ³ˆΰ|_Mδ­»ΕΥΌ}v^ ωδ G0Ζ±L,β­-Δ"±‘l˜£ξ »E%-MΝ[›“Ϋ‘υGΗΈΥ?„'‹§"±>`MΣ=4p|ψ,,¬b§΄†OλΩϋ`qΔ3^ξΘΕ€ŠϊR)ΊΕ™3Lχ&τ{κΠFڝ5‹Gφ₯Λw ¨½‰°£odMΆn‘ΔΘ+’ΕY%«3¦΅p 4>i%ΐˆ„γύ>ΐjείΆ5§jg‡_9Œσ.^V•»τβΑ**"Νwϊ¨h5Χ–;.wλ’³²φNΰZ lύ₯ͺΰ‡ΥΛκΜ AΘo#_ΈΩt ηv ρnΩΒ‡ΤΧλŠΒσ?Φαœ\žœΉ“°“†Ά<ۍϋΉi?T‡άnΗ±SΐtΗχχ7όΪΚ3Ÿ ή¦•ΌclK_e0|9φx0:p³:(‹ξM.ΩD‚“TΞH‘€+ΆΫΨG’ΪuΟΒ|ό\s½Η―έ†ΤvœΏ,„ΪΖ X‰Δ–VE‰±‘‘ϋι[gD<εΜΕ––­‡t_+hzΤ=Ύρ·‰kM·ό₯£ψͺΘ yp“Βrλ—]GΙΥπ”²Γ­·@Ύ³Ββ0ρΫΡΧ“΅eηΰ”χŒPυβΊ9 ΘψXΕξΓ)§A+_D2Ί4›―ΡΒΕΒ²Ι0QπΘ:`™ή)Μ€ςDžUmΧτΛίͺ)οrΖAkŒ ΐ[Ύ3gιΙΰBφ‘χ.mn,c…ύυ1DIκΠ=b§E@vTLNηkƒ$[@F•SN¦xΧbv"΅¨_›ΫεcX~³γŠT,€'Υαs²Jp9Ϋ―gkγSωΞj@sj.z“Έ°0aM]pΣμRnΝ₯/aΩ,/)κ€ZX2hdγD₯;ˆ›δή†˜$% ˆΖ¨Š¦@&βΞf/iœš*‰Ÿ6²η ςυυ~|Wj—; ΕF*{%½ˆΩ8†Η0¬jtΚI·ω ιΗ œ$ΝXde”N‘$ωx&Yu/λbΤΧpΏ ά3ΨΟFΫΟ<>UYΡkk Š|‹u R?œ­ΣβJk‘`E΄UΓe€ΙWpU#Ρ9…χI·rψ]#Mœ%qt―‡ͺZ2Jώ₯†;°Π βxΔZ½dnη4؈±E΄Δ#ωβuΚ₯δΨ|/Η»Ο§–œX«qβLώWX^ 4fͺΐΡIΞ”ςFε‘, Θέ’Vn °Gšτ²”Šo/šNβψΓ$šέEΌGΞI3¨W8ͺ ~Y»$zˆ|Φt›m²/t₯Γ ΩV F8 Θ™Ξ-ΌEλ κ>‹ΒNŸ›Ο»Χ‘μβς£s₯)“qά ŒXΐ ψπΩ₯½Kι¬g„Rξϊ-Vt}q>?Έk²ΥΏ4<ŠΔω±MY†g²ΎαeΨF‹\¦σ.Š^–’°rjδ$Lς° `Χ|?μicv ²‰rK™B7d|R Ά}ž0Άn ’ΨTvHΗnV$=V½ §Wχ€ υζWΎΦ f8ΥΜ؞!N0γk€δγδ†>θEj'Νί€YgΚΨψΫ»OŸέΧΥ³dΒ+·uΚ<ΔμK‡E–,Ηα‘›ƒk–2©―ib°\lubΥD\/Ζͺm‡2Eδ`Ω’™λcπΩάσΪI©&XΤΤ΄Χ@ΆΰρΩΚϊh«]Π"ξ%Oπ΄‘cσ'Ρ].X£–‰gIΗg°qΤCdιͺVΝΖ;ιiΠρΨΦ Ί€Ό`ρ…Υ’h†/ΐ5΅J0*Κ΄ά²μ‘«ΖτžξŸWο― ίV<ψ‘Yg―<@ŽržlŽηBtΤjΒ†ιŒΈ$G"e.šŒ-Ƙ%}`:ώMε­τ—MΜδ#v²›V>w”žސ4[;8DK/ ±QΪ'$Εƒ­ Ύ-κzΉ›3ψASVZNWv ΈλEΒΕaΰͺxMž««~a «½Ώm4^.ŠMh“ε.’O½‚nΙr#-_’/Άˆ£H{Uΰ:ΉR­nσγx{ϋy[^_ωEtδGΕΟΛ3x ,φr¬+ŽΌ/ „Η%—’B#Ž’6Ή©X“8©‡χ-RŽqFfϊuu+}yΨ΄Z"œ[·-~Α/lzρν†οηχθzf>―žR›M€Ή©Ωc₯a1S͜؁“dΓμ€ρ₯ŏMΟYbΑ3Φ+ΨΦi,~DΘsvΰ"xΧn$‘)°τνπYΊ'ΨP +kl˜XιΞŒΟExvίΰ+^(d¦¨I]βtcί£e?£Μςk'B’Θ!eΥ{N Na ¬Y8’ΤΊ$πjΤ­(P―μ΅05τ5Ν«™ξ‡£Έ)ooη%ɟ-s?ύ'=[EWΙ#‡Ρ‘Ϋ–“t©@ΩΊ @όj0M1ϋ(bχΞ«xVW­—rϊ³u8'—ΟŐ‘;"©KΛQνR€)7΄bγ}aίl#Ή‘<Εήu©M4γEA§htΏφnŒύ?NŽcΣ»ύπ„/žήRΒKLHˆj‘D,ΈΝ jθH'+VZΈ›Υ$Κt!UR’2NČΥ–ή“š\ƒ/F)G΅Β“ŠQΑx)Ψ¬ΪD|Ήc4ΐŠ gS}–B¦*¦Ά“ϋ±’γϋξvζ™—λ–έσŸΦχoΟϋΠM ΐΡΛΔΉ?ωϊp}ρFζ΄;›Œ€bΑΐJΕh’‹Ϊ”j 4OκΙWφ―š2ͺΖΔ!_œα±_Ό:ͺ#1‹k“Ω ΙfŽtŠ>K+LηΨU}”ŒηKρXX‚—^ΖC€F­Ή°ε^φNϊNbλI‘Λ£±<ο] ˾γ$=Βg°° ς Γή[ γΠΩ^’…-Œ>Ĝkˆ 6ˆ`.OOΔeƒό)GψκšWœζ%³J‘hχΐTƒ“šββ3]eUEΨ1ψκCŠ{“f{6КΊΣνΐ†.ŸΔZδΊ+;MΙτ‚3ιA»΄¨ †¨I™( ,3ΧTρ£βlt]Z½Β£]8„k(,Ψ$ωM•ΗΠαœr5t–Τs€A-<ΕλU°ΏΣΐxH* ζ‡πΘ7νΆέΏΏ~ηŸW-)!A{ŠZ.}Z"Jƒψ!–ΓΦU-ŠtΑΒτ2[η€PmΒ8Ίσ³γxzWΕΕUoΌδ΄EnuΐˆlNƒ%šͺLZ77υI$ wI³?)ΊΫx<œ9ν/₯ρψ†Κ-―EΒΝpς-zκdu C?ͺ^2ΏΙ΄`η€CBU­ƒUPn 9#Su«ςpΨΝ`ZβaΫρuΔc:/χ―7―Οεq'TžoΦ•lΫŠρΛ·kΊ=υS‰2α½Ό·!qgκ-ΓٟόΙsyyε©Όςλλκiς)7O?»FIYqqKJγ‘ΙΑΎΈZaόZ’¬§\ άΏsΎNŒ~°Ϊj€Ξ”{³>Tο©ι»ηέ²E-²…ϋ™,C΄;© ΚΝρjwm§ψqxεΉ}»hΦβF ΖΛGΜ,²σNξ)s&ΐζZkE:U ’|iR–€ώŠpœ¦•§γ•Άϋdw‡Ύ™ °;iΓ’Ωωΐ‘½_Ό“—k’#—Ήεh₯saνΡψΪ-Œ’§‚(νDιQύ ³ 7™t–&3Σ&σ3Œ;½W.ψςoΰΰh½tΆjYΊΗw£½•šU΄‹5Gή‹† Τ>4'έ‹«=JΗŠ.xψ—95πqJάςάYU8@“Q$x¨X©‘+$K"‘€ƒδ)κξCΡοJ=Iφs€σΉδ^‘PΞy`KRižb`Crφ₯d(bοF§9Q3ήƒ±SΕ€Ge3@NԜ<Βwνκι{’³ΫίeΓ-ύ1Iz!ΛvxzιfΟ[)βΜr£Bΐθ!SΪN‡/;―wΧΧ„΅ΐΡ,:¨‘8:Μyǁ4„–rεQ0δUi9Dθ*eΊk$Vzr”§§8±kkϋθP†ΐV X$ŒΑφH$’&­TU€D₯bάX^“[tͺsbμq—tX`1.έ­ϊΫΥ7n„sDoI9‰4’‡1*IΔ(ΦFΞxΈσΧΜxΕΈs΅RΥͺNΧT}τ†&ώοχ ϋΪ6Χ܌ςDψΞ{‹¨—?Φ€‰YT„fJ_@‹Αͺ•i ~Ζ‰g­ΩΧLN°ΝͺEL6ψΜtLMΑηkxeτΪΆφV(πHαΉ9ΫΛΨΩϊεSl“νpΘ6c&€ ΅4RS.b#ΐν²SMξ<Θ*°m²½Ÿ’ςGGωώ:–‡]ήπy+m0’$³5·Lά Ly†‡)λΗΞa;ΙΩ’(Ό7!&`± ͺv&[̎]Δ#χ„_ώFWΕ’‚wΚ’HzώHΐO„8%ƒΑ4MI±–ΰϊr*xςΕ‚†)‘»'9Ξεu΅Q:lσϊσρ­ό81ψOYέΡ΅Λβ «(Ϊ^“dzΥ caD³ΤˆŒ;³εφIήP½ ΥΰΑ4€μ{όˆ6πyCέΌkΔ3όβ :Glτ”€}ƒ73χΪ„έ W[ρZcί«–“Υ%ŠN«ˆIX©LKΉώcnOo|#šSSm$7iy'u¦mρ±_έi¨~νζ&Ψρ€±υΌ?€«,0’&zžL ΧΞUBΉ8FE€ο-•—€Ξψ₯Φ—ΓΆv›ΖH'ΊΤ——oOŸ_}φ{Ύ’ς% ωΗΠUk“gtΏz~ώy+­V^άU»+|?•…4h(Nάδ$ΰ‹§zΨGρI²³ά}vψΨ~χ©M°γΑ‡qU"3°³ΰύ˜u+`ŽI<ΎΤ‰Kγ·8¬Ψi•˜ιD29ς#C—XΟΩ―Ω~¬»έ‰w_ίΩΑ}jGkvΖÏρρœ‚ύ‡σ\[8SŸ=k_>·ΧφδΑ°4Χφ„²{°Ή$}·)ΡkθQc— ϊ$%EΧ€A’½P˜ι^BpVZυ²k)Μ7ν:>81₯W/Μ`W}¬ΖWgqΘ³Τ'©Ρν&Αα—.I½‘Až}NΤΈAK8>-U8ί9™±+%ΰεΧ•Œ”ZΟ亝q­{ZΖtβBωϊΣαJρl]%E`ΞBe£‹’Α+=!ΑdR*!*ξ5Χb«δ q0,ς <Σk|ο:ώς+ουcNόΰžπΛΤ†ά†Χι»π—UΉ_ύΝGnΓ„ @Ξ›ΤΙ_°PΫ+ώλ―—*5‡Τ՝\&Tι6έbn%)Ÿ7Α§(±‡˜’Ž Ϋ6΄lŒθff΄!ο©T†ΩΊt‚—όϊ³ΤK‘jŸΐ8λ֐deYeƒ‹&ϊrθQεj)GLf(Ψ|χλ[užfR/`ΫM2₯Ά«K3Šκ₯C+7Ϊό?ΞϋŸ|\Λο++k„q0γC₯ρŸ«Ώ/:]—’ζλowΘηχŸ mο€FΧϋjpΏδq·/OΗΤβcΏΑŒ'³g~ƒ[Χ―Eη&NŠΨXΆ˜ά¬o–“¨w€X¨Eœv8³wΨw±Ξ„ΜŸ@9ψζυ¨’7ˆ²|=™H`)ζ½Ώ^ÈJ 9ώρέφ7vp›ώ׊ήξΎ²€‹Œο7¬iŽ$ ¦„υ 5USu.ΒV₯©ccώQτMt±©†¦}£ΤΙ›j]ύ2TΈ,gλ`vΦΡ‚ί0;˜˜Π΅( ͺμ\/©Ϋ ξΖΦδr‰ σΖ ΰήEΡ/ρsš₯¬©.γ¬ρ|X²ίΰZVΝkνmk>™ΤδκΗ 2‘ _š«¨hm@;e²π½ΛΊ·σ΄ωΓWM#›±[•Ξ™ LP­©U‰Mζ›α2\Z9dM’ΌGΊzB6§]ΰ—ΜΗy»x τ?IΕ›¬€+kV’ͺM¦Q ιοΧ#6φƒ§Ω9ŽΡi Ό@䕃όυΒ—YΓ|ύAFU]e¬ΉJ)Ι'>ζ€η0£6R)-{Εό[$θ‡–+`~Bžaν~Υ ΌώV^Ύm4K.…­›'ω –Η.ΕξΕ’ψβeɐΕY4*J#ί₯l΄Χθΐ\™Ξ°G>…™¦Ψ§Λ$ρο₯8{RΦIΗΏΑ― %o H§&UE?•A’W.—u ΅d‹©’‘μt΅Κc–b3wςΗxιοΟίή™KˆξιΤξY2ϋi˜Ÿ^δ •·ΥΣωΘβσψύ4 SΫgiK,•NuΘu5ΩeT*Ύ`{΄¦δΊeαΓNzqyU=“Y°ΗΈ.Ηlgώϊƒ§Z”Z‰.wι‘Mpΰΰ Ί΅Ψ΅πζ½ob³ Ο8πŒβC© 3¦MN—UΓν]Œ-fΕΏ΄λ·Ψυw—ε\Ζ(Ξ~%ΨœαD’-8ŽΕWγ$ƒΛαDH²MΠ„‹ΒΑΠRšlE &vΟΑœ)*<τƝΪ/Ϋ Ζ‚±½sρ΅==3έΌέΏξi―εMΤί›“œσΌΕάμƒίΰUg–’]X:Έ."Ι"€Λ/±— /ΗFe°K)Λ‹ͺχ”Α>-V5υ^T$ώ­1Ψ_Žœw€>.+Fδ‹7gζ,+ -ν@Hι^ĝΈ†©NΕiΖjTSRΓα-tπά ίΤ›uζͺ=Ywbm –@ SŠdͺ|™»DϊΑΩ ˆQ\r +\pΥΞΈ .Ήa΄τias”ώ>”Υγ™Εψλύ²QΧ»}}έ±4·$W»›ψκϋŸ7‡uπΖΏ{―—ζ܍[Ž΄Ά–Ξ0₯HgΊ§ΪŝλΖ‡Z'ΐV|‰¦&+ΖY[η+&;Ϋθ€ΊufβO%َ㰧gβf’°ε Σ‘΄‘–r «—ΊOβί₯a{qαk ڝBμ‘5°Σd•\vΰdRM3€# ·λΝ‡ jΧ8  ΈR‹"Hœ%Dt”ώ³ͺ0%鞀B+"ε †RfΫ<ωΖ³’sσΝ½φ”σ }ώŸωiέ³ΞήέtΡ9σÏʉLζf€«γ-‚κΟ7~z‘mλΧΩk‘OώUύϋΓœΝ“ψ©βΥ™Œ£ΓΫ— ύ?ΘΎ:'[žϋύS9·‰Δ9“pMδœrΏpΫ>Ίd?s0'`Τ!z:δσ#5…~ιvzˆ[ά?ύ…}όvΡl€ϋ}892‡4πφnυrdšFэŽΆKΝΎ:)Ο’x0ΠTJΰΩΣς‘Xvρ,8ςa­E3uΙδŒΣNξ—½‰Έζߎ$Χ.ϋsΏΊΗύ΅“:·GΗ^Ÿπ8ΔΦζΖΏν¦Άε‘μκ?w τ#¦‰,χ_›€q2Α‰cΌzμ{s8šΣΡ=ο½π2<œΛ__κ‰ΏyA π{χάήφσ£{οΧ¬Ι†ΪMέ,°‹Ώn=ψΗsy€‹vω‘yΎΏν'~ϋφyKϊπ‹_qΛm‹Ίf2hFyg:½ύ₯˜‘¦XΓ8η‰σ4LΗΞiΩΤi;Q ;/?₯œμK:}jΣ―y/΅iFτΟqbμͺ=sύ]ι&›σρmΟ6Θύξπϊσ‘>έίΗfS=qΰ§σ·Nμ?u±Gόφϊή~Λ’^ζϊΖKw¦ο›]Ύ%άί™ r,oσH»Ύ $―™ yY‚β,Τ9y'~k’γ6 zζΚlΖ§ξΣΉhdΪη}Yu!(ί?sψnό€«Gψ…^ΪΚY=Ύ]h5G@θώhϊvυπΌ;ΔΧς'ίξ—. X>oλ"w7Δζλ›ΧχϊΪ^Vu»6/Ώ½0_°qvΧbbχœϊΝ³Α¬GvΜΔ΅ο…±“«&₯n‘φ/BuDβ7FαYΣ<A\΄ΩΏΒ¦R}Ώ <Ÿ“O₯Ϟ>“Iͺ§MΜΪyC{’»y,3?βρΚ_θΝAςvΜχΒ”yίMΜ=υΡ‡Ϋδg>έA½ζE ta8}9 1/<©gγ8‘ωLLxΖΞ;ρ‡;Ώ,d.„χ‹Ου"'κϋœ7)ϋπο~· §ΌΩΎγϊˆzξΌ΄H£ΞƒΘr`τhΨμͺώˆ)„OFL―‰&Π«„άv_z|zxzyΎΫίPγpέΑœOΓΦg…~ŽXζΑΫ0OOχςo \’έ‚γΫuƒ·IΌ|N β\l7A˜―„Ζή‘Φyoێ η—¬wΠ™·Q]”eWΉk¨ ƒ“μj*¬|­8Ζεφώ²¦θδŒK2.ƒ)σ“ύKΐλψs_<3t{ΗχΟΫό„Ά8ϊg&o=ζΞΗ’ΕŸVφBwwE_υΎε¬ΖjLσΟ5”›ϋJHάΏΩΜΝd4wςVsΈEcύ#f£ϊΗZ˜ε–‡/Ήω% zρeκh\ιjηΣ—ήnžη+Pτά\d4Ϋ‚ό’»ž§ϊκd\œ7ί“ηιπ:μLvωVώŸ@–φ‘φ™ύΑžπ6|ΨνΫΠΌώσDžtxƒόkTεΒiΎτŠιΤίe@Ξ?ή΅Χέ‘γΛ‹²w†ΤY‘€―ξ†KVτgΔ~/Κ όHΏN¦Yύb«‰…»Αˆ―Oξ‰Sϋ…@ΜΧ²φΆA”_Ψ& ‘—/¦ω8ΛԝγΡyΨ 7S©Xg„cμv‡xΡόmώΨ™ΰm2Οazβη+‘_Λ—]Θƒn#˜_χ‘'“ΰη’ίΏ5σΔRόŠ όΪΔο'Fœi"gtΐ3g^NΊΝcst ˆ|ζ,M*)‰ϋξfGŽΩΉ₯.SσσΈDΐ’φδTŽδ―η€|ΈL¨ζΞ2ΔΕσ#‹r~νΠ©„³+ΧÏξqΞτUΫήΑGσΟ=Έη»κΕΡλ„ ΐ•ŠΔ.Ll:σρ?δ§ϊa}ω-l­ΡxΉΈάKm.%κ!“bχ%ηζΉtOZI·η‘ο†₯^š7.†ξc>>ŽΜϋŸΗνΏž3δΩEyΏσΆβ¬kΓQνέA\δŒ[Ε μv“5ΎrX6k0€XΎuu6*ΕζusA)|iqͺ>rEߘL―½ZmXwGή(-τ":Μ3­ DB0‘>ΪgυΘH—ohV{Qέ‹^ Γ!©Ιυ ͺmΥΎ&[’α€s©ΖGιC―|V”½(¬ΩŽTδμρSϋJΚΰa~ΝΤ½ΛΓκqΥW›Νό~OO=ή΄‡ςςύuKˆ‰Λƒδ7<ލ°ΉΖAη‰*μηρKωbϊώρ©Ϋ}Άσ/.lB³ω3owό0ύ'ŽVδ»I§TCϊκΗΥ›IwΣΌͺΡΥBˆkκΐ―—dmμœͺΩ›zbWƒγΪ)Eέ‚Κ!š¨ŸκΉ΅νρqωBŒGf§ͺ²ς―%zu&ι(Πaƒ ΅J›[|Γ]WJ^ΊΰYΜQŽέšrΕΡ?Όέ΄§ΗΎϊv+ΙCkΗ5ΕD.Λ6ϊ|ŽŸg<ΐΆQΦA«΅ΩxI±ΛηtˆL{zίxδQΧ΅΄Ρb9hZυQ·J«—‰žBaσ[»›uΣ‘©L3BGhŒγL[²ι΅9n,Όƒηϋ(Γž|£x»[½Ψη =ΨGΒή·!οφ\Œ«u6―ά6Μώ·§—ŸΠlšςΆβ½–n¬t΅YeŠ>α ωs7–\΄@-;kSH"τk œq‰’ϋi›ρ­SΙE₯4gpΎ_ύΡ£&«49-)«K%ΒΣχΘ_­C*ΩGPΠΩλ’½Ž₯c=¬DOaŽ”Ώβί7ƒ§<@XZ½ίφ¦aΚJ)Ήv„aΔΓ’η_aοe(€uU‰ζΉ£XΎ ΙΖ”•ςΚiΜΈνe7³Γ^·­GJσΚ‘]ωZΰš±ŽŒ9+ς.vΞΈ9S‰Φ’n9˜ΦϋΜ? άRmqΊΜ‘u8•ΈœΗZV8„’MV8%πPͺλ€όVμ½C!aψ΅ΓQπZΌϊ¨ΕNžŠs©Νi#ψφ^^θκ"nd€¬U d₯1h=λβ‹ΘhkmZ1 σά{«ΦH[R₯š"Χ€"b¨θA5ς³ZΟτx<θ|lˆΫw]€Ue€„bjυΙ([t¬ς‘:χKΙDŸ¨6Zh‘`ƒ26₯­€υΎT­stθΫ~Ρ#έξ₯έI3-b»’†Ϋ„γ,ΙΰόGν³“h-ΌLsρ°ΐ-ι«Δ€JƒΖ˜ώ53σAjGτkih[ΨT€ h WΰaL“†‡Θ@1±HpÁ8η΄κp&΅h@ ±±Τ‹5ϋΣ™$«·§Ν₯θδ?Ού ?«"—ζn†ΰύb(Π±*―αH4ΜUΩ<­ιΰo…±ΣUgS9₯]©χΊΕ°θΆ–ŒŠQƒα₯·s”Α 8gΥΑ°»–¦]π:Ε[ 2sΚfζ ΪτvχOνϋM}ο}Žμ&Žτ fzˆmΪQ—ο|σΊzXg›==—~ηβϊώmθ:o/›œε[–kρš`ξ)΄\Α¬"°ˆ΅! Α Šΐ±Ϊb½ΰ|Ž€’}Φ!FuΞδl―&zy>Ώ―θ¦Jp{oφΆΏq0_φΨeϐŽsνι2ΩZΜ‰\Lθ ΏήϋJ…R­Ξ…Ϊ%€Ββ¨%Λ ™bLΰωSΣ£¦ 6‡n^οKGS–ŽxεuΖF…zŽ.«žTqΎ΄ήrfίΪ8όΑΠΦ ƒΛšˆŸ³vlΟ¦Μ“οοoψ΅•ηqΓ‹₯!ƒσUž]§^²6!΄“Š.2˜ž±% –­½€CL©9ΓΑYE0>:Ή>‡^οξδ@rή-΅Iπ Ε‘Iؚθœ-ΝhΧ€ξ:|>μAΆ 8η«§²©ΕΩ¦“―@-εώζξιιϋΝφ)Ζb7ω-`‹jA"&žK+\Π |@ΞAy•f"₯N\ΎͺQ€ιΥ¨R;Οm΄Υ³ΘβθΕnΤ₯htpΖ6ŽpΛΉRΆ.( ±ͺ–X_…/οΩηάjλ¦œ=λIπύ³ υ7ΜA»{όώ:ΊsKGο=OB΄m₯Α©fι=ΦΊ·0 b#*|’€8uUΦJ{|KFΕΉΨ¦[ΙOόψύαΘzνž[~j­+|ƒ4gp‡.}““w₯«@όZΆB+°’ 6#NΩ ά‰Ή™»€ψΈί?GΛΣqι•VAΏ­/ΞMγyU+ΰΏ5¬δ―΅Β8tͺΞIΫ€Q9–*Ο=ΏTďά(ΏD kαKjSμT1­Ωvβͺ+7ΉsIΠ³ItXI3Hίb4Λ_Νof΄uw™Αw/‰'7ΨςΔΫY§LQ1k_ˆ²s!z*£qπαx|ŽΛ/΄BΗυN^<Œε5mφβΧRΧΪDjb$'ΐJbΒJ*‘€ηJq@(‘{•Kφΐ«°Ϋΐ‘ΐ Ν†~6Š #ˆ³΄IΛ*ƒ${α:ΑΩ½θ΅₯μαIΦ:ZλwΝψL­€GΫOΤruΣaηΆ Χn/&όϊpζ‚ž«€­υbξ·9€Ϋ4“pt²ΧGΉέ?|ώvzy+«7―ί~ά”Ί^‡Y_žώZί?ά‰‚δΫΗ?ΥiW«ΏoŸ~¬6χί{Ϊӏ«v[*>|ηϋχGΜm»Ότ‰faΒrϋ9τ˜.lώ·νίΩωΔΏΚλρiήώήΨ<«ΊazV„Ε¦z }­ v½Ύ΅‚½<’βjqϊ3 ΤΘ Ύvxϊμη₯α,h¦dΗ±Ρ¦φJ:y]‘‹q•ΚY—ͺόΧν@°^€ύξΔ”­wΓ]ΏήΓΫΝΑ2Ωοoΐ=’Ζ§"5;Σ΅UKϋ ™T%φ¬3S"Px§.x!tΦΦTSμˆάΜΖε<ά[h·ζ™x2&Ο/›^nΣ3Τ923Ο7ερu΅‘[“Yn˚\ 6Δΐ¦Tιl¦20pN†¨ΑOZ ά†ήeIΑ–bϊ-XsΓέΦμŽΩ^œΠœ8X‰VΫ€UO©0e,ΎΣδhO>]΅ΦΝ i5Ž,œ«9Ϊ|‚Υκπ1=ύκΓ€ΏyεαιOπσΥΛνφ₯S π ώeTrz…ΐόSΙ°†€bžBRχΗ6Eο €1m—3Β±­aΣΉuʍ³-ΨSΣ±ΧώώΆNΤΖYŸ†·~“Ž φ₯&^‘»ΈVA˜€d\R-Εlc2€0Ό‡€%K¦·¨£/δB“Μ«0˜ΛX$­rZΰώ©ώUξΏOηm™Ž|ρ™1±›_~YA€δ‹’½Ko‰¦R°ΕΒ³sT=h 0˜₯ZΓ¬0-tm `G+ίΩ)Σ‚ξTΓ»Έ MΞΣGΚώι?βς‘ζ3υTZφ”CοYn›uβ%θ¨:¬yJ”UŠ£½hWπ…g¦ΪuŸβΝ#ψ, άfן;ξuŽΓΜ[³xNdΓΐέ+Ή,격…’J©TS‰Ωεΰ3\d^–Vκΐ &PJXwχυ|πmΧ‘k_`κ¨BεP}pCυΈ¦ι‚φ,~*Zψ9Ύ#Ε!7ŒΙšά2V8wPr3“2rv4v(ΞϋͺZΖGΆLΦ™Ή `S€ιπc“³r¦œΙg™Ρ!0K3R'RQΑk€†υΕ&(ΐβ°‘ωΑx{0Š{Θ‘αΈ*“:'Π3KŠTšζΗσίlϋOσf€Ξv•Α‚)«ή΄Σΐ¦΅.ΖHμͺΨ%αׁŽe‹χ]‡μ`Uαi«$#,™¬υvχΒ…nοŸZΉΏώ坌° dΙ άB―Ί )XΥδW¨ΙαV|Uζ bjJΘU»―'ŒΌ­θη™ΐ£*CmΆ©;σΝθέ'nΜG«cdgΕ/7Γ$]>όΆϊώηΝαυ=Μ¨ψb@εA—τΝsyΓGΣΉ˜`­–<Ø dΩ+€bPΈΖ|D&ƒ>Ή’υxΓ³φ֟Lμ)=v'Φ_oa[7εΰΗs3φ¦aw_›α@Ί‚«`‡SΤ`ΐ>Βό*ΨHJE‹MšTm=¨œ%εƒ/Z²–\†eλΗρΒxY ύaŒŽά))­€βau J.mΫ•ΔλB”ϋΫX€$3αͺ·ΝQhEƒτξγlϊEx΄zόy˜ !Aν₯?Ζ¦Ζ*j2!b=αkαGA`5wn°Ό1˜K]u¨!ε£Β^sQλΉΔ›·§ο«§‹Ί|l3A€ρn#žή$o”„δ’1Ι:βεα1“ΦΚ«%³ŸsχU›jгs7εύν ΐι£ϋυ°―θC»{Ω\β>ΤΣcγΫΖ›ΖσκρΎI.woξW[—4•>vΦ¦Y½ΑΫa…G`ιˆX”"<`ŽdΌ‚ϊΉ4₯1ί\Jp=Δ"ΓKEGΚl"<΄rήY Χ>σ›OύΡΙ ZοžΣ0‘5Ÿψη ϋž]Q.ΨR•ΟΤjΙ™š ΐ&₯κ βη%.(Ε™Ξ'ͺυy:ςΉ«FΣ±}αuυψ}―Φώkστp?ΊΗ]|›Eρu(=QΨ Jfi&LRΠΊΪ¦ΊT_¬q!%όUgηΏRXρ&jͺ7υw5κbf—χ{AŸk‚οV’~AE+pβ¨8ƒωKΩ4`lτ1Š£*I=)Γύς͙ȍΪΛ¨ς%- X\ΟAςΐφ±q:‡₯zŽΊoΥΦ »cν6¬’{y[4`«TyΤrzƒnδj$β½ͺοΫmΏ}ωxΗΔ/B"Kοζ†Ή<³T|α$ΧΤ(7 Η”Ήζ@ΙlRRͺ \ck$ P―‚W‹’“έYν’Ε£AΨ„iεΞ#«­JCfͺ=ΕΪ‹iFWΉͺ–J –>Yΐ`ψWΨΙfœbκ]&e¬‹R|ΞN7½ΙΞΆ«VIΨ7–k”hvg0ρ3 B΅³’uΆ6ϋ²m>vΌΖΘpΈ8§%š„Νή₯Δ­‘‡Φc–[.rΉU²#J°ΟΨΨ‰”χœΈš™BςΟπό…Cώ·:”κY―«ΫMΘ DYoT)_žŸ&™ρΓΐH71ώ‘>ϋ©λŽƒ—±ͺΨn4cNPμjμ»=Ε±ΎwWμp·.žh‚…ͺNΑu °ΪLmrmΛ"–h4ΜXŠΪeφΉƒ’‘cS@ΒΆt<Ρ>zŒtŸ˜ΑΡ„νJ΄ΝΝΪ&uΰΦbωK]+ β>«gDW-{ΠΡβΊAΒ€š±V[ƒΙ Όξ½• #Ά:ή_ν\Ζρ{£›©F3`uK§˜±ΨΦS5Υο“€V'Ptr«ͺ2;˜'m{aλήƒ~°tΰΜΨΞ²ΠΫ£φοωΡsŒ»ΈψA fΌUΉzEπEZ΄‡Έ«Ξ΄*$ŒΩφ£ΣΨτά ζ³£›'Χt›[­ΗU+ke η˜wε c”4E"TYDuΨυ!?H½ˆfhθ"'˜\+T©UPΘι\Ευ3ίΆMκΠΏηΗ(QόJtfhσsŸώΠ­zqΉ›J  D% M՘ά:Ξ©ΙFΗΦΑ.[ΔΔOAIξ°“j|λhš9­=Μλι!ξ7Vk»Έt`ΥYΔα.r τ¬ƒεnŒfɞΰΒq.ͺjͺή–}r•JŽΣ–|$;9X±Ο£ QΏψqV91”ŽτP7ς°R &³–f%ͺ’γ›Τ‡V@γHGΨ°ό£ΨΆ’=Ό6]\ƒ„!&Β―μŽ‘K΅š-x€(ΐ"QRΪΦ"ΉX5οSk₯κԏ^»vτ­ιΥάUψΫχ¨ΛΫ8N–΅·€•·M8‚Φ‰e ;ω:€^g0FΫ•’Ϊ(Ά …ΎΛ6˜@ubMΧ—Χvͺkθ³D$ŠΞ5%’$Ž]Ϊ€†§Ψc q(φXL Γδpκ(p1ΰ?s΄gΊ¨γH΅ΖτήΎο&R„₯©‘\½&Έ)-UάT¨3BŠEt%$κη1V;|•  \eΑ­νφψJοŠM^;³ΓfnΖ‰ϊ΄¦ “‹]Ϊ8Hh§2Ύ&ŸC†‘ Ιΐ][ναΒ;8P–Ϊτω‘τΨΗ 0:"l‹{ΗP,YΐW’*Ηξ΄)oμJΦ’~a«qΕͺδj“%ΑC8” D9Ι2ŸI>΄Qg7ΫΊDPΤΎίŒ‹`ζ€€ύΝNηωαΆυΘPΞΜ|ωb™Ϊρ«Γχ—ϋQ•퇉ΐΓbSzaD8{‹+ "6g’[²Q9[•ͺΔ’ΠuReθύtUԊ‡+ιω6½!ӌg|»ΑϋŸ¬μυ ώΩs``PŠW±asJ%§δ 7LδXΙΥ>α‡Rτ䀊Ίβ%ΐΰ[bšΙ)†ϋΌΕΣέT5mζe{St^ΜΏτy’wλlΤΓΓ₯‘˜3=6D§Fώ*l‰άό'xμΣ³-§A󯉩&[€·$ίζξρπiš―κΕ«&"θ5\GuœrφƒΕ³‚‰Φ$wC1ϋV€Žkν΄₯d―tΝ.9ωŽsΆηοίΖFvqEoηΈFiTPkS›Π[‘07–Eμ-„½*ΉΏg²‘80)|‘ρvΙP5Jg=ϋψ/‡Φί_CάUJ©£T” ΨQ΅ΗΞΖφΆRf–δŠ΅Πd=”Ϊή|Ή₯»,’μ)9υ@€ŸnDΫϋ£0ςΏ½nϊrΰΙΝd6ξφΏg§j‡­fI./Ιΰ %o²nΝΤDΰ”RιΑλ―‹I•ΐjW•X2""+ v}ΨHyδ΅N\‡σΨ‹ζ‹ΉP1ˆH’o©`¦ŠθRe‹Nη+;Ρg€2Nm†S}˜ΉΩΪ¦`ν;»εoIcŒ:™*Ί58γDM1z°›™’TAγΐ‰ΙN ζF΄#a3­sΎaΙzœΦvψ”ήK83‘z(k%ξώ—Ό|#r―wOo7Ο/όηŠZΌ< 5X&kΌ‡go ”‘ϊ„έhδς86IŠSÁN’Θ‰ΝΛπ ‘‹½υ:"γϊ•κωΝ4ˆ₯cϋRI’Kˆ7‚LΩφΩgΈ8₯Jε ¨O³Ύy”1”'Lœ6%Ψ―B 7ΟνF φΣ_―7ίίw·ΝnƒΏαθ„L~θ΅ϋο€iΦ΄QΞ’\sΦμ+k2χ>p”Ί­¬rz”λkQHsΉ»ΗηΪbQq “―ppI{έ {Œ@<Ÿ/‰s$ΣTsXVm xτPU#i“žDΗϊΘ:Ÿ\²ι…Ύφ’Eσm$Š”΄e֍€nάH |· Ίpb€b"7gZo:[@;'™ΆΌvΔ8ΙnpξΚ)ξ.ΰ¦ ΰ©ώγΨKνΆ£Λ9dΙΒO0a!Δ°p~¦ ψ8ύρpοyB`{ω’-UuυΥ, ψ»ΐΏ&Žͺu―{PŒ…’Q!*pŽή“ΆΉbοR(~Ϊζlο·e|Bκύy=’u<ΰሡύρ·ΉΊ>jΣ1§φ[ RŽ=¦H ~Έ•BmΆ¨ΘxΙ›”+Φ’TI’’ŒOΩ„™5ύϋ‘ΟΣύYξoKί|η©<ν₯Ωac–(ΚCΥη42Ω•αƒ]†Γ,ΥŽJΡ^*τJπΰΔ3*εΞΊ:άο>3 Qο;1ςΖ‘_]Ϊή²„[‚$’ƒ0T’hΚΧ.†&ΐξˆΚi“r.iρ!©κ¦ΚιΟη+9Ο5½˜€[ό^ M΅l€μŽ@[G ;³ψ2Mΐί2Ύσr£DPU5§φψ}#‰s³V4ž](Q{™¨―ΌB.Ό U…δz4€”Β¨Ζjƒ}@ι\ΐͺcq|₯F,έ>μ uάυ)Οψόο?ϋΟώσΏό_ΟvξΔЊcargo-0.86.0/benches/workspaces/rust.tgz000064400000000000000000001300101046102023000163200ustar 00000000000000‹rust.tarμ½i“λΈ• ڟσW(²?ΈάSΚ$χ„kܞξzγκξ({bή‹ς ‚+)R&©\j’ϋ; )qΡ’J¦˜χ^¦—K‘ΰg_²m^άί ž-ΣΕ£ΘQ¦wΏδiςΓύπg›fο}ό£”Α΅CmΗ΄MjΑ5!&ΌoόΓώ`ώ<›Νώα+ύϋΏ7³Ων2*n7ΓKψ‘―8_·žΛ-ξΉ‘ifψ–ΟCί ©OCF¨ϊ”ΒcF©{ϋ­j7»Νδ:-$6]Ε&έύ=τ»Ϊϊw"]ίg°Ξσ˜'Kuu Mώ Ϋέnx±‚M‡{[ήήόΧΝ?LΧϋChάΗ‘ŸρμεžΗq*ξˆΘΰHΧρuΞ?‘”ΆΟ?₯†1+όύȍL™ˆHζxR7Q,³…Ώβ"JςO7‘δΕ6“ωμŸg?έβnsh2OΓy^·Ÿne–Gio;rg·77νN3ωι:Ύtww7τ[σύ7?έd< tOΞ­ϊ±xN³|……ΎK±Y5’O7ΥpηΥpηB ³3{qΫχφπQ,ƒyΒΧε»-οτχ"Χ‡ΪΚuo‹$σόP#ύΪέό΄αβ/aρψΆH}X€•fΘγ\ͺ{…̋ݝ@ζ"‹6E ŽΏδμGΨ Χ{¦Ξ6WΟp‘EΗRΰΟ|VΫDUcjχφ&Ž„Lr‰7~ψώ―³ψqφŒi%ητΰŒK‚TΧ/ΉIσ¨H³Όy’ά!Υin{pςΘψ?ΟήΉΛς+ρβϊώ'w=ψ#Δύ4-ς"γ›θ?1»τίt&ψ_›ώ­BzKΫήνXσYQvτ RUDkYSγ₯,"AψϋŽ@£h™ ½QwΜ;=ζΏΎ,`™‹¨μ!ž#κ~Φ2[Φ_B²]/Δf›—£Ή½I!BΖ±Ύγ`£F.3έΚΊ½ΙeΘΚΥΰέh ό€=]ΏήβRώ‹•Œ72kp+ϋ:­Τ7[LR ³θQ6Y#ΫΟσl2Y/ žC_š«Ϊ·ϋ €>P€š[̒9Oruύ v;νξV„Λož’$HŸςίήή5&·ω&jΝ AwoΏέF)\δ²ΐλ_R~PΌ\_QΏ}D©(bΌήδUΓυ&†Ω‡|mΦ‘M”ƒΰA)‘ώΏ&ό‹4sμP.ŠB-bNΑί4­6όMfLπώσδe•>U‹ c^HZέ!@–VςΉ’ξ΄M©‰"ν©ΘCΊΫ‘ΜpkΕ©ξΕS”™guŸήqBύ ’Ϋ ‘‡ιecΟίΆ5_ΆHzόόC .ΐ&5'ύίuι›;°x ώΔθΨ¨mOςUπ™ψ±€Ύ*μψ΅žaE€Kψ›±ιόAΧ›9¬ΘRÁ“ό?#mψ3‹ΨόGηΝΫ±ΝβŠ5G`WΛf5v4έ΅XφžΧ|ΣβΪUWm¦έΉ3ή€e#Τ:—ν―·ϊWLՎœΑˆΐψŸ™6™Ξυα―Α†Ά€ΏΠξΠΣ™τ?WΑZβo [­ςωtSjκη{xW;4ρ―€#Ίh˜!ξιϋHΗ 4lήQ»M Zκφ†ΕKmEς_ ™GΏΚϊ©ˆωFaώ;Fπ‘₯yξKΎžo‹(.--&rσό%―>lΒ=™<.βtΉ¬,LvΨ2€έι[FE©Ι"LιΗπΖ|G6‰‰ eœϊ₯‘ϋΩιΠΰ:­ϊΚ΅ΪyR}j›MΣ’δ5ZΟ3mJ³Κ7 ™©\~Rέό%υp>Vγ‡0{lqΚ“οξŒk΄cžƒjVυz§όCe5,xk±Κτΐ ξ€―i±QCΘ€˜lΣ J–εœoo΄ŸΡSš=δ@Θε|ΤΌΪYεγ0*WΠVκDΕ•θ… φ¨xM<—Ήΰ›ΪΌ«Y΄™σ$Κgω^›B7gΌΕτl-8ΝJg‡έΩ&L@Ο’@› ±'kw9 ͺ έ•;ƒΒ/XΪ'?QΉj΄λ<…¨xΎ¦Ωzg˜œΡ_׏;|Μ‘ώpχθ uϊ!έ~T›y”v»©ž΄za¬‡³ΓcbμΠqˆΆ­ƒšχl5 O5zΕ=šη0ͺTyRqV‘m[Θ ŽιJiΛέ‘Ž½˜=¬ξϊ›f”ϋΖώ:Fω@{Εά·ψΣβ‘ΗΫΎQt‘ϊ*$Οΰ tΜβε>EΆωšΪ>°[w/τΧχ{Ι·›MšΗϊ)_iϊBW/σ'ž%€ŸΤZT{ΐZσš@όtہ½Zͺ$@Œ4/7•z±ΌΎ―v\ύVi¦Wύ“«mΐg‹ΏΞ~τ"x‘aΉζQŒξt-κΐ©Ε³?]ΙΩοΧς0›8V?λWΎ‹Φό1‹Δͺ€E=‡Ÿΐε-ύβ§Άχ βΏρY9²Π%ŽsD£ά οώ–άή©Ψ…σͺYεφrτςφx"ΡΫpνσQ΅ΡΉCΜqžγaΩy&y oόψ§οώε‡?έ­ƒWy#–έ4φ₯εžι-ε)@JRδ.υ²πy.‹<θΈSh7‹–ΓΠ[˜^y%ψ!⏀¨/Φos冑₯Bζ9lΠ½_Ε W―rΠ¨=5ς—D¬v2Λ¬ΌΖ!–—"MΚ«dςηψ‚俁=@.њl²š““€¬ŠˆΗ%•ά»ρΑIύ/uZπ§„:όGΠ`DκP‚Μ_€(f"e ŒL–w9‡οͺ€‚Y‘ΞxžGΠξ)ϊžΪ6³έ>šiƒS~wqπA{gΎ™ς]6ΝKΟkHΔλρ?œ:Ω>0όηd'ϋ)Ν‚3(Α)ψ;΄νGΩδ9 ώο·ξυκv›‘άΧΑΗ]μϊ­qn’RZTŠD³bΕ‹YΖR€@„fQ’p½ηg¨ΩŽfνNΣΥ©ΧΫΟiJpώgdŠωΠψΝEšΟδ‹Xρ(9NNΑί6;π7‰5ΡQπΏΨ«ώ23ΐUh€Ω³C OFAγ°uγ/³jλˆΕ›gβσD:G‰ΐψί:?ŒQϋ ΏΞζΫώ”:tςΉ:ώœ³ο΅q”[§mZ8zηA.žUΟώ6ίΜώΈkςƒ6… H:ͺ5Ή:Νxλω?Gtώ§Ά5απ:Κ’ΨκrOΐ“ψίκ‰t¦ψŸ«ΰ½GLƐΤ‹γ~5˜Ζ§­Σ^e€™Σ,ŽVμ,/±h”»Ϊ)σrm?€(?ΐΟύUςuύHfςHK€œb( ™‘ηǞcΔμ‡οœ}£Ρμ)γxύ·§IΕύa:'ρU”A78‹0œ8ƒX‚/‰d“ώ|ώΏα\x9-8©aόoΫΞΔ_ŸU:z”%Χ|φ9<Ήzσ7ω |³v&KΓŸi?ͺY΅οΞυ8Ϋs‰=Λυμƒύ–~χΩ73ςτ*VθWœ‹iΑψίΆ'όAπΞΕφR p ώ–ՁΏ3ι„{ψ#‹U–Ξώ‡”kžΜ~‹ϊύ@O’η.Γ¦|y”BEoΕWθ]ε*έF…<†ΔαΗ«"ς}Ης/Ω‘θUηB pώw {ςϋ@π/C#.£§ς»ιXl\ο‹ο¦όμΔ;ξBD"v‚QΓ#Χι£\QΆΰq|8‰g7όN₯υlΰ5BκzνΤ}‘D΅Q£Ft"`n§ƒε†K{[DqJfη½ΙΡ ¦š}Aψ"ΰϊo:SώŸΔqo³’fΗώOlc’>ύΩΛ¦Hη+ž―*[<ιΝƒΠL ΪM>@9ξάNϊ€ˆΘΌ ΌW)ΘΖο7CτQiΔΡ3±>€rς‡(ΗΔ<‘ι6Ÿ•hp†Qύ³m.ƒ™’;»»²|ͺ97K¦€γͺ―).Υίn•“ΧίnΫ‘«XOd¦Ϋ$Pς{K_  ύ‚ gQ1-wομΨΪu€w#n;ϋ-΅"Mς΄§έΛφ9šLψΏƒίdΌ€ώ[Ξδ1ό‹αRŸbtσ± ώWΦL”Wο : s_Οω0ΐ%ωΨ? όγh³yΉnώojέόΆ3Ω―‚{ό΄σΪ‹¦β³ύ€EhΧσOη³*ιEO1΅ίq”ω^j¦½»mšΣιbΈΡήUbεΡ¬]¬jΨ.䀋(―eΑA.βUžΌΫν@3OδS­εξ(Υ£p‘ijύoG~{σχ-`ζ=ύωR ά*ΣάwJ”–σ’Ξb؟'K/ΈJŠΨƒΊΫίL―ΔώY»Vh±ή΄₯+§·—WτθΆi‹ α6Ž{ΫIλΥΨtχΗΠϊy.³Κ\ “+wJω(ƒ­2W-»]5ŸCƒj‡ΜΛœi¦©–­—Ώmž…ϋM›Δzj… η–•ϋ-Rx ~6~¨sσwΏ«€ΆΛ(ι ¦π·‰X‘§¦ρ€UŸι5ΐΌi„UFΧkxw!cχ£*άa6δ Fο―JΝS©1ΐΞΤ‘θn6[?Ž”βJJޚ)L]U·xa vw„» P ;Ν9@τεWLλ§Q67WgY!—G?Bώk’£ΑΏD:€†`OΑŸuλYΖdC”EΊMŠΊε^ eΦΛ–΄rϊ6ω’ύ}[U2έζ9ΙόwΆSτ’L:Š·œHΑ%ρΞdώšι|38%“ύΧ2 €Ι°ηΙ§Q"ηk±ρ6~ΎnI˜ƒ˜Vπηšh‰u§ ΊPdS[Π¨YeSOlΝγθΧΪyΈO+Π/Ρ’γVG¨έΟί ‚c>%s±ζΩΓΉWξ[kTΜΑ}D ΡΧ΄Z!-₯;όn‰ΝnRφž δ₯«έ"΅Zλ^‘Ί_nΦοΏJnή-ڞ̬ϋ9KfώΜ$ΫJ56Ι³Σί»Σ7s€—Ψ™9ιG‡ΏF οΝ&νΒί$“ύoώ―Γηυ²i'φ.e?JΌ_%α—|[[±;Ρχ;γΰkŽEοjυ_ %ύ/sθ€CώΗ8+]A -ΧQ֞Β@ –²‰4ί…‚5‹Ϊυ‡yΥκΰ#…Ϋšρ^e18%ΩƒTF2˜οFCΫZδAπςϋσ|λ£PθΛμάXp­D:, F1AUJg β£JΨγΩt½ˆSυ"– jΫΘιyΥkχjGγέv†|ξxV7κϋ½Φϋ-žΨuΞΏ©`ΠΗΖ£Φ΅ν‰ώ_ ώe½–{ μΊψο9ςŸέ‘ԘδkΡΆ[Ζ“`Ο_k_Τσ·ΛE&Γ²T,–BδI$Ρz „ €¨χ1<ͺ-Τρm‘ϊΠύjpβ=•€ΎΣΑΦy]ˆΕo¬·θεW‘“W«Fο0·auύ’ΟΐΕί.ΓΤ0¦ϊ/WƒIυ³{­YGΩ˜ΰ$―Σ~‰ε{εκ©%ΌB/x2ώ‡°Nώ_jOω‚Ο54π{ΐΒ±βtώΟ8gŠKςS:ō!5σΏ—•άί(œΣ‰΄l6Αύ_Oώ‡2·’*VΏ‘™ΐψx= J= Ζ«s2oΥΞ½)“QoŽΒ\e&Tv*.TaRUκ‘.@Ž₯Ν/4ͺCσζμ Œ]ͺžwώί&\b±œιό€•fv©1žKτλζ°}ίͺ:Ϊƒ§όWΒέψΟO-ΣJ7ά2HEΓ§ώ‹*ύδ<ϋEοF›€Šyώί¨Ί(ΛdώΟžσΎŽη<Θm½Ώ%]ψΣ‰ƒW€_cύ¬ν˜WΩΩ«'Έ[ͺ{μLDίέQS™ΟκόβEιόU€™V<Θl0KπIύ—g›μΏ#ΰΆSΥiόΎΏc&ΔώE‘,Α—ψ8Ζď₯‘ŒX“8Œœς5ΊωΏΜ)γ(ψΏ©'ήνfPίΔΏ]/Δf«dψ™ρ—=eύͺΈΔUqΦvέ}ώ•ξ₯vξΔρςMΛR€Μi;•xGLΗ+Dwτόe«ΑIΫC³m‡θ·ΈΝΚ,[kGΙ²Lb¬~V£.rY΄«jΓu”Š".―“br»ώΞΖΓp—՝όG€?ZpƒTˆ‡kζf(λwς?Oώ_#Π0ŸιΠ4ΥΊλ ωΑ ‚–Ÿ …ϊfšΉ(‚;a?f―w@ΎŠχβ‚Ξ4λ­9I™Χ8cη&“οπφςahυίiύŸeχΔLρ#ΰ&&ίΗγη!ι½ύ3‘ιΟόό7Υ ώΕ€όͺό?£ψS{²Œ€;œΊJ₯ςΪrkljϊ'fO“Ο^—+©Rͺ͚₯ΐΡ-©@„™Ÿ¦w·G©ή­­όόΜS6Ι#ΐeΡΰΰ'σΏXέϊ/l²eςΈˆΣεr―\Θ^]OcΏdηνΝZς|›I‹=]˜{<ξ­J’u@½Ε=«„)ϊM§cZJ N u;Giτ&Sι©ΤΘr£ƒήš5΄‡+wk‘ϊŽΩμ―’―{Šj$@#72‹QŒuΚ&“XΑ©£2dύπύ³o0Z{`ΤLφΫ»“ρ*χ}Α*xά_§’t‰νeΙΦ^™₯f’ΦΧΑCgΈ$ώŸ:“ύηjπ―ς?θl*‡Η5ε?‡vν?¦1ιF U$ψΓ‚Š(Ιχp|‹ ‘n…©;]Žp9Β΅ΤœΌ7OΓyα&=IΥ‘ή5SΉ«œ.­·bœ›ωœ“ZΏ_obΉ“LΣP“^uFςΩcΔg›,2ΟgκΐδGŒξΊλg¨9xώG―9ω„·ͺ6ϊ€ΰ$ώοδ!Μr&ό?ώWΘzΏAx<ήͺ„{Έρ}λmφ H°Ί§(YΎεW#3+Ωασ?Έ[Sύηπ?04:»Ο :ΐΣρ?Vώw’Žο€oΰLδΜΪύχ}₯w;gŠα"ΐ: Kπ?™κΏ°Αμ C.¨ ό―‚ϋςΏˆ*νέvΈχ–@πj͎qΎDpαinΩ‰ώ yώ!—ΔΨΖΔ] ώ{ρ?rrŽ&N¬ ²π$ΰ$ΟΊωΏTNΰ ώΧ֜γγΫέ#“ϋΥ|ώίN.ΙbLωΏΗ†.³ΗAΒ@.Βζ„?ό―χΘ„Ώΰσ?ώ'dΒcΐ?Ξ‡/uώ&qΊυŸθ”g<ύvΦT;BΥ€=`em§‹‘φνJ Ύ¨Ό@Kz-±bDξKΎž‹OΉΛ Σv9vΠεXϋ «μ$«t]z[f2S#«”1Z%ۈΉς‡Ε‘Έ·=™Wφ—[)l,ΘΡn[²Qk—ΰ¦ GeΎ7GOίΙ7<©§†7Γό\θƒΛ’rv‘σ*FGηΛo݌–IεΨ¬rυτUΧ„s]°ΚΡ’š¦κ§›eTœ›Θ>“ψͺcΆMαx3Η4 MΫπMiš4`‘+ˆΗό0τϊΏ8ΗEΈξgχκޟχau₯›ΑFR<ό›ΛαpΛς¦+M. W\0Σΐ²©ošΆη…œt} ςΝΌxΩΘΆŽu“₯›4—έͺέU­f°Ο²σό((Ίίwέξp+?ξ<ΚwJΪύ»mφΟνqΘΐχ£ψΤY£ύα…ΫΣΪb|S•ζhΤ­Vs»―9Φ ]σ$ZŠψε|0cuΧ €Τ… %‰τx2β„œψΎΰžεSjR"!Η‘,θ?ΐJΆ2ƒ_²έΐλΦ/γύoλ]w_Κ1Ÿlό{˜ϊ eXl$ϊκλτΧ(ŽΉ5ςmY³πΟ™ϋ Ζ…Εi©‹;Μ,x!—iΥ΅OΤλθz4WθΏ’<‘ώ [q c›ύE w6GΤΗ^E kŽKάO·Eι»”₯ˌ―s ½όώ_ώ”ϐ²₯Ε λυ`ΪΉ.έπύ_χ$@lψ―₯Έ‰#ΟL2β‡ε/yIό™όΖ‚>iD<ΙzνSώ‡τZͺ˜'ς©–ϊd·/XνΛD<λ•ŠΙ3 !₯Ε²…yq+°ΩΟqυ™}Ι9χkΧΛ9ΐ»:ξ3Ό* p2=ό|ρ6Π«‘BaΥrόΣν§39‡=±α ,D%fLό}ρΜΐ%ώ–5ω”‰•([_Ϋޟΰuϊί§KέΏW:΄ν)#έ>Νh‹žWΝ`—•V¦^h_\tίZA΄‘IΠγιΆg^χZ] ΗΤxi7ΤΓό{ Μ³ΰKω―ς)ˆfΏ9pRιΓ–kΕ—“πο1ΔΌ 7…nΦΫ$ZΨζϋόγog1ϋ²x’2Q*τK•Ψ…"ΎVΗ½FORώη‹GΝgύώZI:pŠώΫέόO&1§ψΏθŸœΌ/ίοF?Άν¬4©e, ]Δ°c]BζεDΓ怉λξξΎ&«―αgޱFžJ‹Ο©6§m+-HeBQύ£Ϊ£\`ΌT£―T!Έxϋ¦•Eψκzοfy„έ³|­gΓΪΞα‘ΞtτεQQ_ΜΧΫ“ƒύί‘­<υ?5Σ~΅,š0Λyα§Ϋ:ΜσψώϊΕδr8‚κdέλχζψ»q˜Bδχ7‡}>O“yš?7m•Cq“―sj“·Ϋ6豜υ~aκ$-ΎΑŠhιSώΫVκ»rqN‹ΐ~²Z½V=Ά:„Ϋ|΅QŠ’Π+ΜΡC+Β+Ÿη²Θ58Β₯ϊ'Mς4–εs™e+8vq”,«;IωΰΤ&‹|aω Jl™Ύ¬―Rx Ÿΐλ_RΏ|U_)τωdpΣbš+Nγ”Γ―ςΥxR'CΣμ₯Ό½Ž’ΌΜYώ„9γdΤ/€Ο&ΪθΛ§<πΐ%‚/€ΫΥΤ’P—ΎΘ₯¨oβfάͺ¦ώ/UeΤ¬Lχ~«Lς š~Yφ’ϊUέή%|f›EΕ φZ=Ζκυυu ŸTWyyη%ζΥuކϊς—ώφΨ­X.ΉxΩ­2f^ϋ5MͺlsΜ§†½·Bp)4ΎΑ«μeS”Χε’ΐU”Š".―q ΄žrZ½‘Σh³»Φ ώ©5ΙF―ω·ϊ\"±©ώϋυΰίτXπMˆ|Έπ§ΰOνnό™β/}Ίρ£"ŒωRgFF!ox.ψLW΅jNήj£‘όΐ.ŠœτγΑΨN~Εϊο*Φ³cͺ3‚ώ―t3ζ_δ ƊR#ΠuδnΎ1"‘ΐ­:‘ˆχ8#Χ§ώ ώyqΝψObОϊο“ΧαQeˆYRφ« ΌΙΠo‘λΉ§΅Ί M,Ÿ{£Τύm”)₯o˜ϊΑVΉΜ"GΏΚž†υ³Cm7<ιk·G$Ÿω$_MτΏK§όο#Β§O€Π’εŒΐΙόŒuλ9ύώŸEμ•|ΠCΛJa¬Ώ ¦ποΆ@ϊsθύΕ&“Eρί¬|ψΞμˆΜ²4λkh΅ŠϊΨΈ; Σ“c΄—£ΠO`CΚztΚhέΣF?•y©ΡΤΔΕΌώ€Έ¨ώλTgTψoxˆd5ΐ)ϊO»ωM{Κ?ύοϋ9#Έ*uηEΡG`ρφ‡δJ:ΨΣ¬|r έ†gy_+usΰ ^CΙ5Β™θψΗΒƒ¨.±ΪSώ―qα―πUθΏΑιΒί™ό>¬όJj‚ΆΌŠJ”|ΑD%sώΗΓl²Ž`€‡4Ÿ¬Φυd¦5ΙWΗ_‘φRΩμ31:Ώ4x6ΕVωD«?Gό? ψϋ―I¦όcΑίOc>‰‡+Υ£*Χw»ώΛδ7†ό'£b₯sύ“;U «ή€qšDΫ|.“e”TUaΎ|–τˆA‘ΕB>ςΈ7ΉtυπCr ˌoVΡ―=νͺG#Ϊ„£$μεIΤύ!ω˜(β>vD?8Ψ*S° γτ©·νξρηΓ `//b˜?Œ%–’θgλcύδ‡šθ©_•‰ό|θˆυθ€ώΫ(.’€KίΞž¬Ϋ“Υ"χ₯θΏ.kΏ|ή θk₯|=Τ%~κΩΛ¬πβPΣςρδ±xj ΦΑ ίΜ\βgZ“ώg,ψWž°Ρό)#=ώl²Œ@›ρ€PΙ2…!&YσEύc-yΈRγ7οξHΑ`D„y’ KžPx•ƒWsoŒ6­+_`FΝ>C?Qw…Έ¦ΑŠhτI²ΰΈZ}Ί€ςΡ ϊ«Ώoeφ²Π){Ϊξ?ώͺτWWγžφΙ€EΊύ)ώΓp&ωlψΔxŠsh7ώΓ±&ίΡω?•Aˆ*1νυΩI} ^U…phΥδο,ΐΝHL‚( «{Θ+Β{Φ]›ΐΚυ“°β †με .1υ‘’8·θ8f\Υω§1 njΊ$V©JψZf„V‰»u~c,QŽ §1CjSξ€σΆ{rt7’§υρ•UB»‘˜Χ―…ω(”$E―}yοι€ΜλeŽ]ϋ> lώ²φΣx‘dPΐ }›o|Œ°’3ίΘŸ’C˜/±9“Χˆό_ε„s•ψΨβ=ώ“Χό_Ηk™/ƒ’ζμΞUήM<Πgεv!2’Ψ|Μθ v>χ°s±œ”h“ώο(ύ-ώϚκ?Œ |οϊ”˜έϊ―™μΏD.ηQΈΗΚ„—ΏΜΫŊ¬KΫηv¦•xΕσUUπnόX.™ΙP“·½z\πP<μ4Œδ…!Ο2ώ’€σƒ*Γ5t:=ΤŠΞ…Θx!ξκg-šJϊŠnxφ#]ΔiΡ+’Ύκ{/šΨΣSΛ§ξ·ΎΖξ΄ŸW…έϋ:™χζcyϋΛC jnΆ9ˆŠ›½‚Ζν2ύΥΥτ:ѣ˞u Σιί TXΓk»}βωšΡΏέΆ+Υ}‚“Έ†sJλςo¨GΧW- ^T²ΟTIμ‹£cΤ²§ψρΰΕVΜqώΜ4:υŸ™γLυ_FΰxQΌτ»ϋ•μΥΌΘdνΨη}ˆ·:ε} €T5ΪƒjEύτC€Ώx­&ž†πξαAΞ±YΘ…μΥk–Ο9Β }Ž…pϋƒΨe/ Lj·Λ(YDλMί¦έ{zˆζrΑΏδQί¦i<Γq_6R<τ΅R:­JμΨηξ¨{θΥyΎυ±ό΅ΪϊσΌXΒ΅ͺυ+“Η9pΰ°νUqαR:QΜψN°T^,Iu Ρ»Yξ½ό΄“Lσ<έ+?Kψσ"–2FBͺή,§pί|Τ,ξ}JΦQ<ΖIη5RI³όu ύνrWΰΉͺ=I'gσƒe€Ή$‹ƒ5!&ώoψο1Χπ4ιρ˜τΧαΟEΨ t²~-η4/sςώωΥτ?DΕzΆλ?Oώ£θ’$-x!ηym6²(έό]Dρ έ k‘ΖiVGŠβψj»WΧ"·M"D*σ§(ΠRΎgΎ³^ύΘWω%€zφΉT‰|±Ξ•V< jα*IΔjgψρy.'ΙκKΓγΚ“ύg<ψ«D5Χ£=ρΜ±'ϋΟτύς?©z2‡Μ;eνŸ){ΤUσ@]Ÿ5Ί¬’ΥΗ63 η„y—‚ZυŠΕ+³‰½CόW‰Η₯dͺ<ύ/χρ` ΐ)ψSΜυΠ’aLπΏ6ύ˜$ΜΦ„o:_χόE.ΡΞd ώ:!ΓΥπ?1Μ …ΟΖΒU–Ž -ηLόO¦ϊ―£ΑΏŠγΉRύƒτΦ™ΰ‘π.Έk"_Λω΅ώΗd ώ«hΠς―'ν?ΤκΖΠΙώs}ύΟIϋO¬Š–ž;‰–«"~ι˜‘. b=Ju©eεz ίΡqδsJo§’ˆ&&c\ό?`ωΧ‹μ?”NτDψ—Fυ«δ3,•μ)ώχϊτ”πέΧ†’Ύ ₯{mͺgσE¨η΄ό_6›ΞXπίK’}ψ/ φέϊ†1ΩF2žuώ«wqό<³Π_―πχ5s±~@ΧΊs q#‘$,Ύώ/ώo’γΑ?Οj€OΑŸΩ?f“‰ώ__ώ{{’Μ«θ?Ο'JE;‘‡KΞpΐKτ–9ωpΘτ§ε?Φ΅ΩΖDGΞωΎό"_Ήφ9Y ΛΊ&M'ώ<ψW)‡αNΐίth7ώΛ΄Œ ώΧ§”Ών{₯^[}αΝU .6LΖιΡή2ϋί'tύΥΑη~ ¬ΟSoζΡκΡ‘–Ϋ(.’δ0λ|αD.eΜύωι&έ εε1τΌœ<œ\Y—d³3ΏšUՁΤ}­ΚΰνQρφγgHΖ’p*8ώ@Α8υμH[@NI¦Ωϊ@ϋϊω‘>$]§ΩfΥΟ₯ο?2Ησ!ΌsηΌ53τ&‹Ήθσδ(Ÿ­Κwΰ³»‡ZΓΙKA\θiZ>™*_ZπP?ω‘ζωΑœΨΚBΪΫ|4P6ν7 ΠΩγό2φ`Zμ₯ϋτ*ω΄ΞO?`66ΰΣβ”2Γ$loΙΌvœFΌΔώg?–ό§r]ΡώgΪ=ϊ_:Αω―JΡωU½€2Ž£‰Qν=κ.ζ…Μ‹:θV $7ΨT˜ρGXζ™ΪW³m.ƒ™2S{νnφοι KEqTΌΜ–[¬X!Λq77Yϊ2ΈϋP²ž#!“\‘ΪΎλμ?~œ}Ÿ_ΙΉs —i°2ΉIσ¨H3•ΘtU›όwχχΛ¨Xmύ;8κΜc -κκΎSΝο‹Σ+>#λ¬Ιώ7ό2πTύW£λΙΜ)χψ? bΕ£d—Υω@η\ŠmU ‘;λC”ϋZ²=^Γͺ¬@½mΒƒ%ίPkϊ^‘”ΏΖRT—ύηJ§ZΙ7O'ϋo›ώz gύώ*χοuμΏ†Νzτ?ζ”ηκόίΘ!=_HΦ„ΧΠή2ΕφxψψωS;Ι£Α?~\_Qώ7˜Σ՚Φδuό―lη-έ₯όg«ίέwξΤ­ΕJΖ›–E¬±ΌJnFwkήδZkŽ%’ß>έ|ŠHΜ‘I^b³Ρw_f•oΚ$βΌςόΝOυίFƒΏf·VΗ NWλLω_ΖΠb₯μΉ‚?U$ΰφζοΫ΄εuώ’ΤL|©¦=ΚπZΛ]!άΖqΛUγ5œrΕιΖΈuώΗ­B§ϊo£ΑΏταΌRώgJ-ΦΝ:ε7όσ„oJ\ύσ‚~nΆΎΛœΑ―e!άεόκovάξ:ΕX~Ρ1–;§ώ]Xα°¨šΒ€VΚJΒƒ9΅NΓΠ1σΏOώŸγΑ_‘«ΙΤ4z겉σ£"Œω2ΧdB χbΕγ‡y”i‘‡-εƒΙt.ύUg;“Χxπ/Cͺ―γEœnό—9ΩGα&ήκ Μfv=OώΙXπύy:'Ζ)vη8ώΣo’cΔy€ΛŸ†`NΡλVύ2εƒώΣΫΘ₯|>Ο8ωW;L„u‚Xa΄Iπ*ό? pύ·™π˜π―S’ ΐœ²ΫμΐŸΩ“ύgϊ2+4Ξ5rτή‰ΤΏ^JœΣ@~\ΆbΣȍΈ#›“=δσΣtSα‰ήži™›:F0€φΥχ{oΌ–ΩΪΛ¨9q[Ÿ7ύ;x Η¦ϊΟγΑ/Ÿν5τ?ΔκΦ€SύΧk™Έ©IΡrˆφ7RaO€σΗcιμΙώ3όUΒ΅+Φ#΄―ώηDG Mί#ωLΗ’9/φr ωY ?OoY•u·―‡N]ό‹p—Υ+&2%β±σ?Oς¨π/^Aώ7hόOμ)ίΥι[(Ρ€₯Ξυ;–ρΟXςί€ώX_μjρŸΔξζ7 cς¨ϊί)§ηšΣΚώ†œώ―,xψΕxœΟνθBŽ#ς9GπΈωΏΨ€ ώ»"‘ƒ0§ΰο8]ώϘψΏΡδΏΧχλΨq?~™βχΦΖͺ˜,x%δq.O–ύJΏ‡ Μ©σ?Έ$ώ˙꿍‡u‘ηΑΐSς₯έψobMφΏ/FώϋΒc²?Ό·ΠPeΓO—ρ>[ς©jΙO*ޏ‹‡/‘„LφŸ±ΰ―ƒ6NζtβΏLΫ™δΏθZςθ©F՞FΘoNΕ7Rψv/Ύbκγ/2@λ\6c‡Ι&Nγ"ό? p ύ·ι€ώ'\#ώΗ²{β¦ϊcΠ Ο€ /β΄ΚζK`χm²ω>œͺͺST“­ϊΐ¬ΗIό?’β?Fƒ?‹NΙ΅τΤ0¬ύδ5ύοΙaHϊςΙ€o‹@†ωθ7υμγΗ ¨₯Χ‰ψ€GΥΙώ;όα¬˜ώσ$ύ7Ίρί̜βΗ "\Ξ£°Κη @. ζEΌcς§ΛΓTωAŸ’@csμΗμ`ώu`!ΒWXίZs«…΅½] †b0>Ί€†4ΦnΜIίžMQݞΘιW‡‡KyQώsŽ—΅ŸΖ€Ÿ’%ΘΛ7³'ιWώ·lkЁώoΆΙ oιΝ]ψ_ Υv5kpαw,SμxΡrŸa"²Φ‰Ÿώ„χπ[YKμΏ6θXπΧψγjω_ »§ώ‡γLπώ_κ΅ΨƒΊAUtzLb{δό›sŠΎόͺκ󽈣Νζ₯ΪxKY²ήF Nβ‘lfLφπΝO•gΟ§Έω2βYΨ_9ϊ|ΪΗm‚r™fQιΘG§›΅LŠΉΪ7·ΨA.²hS‘@ε=4[Ιx#³Y‘Ξ–2‘τ2«π_”θšx W³eTΜΚοo Sβήή<Θ—§4 τχՎE$ό8ώ ρŸ²oΌ\ρ|£Š#!“\‘αΎλμ?~œ}YΙ9EΜΫΒΠυ 9Xς@?ϋρOίύΛΊ[xs“ζQ‘f/ψ`U›όwχχπνΥΦΏ΄ͺN<NZ_ισΥBωtDωκΜσ&Zpώ·ιTg<ϊίΜψξϊ?Η ]ωϞπψΚy₯PV u½±κώHΆ_θP‡ΊNΣΧ J'h·“˜uhYρό?ŠώMώ£+Φb¦έ­4εƒώ‹ζ2YFIiκ³,D2ϊ~”uο©PρύΫ_ ρa™Λ?GH~]b9Ε“…Η՚“ώw4ψΏ(₯Ο`ΐ)ϊOΜnώ/:ΑCʟ›t~5βϊaεΥ7ς³‰o‰4&ςϋεΰ8€Kβ™πxπίΘE”]+ώΧ°h_ώΟ ώ#ΠŸ―Νίη|‚§NΙgNqσMρŸcΒ_<\MK c=ώŸSόΗG•’μω ·Ώ-Sΰ΅”ΜΤ\Ύ’ϊ‹”·{λnjy¬·ςf%u¦t/kNR—FΗΥ³Ιλjπ/!ΧA*†Lύq–ώί²;π§&™ό?Fΰ’BfΚν·N±Ž’(ŒdV!v ‚Ι₯|.SDΆA«!%νΩ£'…\oΒH‡³@ω{^d²Ž0ξζΰYΖ_M dΘ·q1ί£m!sΩ€BN§‡Ν6Žƒτ)™‹5ΟΞνΗνe¬…ΦH΄±W#­E .I]‡“6Ηe›#Ίνφζγ.}Ηeoχ@fΡc‡žwΏ0ζη͝ά£―ƒ\ωΦGωΚƒέ5†•WΎLη°` ψ«Ϊ/x½W€ς$šBwyΒτšΩDUyΒUΜ ™{sίE4ό"ρK©θ3εq}μMΥϊ*=’ :Wy“ΕΩ+¦]`g xΘ›Ο˜ϊγRϊO™9Ρ«ΒΏ‹s¦§=ωŸ 6ω]ώΏžͺ΄1p7π 4Ϋ x ŒK&ςϊηDύmψλψΏj+ΉŒœ‚?ι©Θ¦όΧΑη#g½'&Δόρς3c²ŽaU€'ω³““Οό ώ†2 ώ»Σ Φ§TdβΎΊyϋ* ‹J1Y‘>ΚωTt oΠI?όΓ5Z“0Z.6YZZξίBNΑ_ωϊ΄ςXSύ—λγΐϋπΉ8­8ί¦JέkKΘ_’–Ύ(άΖ*Οc”GEΪ¨[μ•Z§ύ Eώv9ŠŠΥΌάΈZ³_Ϊ"^³θwΏΓωΛ`›ρX―Β\§+κΙfτέL€qι·1KΓΩεL»Ί¨Fε°z²ν₯!ΪεΊαϋΏ6I#4žwγ«σ©!τζ:ϋόΏ"\’Η"Σω_“§ζϊiΡ₯šΰmόΟ“—UϊT#[₯"έ&…Fφ- PΨ‹ΚδYΫΗ5Ίž'ς©DaXψƒ(S.€vπ§LqΊ\VnΠq»ςX΄L¬ΞCN QΛ7q(υeπ+’Χ@I ΠqέΜάwVΨe3J³‡°œ―€6μ΅νσfP£0ΆœΞ ΩΊw±ŠrεΊ+‘§¦^…ͺJ.—Hgx±£eψnoΉ”]³Eƒb©‡]§\ž$)t ίH’ΝFy‹”J³ΆένυIθ₯6;i°‡5‰Κ[έv€]ν³yEΏ­!—QZ§"šγ¦»Ε2v |DΜσh¨6υFΎίt«τ­φΆΑίF1vs«.ξΠψυΩ ·1λa%ΑŒΓΒθyφ#|}¦?] ?L”ηΫNC”–_Α-$ΡrUΔ/Γ$,l3s&©όK§γΛζd»όQΏΗ³—ϋΌwώ< Λ"βLώŸ#θyd4Žyğ/U$Η•G[Σhχθ”:Έ‘SΦ βφ{Ίψ\‹[¨ΚΟlζi8‡ ΪfdH+Sω³/`aΝ;mL³§Q«,ήθΌ…I„ύ,}JΞυx<9ώ.CΗQ Υ=½σΊŽ΄θΣϋλ"}Ž‚‹mφΐ9υ‘’8{δΐž,Τ£ChꨱJ•¨Ί»…―ƒ ε š‰•ζŒΪ=,ς†?½ΰ~š5ƒxφξh³Mž€aλ~³Σ‰~±ΫK–†­­x¬«φΫύAu5¦WŸΪ]xoΘβ5λ~fopAu/0·w~ΏλΎσεjmχο―bΫ·,CyηΨ½“|`ΤΡ%YͺΡ-£uΝu  ιΖ­S‘΅ϋΞΠα©ήΆ½φΚ}Ο¬+<3―ΐ5Χ¦0…ήξ{žφΆΡ  ζΘΘηGΫ7ήμοKχ Χ½ν’tΞσγMυ+(\5X‹KqόΈžβ,cΝπςΎωDν8/σ½¨|ΎˆΦk‚` ιγYJ²™Όο}|«TΧκμθ.;ιΣΝn'.‚†ΏXΚ‚oŸΥIόιvχψώπ›ΝnP‘Β Λ’@ιc΅f8ΖE”i[ΎΝTͺάωα…ξ}‘i…mΛ€+©EΠΏpΆxΜώ¬9Αγϊκ#iσρ\ΌVΖΌΓTύg9Ψƒ€ žηωςωΣΝJςΝ"Χ;0“Η‘ξM±BΒ‚ηˆPλζ' yw ΌΕ7°³ΏαΙΛ7ϊή±Όφ·ΫgΧ^Ψζίΰΐ·ŸpΌΒGΏ­Ÿ₯Ήz²’Ω:*ΰΑooοš ‚z0η~τjδL€R7 ƒΕA·‡υ‘Qp’ί4&ΧΔ2ΑΑ};Ϋk£TzͺΏέV+Ή7iΨ₯κ¬-ΆlΟ+ˆΧ%χJώƒμ&₯Η=‡’fηxg(ŽΗS{§ό’νΌή8Ϋδ!Αψ˜dsϋ[λΰ1Τ}}ςίΠΑ—ΙߟδΏλΓΏŸu{Χϊ?Τ2;ςΏM¬IsωίηΑπ_”ρj­y”π?ΰ1•*zψ/·:{A“¬οhxΉk'?ΤY ˜Vχ˜Ώ¦ΥƒLx"$²M€•Γό²H™SβΆPΡ.aOͺ#ΊbX+˜Ζ³g(*UM›Eά£{81鱚hUΔ+¨Υ'ΗwBΉp\Άξ̐5Θ »½ΫMT jvΧccgΗ9Βe;»νεΫdΈ– °Egε•θWΊ"ž`ώqUNπφέWφΉχςι―Ν·Ε*Ν4ϋπ],ŸgΜ"±*`-ΟαηπDy wΝΗα~—™|šύ+ ›'ΕμχΏπuσυ–pβϊ­M“_yœΞώGΗ^FΆ~Ν~ΏΤχύ₯λξ·θ8Ύ¬€Υβ™œηΫΝFKO-Ιΰg˜ζο~§ηωσl€„ίδ³Ό’JŠ1ΛΆΙΌ€£8ϋγώοY ζ™n=έυΘ«t-7ε6>*Τθ Qη«Μ«οβuωYΌ¬Ώά©σu@Z©uo΅–ΥΓmnλcσ…g«Χšό?F€?ΞΏƒθΗX7ώΫ°§ψ―λΫ΄ΐœcL)}~^­R ―Ά™œpSy»}ΰφ€Ž[VόΧ.5]ύ|[Ώ~Lύ2|}爎ί»\Cέίϊ|ύτφ§΅Σύ kέτώ²β ›|eΧΉ―›ΎνΥjγN«΄ρ­³ΥΪ»—Oh΅Υ‹ε³Ϊod_€Β~­ξZ59­Έξ°‘ ‡$k ’ώ―Ό$Λ”c―" ^Ν νΙ3ρWη>υΊwΰ—0 %χ%_ΟUΊΡ‡Xy[·|°›Ωαžxόθ²qτΆ₯I} έ5‡v0@·δ”tΰšηCδ2¦σ? ό­«AΣΏŸΞbuγL2ιFΐΗ"φΟσΩν  iΦη8*p‰?³¦ό/#ΐΏŠG+ΈΛΉŠ•βEš½«ύί έϊΟΆαLώ#ΰ­ζžεufv^ΗjίψA0‘ύ/πό_έώg°ιό\ƒήOΣ„bΐιόΏώίt¦ϊcΰd»žλςί‡Le¨!hΨ£΄~ζν‚CgλM„δ#œΔ€Kς?Ϊ“ηυΰ_ΩΚ@’kλbwλΏΠ ώWΑ*§EΛ‘SΤιTl­{{ΣqΌάCΨω… λxM‰ϊˆϊΈ:JDΌ--ζχu»ϋκΈ&zΪKd ©aΞ‡Π[“ώjψr>œBkΗŽiNϊ«ΰ:€ΰΣΝZ}©=Φof³[Dΐ9›ΫoρV³P Ύ·η<άΌ‘\sΎ­zκ)ρQ?ΣΌ§²=7•βh³yιΏ[ώ³δcη=ΨΎUΒ.]-uQ+9Ϊ/ΕQς Tα²οQ1‡Ωtζ€³DΦΉ}Ώ+ά΄^PRTη^mJi=ΡD{Ν“(μ™]&Χ°Žͺ Φ–G&GίΘeφ؝‘’7Ž:Ž<­’d½€μ½Yy–‹L­/"λϋσݍ9Ωπ‚οΝ~ήξŸgθm cƒNω#bά ίΞςtφ$g@ŠΖTττΰ‡Ÿ4?¦F‡ο‹m–Α˜UK„ ΛbΆέά5·ΑsΉ^e ¬|>C=Rϊ”ΜΤ8wΣl‘ 7£vΞO₯wλ]&cΙsyW₯θ‰ͺӐιψΟΤΙ0“‘„αΓΚ’LsϊVεή‹0˜I μϋΩSΗΠΰΐ(|ΡΐĜŽ8O5†ήK™όϋ6Κz«τIBƒo«ΧeωUxIϊΓ¬ΔΈ\θ5Ζι“^ΐ\}^ε-žš“Κωέ즙˜9ωeD9ΒNΏν^SmΫύ­d½rψ`Μ@μΨ*ΰΑΠ`”Ι „5"μfgπŽLπSJU „u°]žδ7Eω [&κy8ɞοByk:Cϊ‰Θ^πΈ,‘ΨI’ˆ_ξΚΔΝ{ƒ©ΓΛΩΝΛΩUχα[so ;hΓΧxόΔ_r<Κp2WΡr5KΆxŠ0+s‰;f€"‹όά3Λ”ΗzέΖιlγΡS#ε’48EέG―zλT1Ѝͺe ψc3 e&bžΓ:+Π«M‘₯J\Yΐ]ςςVυnφο@‘Ÿέv+Η€2ΗΥD΅εΈΰD[!υK@p_ΚAθσ¨»ω“x l@²p'υω…c½ί;¬Θ~kXhό=H‘ΐηp±]―+΄Λ»βjͺH–ugΈtίΒ’bΞ„m_CB?T#Vο<©-(%ίHdΈŸ₯[€Œ sM<Ϋ έjԐ—Π &hΘρ„ιΩώρ_·ή«ΈUΧeBŸ9@₯[•C°β4ί Ο€Q€ΚVΊΝtΞΥH-kΩVνμ(Q@‚±DYš`8ρέMΉ_ζjΏ`”PnτΎΙρLξ΄ΈX Θν˜Θh½‰%vWξ‹Hθΐ‘£:6:HL8Ψ&ΝΟΘ(ΣG?‚υ)œH%……η Ο,+œ‰~£@­ά5α œ›§j₯«†Bφ8^έ.ΖΔYž2 3€&pθo½…#νFE‰ψς2Νy±Ν…ΧΊA:ΓbΊψ―Ϊ$IΊ7r… ;L Ύ Λ’ΑρΦhc7qΣΕQQ(`οέDώŸnκόMwsώσΜ€{€φ~«¬D{ΏχR7νέΥ»οŒπΞΒ`[ζώ Žq ώ¬4,j½OΛCρ›GΔ"ΕLgT½ιs½νir £}\¬6 κ}δ3²!Ύ#…Γ`/ήπ>τ‡#B0bkύ^ňΉŒC΅eΤKzoͺ]₯ίγΈΐΛ¨ΨΝ?–F–?΄α…X}ϊYcCo‚ŸΣκ§ύ)Μ†¬SœΓ£¨fΉ"έΌ ±Ώ»γ ,-”ΎΖ„;«τmbφ_e`t:>φfΝΞΧocΫσ†SqιΘQό%Z紇—Έ[φ©‡πέτχ€ωsΩαΟz‡ν‹›―@NΕγΛ‘hΑιω¦g{TU `;νΑ:ͺ;…Ν#ΕVqϊ +φoͺίήέ΄X½jς{«₯—r₯jA€b±›ε8ͺŸ›MΫ™΄ολΨιŸJ~‚‰qY¦8ρ4Qθ “‡’pΧόΝρ―όGΫ3ΆŠ₯<”αU£λ6oŒπΤ·pŒΣHœέ“zϋPW:ΑyΑ―ίΌκDΜK₯ S­`A•G~θ 6T1κMάQ“uυ³ΒV{ΈΎώ—ΩŒΩvώwςΌΖί?jOΙ3¨ΪΨιcyWψ‡R—€™½K”ΐ€―’x­σ₯ μ:ˆ,3e$K–w{ζ)ˆ§Ά’}ͺ_5[wΫ—D8>Cθl7rεEφςߎ³ŠnέEι\ιuoo΄ΉU₯˜΄IH}'τX@…Pίp©ΝΈΰάδ°}&©c»†-l—‡6a¦0ΝΠ’Μ η"ΐ {¬Ώlυ%œ»ŠUW‡ΣzͺSΩ(MHοz‘²΅mήd/•””›R0“Ο¦†Ψ–gJβY&γu8σBΟ,‹™CΣ₯”3ΈΤ [Ž|ΕR]°«ίΰ ™·γ œ;΄ΘΊD2G„%ΫrxΐM+tL Στ<Α-Ηu-Χπ-aQ/Žς)€ ? j[vΨ»kΉ«μΘ;‰¦JγξΩΛZ.!,2Έ2¬ώΉxN3`E•ͺυΠΦλ4‰xcL[σ]]Χ“\ΈqŒΠτYθ³@X4© "τ.ί•R„^ΰϋlFNΰ‡< Vΰ’3ΏwEPQmΙ q»œ¨~―ω$Ξς2{ΨnΤ«‹LιΊΌ μ‘Φ°ί"jΛ@’ΐλmΟ(fž8²lν2,-Ίƒ/`ΰΈ’c­8Ÿ–δΆaϋDV(™’Ž"''’SΛσ 70LΓ§–ΫY؎#₯Υ»€/<Ι£9–Έ96Υn=Α@=ί-9[΅b˜4U—+ω<Γ’E΄ ]8Ž%|._qέ°ΰΩ>»Ϊ₯=£>ΠhηCυκ™ Nυ.G衳摍x|ψ»ƒΫ.q04« ™o ξpΓt=—¦/“Οπ¦¦i…!μ>ΈHΔ7Έ”SθŠ†>(Τ΅>[°1šmΠ 8ΐηψ dαΪ¦ηψΣΐ…τAN#Μ•ΞΗΒ8VŒj%œ$ιZά1iΏͺ '$ƒΦ']Πγpτ΄ΙΡ±»‘ΩpΓ&0₯’˜ <q€3gL{’IΟ飐³€jGnκ“Π1Θ#`Κ;μτΠ{ °š!€Ι€{6 0kgΤ iφaΓ³$:αr uCQΧI•"Ο0|δ «K½χψ]Β‰kΓΘ<ΰΚ,ΰψmVΨ6-J κϋ~H€[₯ΜΎΙLΟ‚Ψ,ΰ8ΟpiΐŒ_ΫΧ›ηΓrO£%ψUμœZ…€”Ω½rcΩ»₯ŒuZΣΦΝ*σψξΆ²Ϊ«Ÿq‰ΑjKtω«™‚ 5j¬‰πbžΏhΜΎWcZ³‰aB„O*}J~Aλ‹yέω2Nύj‚ωΜυΕh•Κ…‹\·ΨŽh=Ο4-άΥ±†Χͺ7Iύ#v—Gί5 R3,θW†C¬f ³mΫ&'³γ]π2Οu@§.˜§ΘpΞ΄\΅Ηβμ–rOmί΄ΙΧ°¬±Nό―IΟζ4Σͺ™>ͺ€W(θ§»0γΉΜί”-Š,ΪΜ•~RίΝ›dY7ίςGΆΦ…―,W£ήvγΞst4½ΐ’ιόug±kmς³‰ψσxΞ—Π3ίv’Σ@ΰ EΕΛ<ΜΰcΈm^1ŒΚ ί?nΚνώΌ―ΐ†’PεNŸ±¨ϊΤε1޲f(‚œ„Rh{*‰τ ·ϊΪΡ>χ0υλΆm›Ώžu=L&jzpgοπt…™{1k—bμΛ£\<Ž{δ‘τγΣΆ ½tŠΌ\ΐ‡σψΧ@Ή–΄οeS€s,>Ϋ]’&=j’šVT΄!*?ƒNcσ]vpm™Ύ ΦD;6°ΑYpΰӘ£¬ανώΝΑ­B²)Pβp›š.PΡώkrΣጹ@U=ΰΚ\L—i ύΞ!θμ(£@{ύ~/qŒ@MLKHίCXΡΗΛπ]—‘Ϋ,$ΪΊ₯αJ‘™Ω’Μp=ί@WΫ0”‚ϋ¦ "€ί*PcοΆ6κ$KΡ[λ:Ύƒλ `”€_Ά}NΕ–f`αόǐ¦gy°ΦhψwνPXV8zžΟ·α琬XΟ 4Uœ1Wυζ{Ο—„8ΎΠ΄Ψ΅άaAΘΡ­_9ŸΊΤρκ—@Ίa²Μƒ{&Pt'јIzŒ“9<Η–δά9©CσkΤπ‰Ι\šTΨ–eΫwl‚8² J1ΨΓh˜fnΰωv½ αeΒ©kGŸΤ‹Dώ½¬Lη9Δ΅‰(ˆΒ°γάSλ»φTZΟ&/ΠΆU’§9t ˜γ`^οU*Σ&οσή>ΑΆi{.ςζ&³ί° yi3jπPΑ aΑξw% ?^€}" &€‰–f`]?`)'~Πλ p:ͺι> Y%cp&φSv42yζΞlΔΧιn_ήξ‹Μ·dΰJDaZžƒ[$~Θέΐς  Τ"π βφ€A€Β“ΆaSΟ²v€.7'±³8ŸΐuέVογqJ@ξ"ž ΏΑa²n(|]s›;„†\ΐv]+πBΣu„p=j˜V›Ϋ>€κΓΔpk‘©R˜ε}›€Ώρf˜ω-ξ³Ψ λ.Β₯7‘7X^PŸPέΗ©ηέχ…ΙAh%šcFl ψ!}ƒΪ?ƒΪ£εΖ^αvΔΟΰ κ=‡­ΞΠ1‘·Θ yvΑη„Zΐ p` CΛbΆl4Σ1Mxΐ`*K”ςΉ 8V†aΘ<JΪIΏ_Ί+³ι–Ί#³¬Ό_@HΩήJΓ«ΠΑ©-aτn€1*7 ?Μցa₯>Π O x Ψ ΐ5άτ ΰ€€Ρ·ŽΝV+ωyυœ\†@ώ}+;΄rh)CbBŠξΡ@Maΐ“Ž‹"°ƒ&°όph@1Cΰ–mϊR†ΔcΤ#Ύτ©'Δ Χ“›T¬¬ƒStΧόΕ—˜(‰ŠsFχωήvWt¨c Ξτ‘mΣσί …αΐ UnZ&aK—H’€‰f‘cX™Ίk”16ίφœ‹cKΤ σl,™ςˆJΓ0—ϊW.\nΉJ1yr=a›u6ΪπQ׎cϊά6Έe JX+°˜Ε@μD―KOΆSš–ΑlN]>MαvtΝ£–cœ…[†άf}j gπm&l$‡qιΑήα“’8°°Ύm2ΣΖZ‘@Ν,ƒ4auΰœΒO*)2Άl³σŒGΧΑ>(ί‘^ΰy!χˆIA” 1Ψ•ΐ’-ιsF}W„Žk†ήΰ”ΫΒ ΜŽ"εyλ°CΜg.ΓΞ/₯ν-nΞΪ8±)Eƒ¬ηPΞƒΗ-Ϋ„Y·lΖYhy@“\ψ]f‡>3Pu!m'‚bKC½²s¦aε‘Ψw“<)7τEk ‘@ <W›3Ξ\Ο¦#y6½ .³ˆνHrθΓu\β:6ΊΗζp€%φ_e>4QΜ-Ϋρ[°†7w[.η–Ο…ά Α 0}[LΧDα½ξMx.`bœYžž`ψΪ―‹j›·ΝYΦΆ KΔjίρ”†1Σΐ™SƒψΎE€ ˜nHM |ΰ j1sqψT†ΠΘΆΘkίΊ±Λ}<Hϋ²q§z5―ΨJυ#²t;Ήν«ΆΧΛt›zζά9ήΰnρ(Θ9ά1;e­pΫΡ‡PΫ7ϐ"ڜ9°γžήΐΛΉvΘά€ς˜NkίΏ:YβιώŠώZh―αζa9ΧI'΅ΕMΐ³Φ &a–.;ΊνΑ—Ν€ΓΑŒbΨ–.LΆιΎd„GΖ,Η&0αψ* Σ ΰM„tl_ιΞRΧ–J†>4­‚Ό. ~½ ,pθ6Ζ²š@νκ?@ε\ ξ9¨κr…> Ό‹Ό`>›φbέUyήέΰZ\Ου<Χ'"΄} D0 ‡ ²³ LΛ₯Δ₯–ΜJΰrM…G lsŒβ7m ˜n{Π‰£²―C1$ptΠ;ρ|b‘„tB &χ=Έε»&'ΓάC sψFhψά’Δ€-νά¬QXζ„~wS’EMαƒτ‚u(lΑ0$ΜR["BΖ +4C;z―†" –k kšžΤζΉg°μjΟέΑ‘EΘCΈΒu@Ψ έ‰˜ ζ9aˆ™³|/t-0ύ8u©t(l9Η0= ˆ΅u^ τΡΐοή™―3 XΨF`@…ϋ°©˜šŠ4,ΰΉ‰H“€2ΠΦό Τ―ω†mς½SΠLΌd .TIΫ³ Ά’c`™g9ΞΈ*κ„θ1HΓu]KΟαΈ°q© ΰ`!ήRΕ]φEδΗΝ{ψFηΘ =7ΒΈδ.ΘPpb’η3Η§ΐ2'έΑx!Βς©&Β‘>pˁ%Ω™rτy³Šψ\ΌΏΑΪΑ€|`ρ)e’X$τ¦„3ν œμΈ§έ.“b W“F؏ρ|νŠ8ƒS8Σ΄σαώ rD=€D³«οsXΦδ}³Vψ@ν‘Iΰ‚0{μ^43|*B%;DJ[Ψ¦`Δ—p`gx,τΉi9£ˆΠ Cΐ† )uCOœ½Gv9.[‘ή‚‚gzν ʝφΜξ+βv^Τ΅j’r\aTή 8*žΒgA<wΌφή#剐Ύg‡Lrn¦tΫP1˜„S₯ u‰# ¬M'ΕφH`ΐၬ:{ZŸvR―Sωƒœcžwgη₯‹Z;R˜©Xyι†ΐήΑ.f.~ΰο ζΉ.e<αo DP O¬=ρή=Q'ΑΈ)@V ¨7—†εϊ!@…“  s¦Rϋ;˜#?„94΄©$uv-’M€-QπŸQΒθY>VΜ)ήέ©˜9h”c€ g }™ &FlaΊ!°―Ύe[މΊ[ŽIe ΨΙ U+@ BS'>θΎ‘εjΨηH˜Ά]/ EΧ7Ρά C—PΧα Γ±‘zCΐu2xέ΅δَ•ΧVΫδ²³―μ•p:Ϊδ±³(ΞΠ Έjβ,€¦a-|‡Δ²LΑΰP\CŠ ξpœ7 ·δΎ ςΚ!‚-«jΈm…ΙΠX&œΚ<ι»<†EE@™t=b„wmΛ3ΐXΈ WΒ,ΨΈ,3dΌΧS˜η+΅?1ακνž›Y}  2…α ˜ͺk>wBK8ΐΥώΣ–ŽΕ€λω6@v¦ΜEhϊ‡·^l³Xy3Ά¦ρTΡ‚[άuBn†5<ΣCΆ"΅\ Df3€IΞ"Œβ“ιYvΐ,Λr,`ϋΑ·Ÿξώ {ζa`<‰žηωςY₯SnoΰΑσΦZ€>)•‘‹ήΚ°e}TaM ŠI)έ@Xυ<8aQŽ=Τ‡˜!ˆLά~ΧLa>°₯/ή)Σ!HdMŒHr(§†rΆ X €0 Pχ=BDš %JK2ΐ[Vτ8΄™σ…|.2ήΪΕΓ§WΆBΚMŽϋΥ€ΐ˜€„„#ΰ†νίNlb€(Σdp`=i3SΫ\a;ζΑρkpε‹G™λΊ εΓΑpδ@ώΰŽe.:΄PfX Š8‘mzδzΔ΅θ‰nRΈ…Ϋ’kKšAsΊ™Hr΄Š0ƒπΠc'tc°Σ1EΟ<Γ4Ρ-€yTΪ8rΞŁRk^FlΛ§…*¨ΈΨ&™δb…Ε鎜”-¦’θJ-thέ"ρ=ΰ¬@&„γ!₯k;ΜΗω0gίήΜεΘv(`¦– ^` AΰŽgΨ6°ΪςΐzΖΟ†·ά:Ν ΙNŠXœ{>χ}A₯…ΜΞ•AT³¬tΐ`G:0+¬IΏXŽ~ΎοξSί«rV7t­Α2Uu³LΗXύΜ£δ‘q£ΰyσF™Θλψv8ΰΦώΛ€,ΈαΗγΓΞYEΕ Α OΗsmΒ<`γ01Ε „΄]Sqšφρem/aΉ<§&ίu!y‡™;ŽX8AΊΪF|ζρ‘ηžπ\`τL_€ŒιQUμ@I©+’Ύγ=΅Žˆέnyχ‰€\iy! VΓ㦏ιfύdΗ4ώφήtΉ‘$Η½RΦΏξ΅i΅ωΎ»klΕά·ΣsΞΰEχηΧ/.(R³ΞΩZpΟ(Υz6²ͺΐpM)–š”!3~ΗΒΰ ]ϊFͺ†A³g#Φςμc“Έ|Τ:  β¬ͺMD °}Ξ΅δZ³]‰NxτRΊ!5UΚ*ΠΖήaBS™œQχΨνΒ=hRJνλΐ"œL’9²‚’ςrυZ–lYqqRBžzΘΦι' š 0`Α₯MΝ9ΖΦC•n£¨υΖ¨Έ>ο;­^N&ρ|{ύFΧΟAθ–6`IsΐŠ):{‹zΟ%%ύ۝άJιKς]Be.蘌J3 pRΊηZ²’ά\4EΑ2WΠκ@£RK- €‹jU½4¨Rΐ=^αMo‘Ζu‰M.Q΅ΐαH2¬\†n2δ‹έ4α~Ǟ_?ΜGjΚeJψR.__žώzΌ~ϋlώ½Τ+Μ IΊN¦$‘@\8ώθjHtΟ8Ε&bI=( jπA$0¬k· Κτ‰M­ryj…os1j‘( ϋAw ™:&DšˆΕš;Œ‰šžŸyPώφΐo[έΠΩq~4$αγΕ₯›Mu!ΚΕ…»(υk‚‚Ι8Ή¨ΥfΆίSΚvh ›'8s%5—ΝΪίSAq'}εl˜zgΐŠHi'RVΙΊe (œœt# EW‚뒍ηŒά ‹τ^¦8Χ{pόθnρGΗ€ΣωT XΎχ ;€Δ§˜€‘rf#qΦ†uΔHαΟΩ&ψ>ΨΞ]㠍ΜΛ·νβ GŠ»αPCθ‰°Ž˜TS]7ΙζS,)‚Ι瞁CJ/΅1Μ”πœΚώ»{{ΈΏžbΊ#ηΤGžrας™ž} ρΛν—ŸŠ–¦:ΙQ5@₯†uU‰{r,χΕ3ayUIͺ²QRχdjg υ¨£Ϋ^β‹ΜςϋσzDΏ@p?ͺG])―…ιR4Τ˜φ“H^¬TρΉ;’"μ$eœ!lŸβδN ζ»Ψ‘ώiRδΣ»λAειΒ‘^C΄Α6]HrΧZΤJ›+c(ͺy[ X|jψΠ]–λe‰²8+2)§˜9ο+—,-N?lκ`ER—/ύ’}'”ΣΡI Ώ#*έλ€~14˜δbΆ^SΙ9>™΅Άυ΅uE«£ͺέ>{–Ζ)Q£ŠΨ‡JςPͺ―X60io@Ξ|Τ© |€ ‡l^WR•*ΥV¬t (ωϊ³°•Ώv'`ˆˆ|ΞπJΕoCΔΦ •”iψc€“¦¬T5U\aWS}3U1Xυά^^“―Qλ‹₯ΓF.ΆWψΥ jMΐJjŽα^SΔSJΚH1‹ΆKά ΦxΓ†Γ9·r€‡M·A‚Iωάq³Ο:Η½ζnow/\θP|Ϋq$N|"IgέΌtosψ+μΫJΚ>2v„’,Aί€ΐ€š·g‹Ιζj +‘¨“ŠZƒΐθ¬ΰαD}ήuΫηXϊCyήvϋ~€[Ÿ;ŠΒΓk?ž^οV/OCΜ†­ώfjxόΎι;e"Y θλtΠ­θ(D΄ ΰG“†›°…SŽ.Ν‘ωWWν@τ†Tm <9λΰ+;’ΰ[:Ωfl TrΒ7Ξ„ΐ'λaΨ΅ΚΊΈ4 ι7Eτσ«33Όε AόΊN=ωΰug­ƒΙΊΒuW'‰€X7γΰ·χΒ)Σ™» S W^ž^]JΊ|ίο™˜SΙώ‡Ί—\EΞψυ'θVeT°|;6’,(ίΈ€@Η ίD)|ά`k1ƒ`)h=Ν4ΏΔΎ]fΜπβχΥγ78š· ϋ Ώ,Ÿ±j|zf7Ζτκ³*²δ"UαE£œΊΓk)7ešθaΒ~,§RMM·”‰“o˜bΠυͺ•Φ_žΥΉΈΠαΌνυ*:Iα'Χκκ“8Τ6Kψ ¨άW@‹γλ‚"―RJUtΒJ‹&]XlΓν…Rο8΅ πΡΝΆΟ|sΒ»Ά³§φӍ·*FΝεaη…?"aΨςzdžwΔ~hyυ0ΐ›ZΘΨ^›3؞JuΣM„›uΤΐbΑhM1Ά‘²T>uη=ΰ!H_ nŽΙl|νŸd… ŠL†¦μ4‡jUpΎ‹ΠqυΑYiΰœ¬θ ƒ­)˜WΙMUπšŸ‹” |θŽη₯oήAΰ’„qZŒ£±…«+έ1xg-R&™λ`=\€sfΆ"ήX$.†‹σ΄=;؏dΔΛΣιΏQjai «T@α$}Ž5Γιmδ@ϊψ²bMN’™A^TΠͺκ•ΑΑUόΉZν――w_jŸŸ©‡λΧewψ€b2ΨZ₯P@ζ©;«|EΩ»$Υ–αDΟϋΨ5˜ΉFfOYn›ί»Βυ£Q`™έJjlv[9fΦR½/)YXlk’%œΨf•ˆtyaέJΓμ@ΈΏtΖ:Ο―ΥΗβΔŽςβ%y.XΉ~€Ζ6nΙΐΞΐ6Y,X„ύ¬MŸΨσΖi0oŽμΕ]FεΓΉΫωβ>σ“σχhfδœ/ΫAμ₯Γ\_k«j,ƒ§)K΅”Ξ^R+›4ΉˆXymœρΨν>·L‰ΆΝysιΨΏ_–ψ1κ9ςρLCϋ››ΓkžkdΟ$"_&-αΑξRΟk% ΤnKOΨ—FlΎ €r ͺΌ0ΥΌΉ£§v’ά±F›'gξŸΪχ[Ή]Φ.Έ7.Άζ &ΑŠφP „-ΩMΓdUο”j5ΗTLRΰ¨I7%‰ν@ Σw΅η΄»?hδ1 nρB7]s­ ’©αWY—\³ˆπΩΈ η΄ *Εlπ³υ–`£›‰Z#Ή67ΎΧηI.hWΟ½—ʝLͺΒ―ΔP|Ξ—zΎ ΣR| S‹¬²€qƒ΅z HΥΩ²β@™ΜLKυO>0;q.cŸ’λ W C qoVXχ(Ζ£ έXΞb 5w$isΨ%£5hʎ;NYŸΏ}αη—sK1ξ~(“Xcq}Ίn\ΐΙΞ‰f"6‚ΥY{ lMΦ§±I| ψHεΠ΅pC—§΅£rΎάΛΜ Y2η]ΠΦ@s”¨Όχ‹tμξ©ΐ>©ά₯'ΉΚ³λ E.l­ΨαΘ`†teψd½šκ\·<*P‚~#ϊ  9`4&+Q+(1I{2p0Φ¦•œ ‚†dΆ’f‡π|Ώk‘.}ΉmYdŠ.FH‰ι‰’’\KU+έ• UŽ=‹ΐ|ΧΙζΔKΉX₯Ω§ΜΆέπ.oEY‚εβ N"J‡ΞX†'Ν&CΗΡ½8K(μ*\ k’‹TŽη>ίυνoΕ)|γΗΛ•Φ%NΥ žyτΒήgΎα!^ŽYηi½}iSυΕΛWZΒφg ₯υήηbα Ί(R€sj¬`±ΑγΌΘ ”hD!ΜΪPΨLΟνgnρTfξη,όρŸoœΙ|7«^Ό[Κ€RΗCnt½·°Ζ±UD8ό™{Ά6k₯“’υ;ΆY65ΓΔΝt!πχ$"aεΤ(ΗΖlρξc] €Ό΅Ι…LŽ,‹B· Ήˆ 2Xh*M*ξ υ9$ψ"P‘’ζΩNοΥk·‹ p°fTqΔqΌ#(š΄!Μ:Η ]4Θͺ‚SeiηF `ιk†ΖRΝΙ=Ѝ%γ,½ΙbυΕDί”Ψ\š-νqΒ£‘:θJ­5R‘"’² ΔXx¦ebJrSίE ϊu ΡΊατžΪyαιΉόχ;ί Rw¨‚ϊά†€ϊττ}Lο‘&ŠvΙξKΰ°ΩžSSΖDu­•.QšΎ³@0C‘‘–kώŒIκŠg"ζEz’Κ0θέάΌ»—§Η§ύ4½ƒv!³Y;ug&³JΠcνYήοοιι―Η›&–p§cρ—ΪzlR4X+μΛ1·Βευύ…RύσJ6cκ±8][„³"χœ½Κ€δ-"WJ”†α™»mJGM9υΰA’Φ‘Ž—zπP“™Όzζ—~Oςψv#jZG˜‡ώΎΓτI§Ÿ?Ή›«aχΨςδήJ9„Ν••’$EΟHΗΓjŠ%̞qΎ'W:X€΄υd”!ΩŚBΉͺμv’―έI9PΔδkŽŠ`ιΨί+ γ”ˆΊι¦uσ:€Μ[ΪΈ/˜„^[ _Hϋl€~λς‹w:Ξ©*X‹ηI%ΫΘفτΥ3θ_1ΒWEF΄Ή›d(θTΕ F'RšgΗχς―Ž΅‚I*°Η νΪƒρΤζ%YW <­ [8Θς›W—gΑωΎšΘ[w‹«yϋμΌςΙ₯AŽ `Œc™XΔ[[ˆEb9"Ω0Gέv‹JZšš·6'?ΆC돎q+ͺOOEb%|ΐš¦{hΰψπYXXΕNi ŸΦ³χΑβˆgΌά3‹υ₯Rt‹3g˜ξ7LθχΤ‘?Œ΄;jμK—ο€Q{aGίȚl ά"‰=W$‹³JVgLkα@i|J€ Η;ϊ} €ΥΚ=Ύmk NΥΞΏrη]Ό¬*wιΕ)‚UTDš)ξτQΠj-w\ξΦ%ge(μΐ΅Ψ 6ϊKUΑ«—Υ™ƒίFΎp³ι€Ξνβέ²…©―?Φ… ζ¬+Β9Ή<8s'a' myΆχsΣ~¨,?ΈέŽc§€ιŽοοoψ΅•g>ΌM+yΖΨ–ΎΚ`ψrμρ`tΰfuP.έ›\²‰'©œ‘"IWl·±ŽD΅λž…ωψΉ ηz_» ©ν8Y΅(<°‰-­Š€c##χ/·ΞˆώxΚ™‹--[θΎVΠ>τ¨{|γoךnωKGρU‘1ςΰ&„3δΦ.»Ž’«α;(e‡[o!€|g…Εa*β·£―'kΛΞΑ);ο‘κΕus%π±Šέ%†SNƒVΎˆdti6_£1„-Š…e“a’ΰ‘uΐ2½S˜Iε;‰ ?+tΖ&Otχvυ[X‘Κs„έMΕΙνΈ(cuP ž)#t±ι”p ΎwUΓ–γ₯ω…«ζΟlŒΓ ΪΕ}ΫΔ;-Ε* +©5YX˜0h"¦1²&ϋ”MbhMΗ,žΘ;γ„vc†#Λ΅ΈΈJ² S9ί΅Υΐ“θ81ϋ ’lUN9™β]‹Ω‰Τ |mn—aωΝŒ+R±JŸT‡ΟΙ*ΑεlΏZœe¬OEδ;«yπ8ΡΨrYz€’Ÿ?^=Α66¬@νΒmxΈκt¦λ‚ΣAψ&ωΜ©ΉθMβΒΒ„5u!ΐM³KΉ5—Ύ„dd#°Ό€¨jaΙ ‘•ξ n’{b’”$ C’*š™ˆw:›½€qjͺ8$~Ϊ|Θž3ΘΧΧϋρ]©]:μ4©μ•τ"fγΓ°ͺΡ)'έζ €€7p’4c‘•Q:E’δγ™dΥ½¬‹Q_Γύ6p{Μ`?m?πψTmdE―­1(ς-Φ1HύpΆN‹+­E‚ΡV —&_ΑUDηή'έΚαw4q–ΔΡAΌͺNhΙ(ω—ς”υύςZΡFG ϊμtΐBƒŠγkυ’ΉmœΣ`#Ζяδ‹Χ)—’cσ½ο>ŸZrb­Ζ‰3ω_ay%ИUd¨G'9SΚ•‡²( wKZIΈ1ΐQhΛ @P*Ύ½T h:‰γ“hvρςΤΝ§z½—Ÿ«Γ2ŠYς!„Γ…‹\£Θs(““ !YM"5eΐ‘!§¨JγΞ’Μύ|z{~»ύσM˕镏‘·"η +>5_€‹X§^ΰŽ¨Ήΐ Š΅WΊqΟZDN+IˆωKžG^aΊ•Ή·f΄LKG ¬‰I$­>ADΘŽ*KˆWΔ©ŒœΰR‹tzΔχΩ±–­γKΗtFΩRΠόαؐWνΆΤ§—·s΅M>ΠύDΤi&ρQ~t”C­εύ«DΏνY€’iψƒGλ †οΪϊ9'Ν ^5β¨*ψeν’θ!FπYΣmΆΙJΌΠ• ƒf[α€t"gj8·πn­;(¨ϋ, ;}n>ο^G°‹Λ{PŒΞ•¦LΖq70b'πΤ1X@†έρ-*„hγ‘τhŒEΟΥUo΅qΦΣ±Ιη>ΈVΎ=Ξ\Gο<”©±‹ΧΒΒΈŸDηΑμ:ψΓήB•φ·e:XG6ˆ9: mDν₯ƞ٣zofζϋUο„bΟΩ/owΎόκ2u)bZΐπ .Ψ=HR ΈΟ"dn\―=ΐšR”}ΣΌ )uΫDE{Ξ6–½z«\«•Vpλ’υbΑ ΕUγ_Ϊ:‘‘‡z ‘ 51₯βΩ„ -ΈΌ{šm’ztζ χ₯δΐ~ƒΣπk-u `¨τΝκl²Ι€gz_Ίd;υ˜2·qΒO’Δσ¬αωqŒr=½$ύ•©{*¦‹qu,€&›š•θs{Q©φ"ϋ§”τ&i6`Kqρ^ϊu|EΙfπ>\"»ψM~w œ˜³‘!%y£wbjEοjP"…½Q‡$€a]²pΓ)Λ~:–ϊήθζνeΕΗΗ6uk]˜p„ta,΅ ΐxKP’·'χΣ€ΐΰΒURΞrRr±³;6K―!S MC‘}}υ‘ITy;Φ,λΰ}Χ^לk’L`iq_“t”R!` ψŽ’VΒ &RΏΨb―Β‡.ͺ ΅Ζ'ύΐoεW’>?δΪ“α]mpΚuγ’bNCΡ£δ_š˜‰Αš$τ`”ΰ;Α%Lj%ΌφA3Ι CžΨώλ]ΉΡ¬EꎌϋνΫKyΎ…Ό–ΆY.D°BΨ₯ƒFs€’eΒήΖdʐtŒkL޳hR(κ4γθ«LuυΆΨΉ)˜ο]£εK΄{ ΪXιY"αk»Γ©7Ν'8Dδ€A'}πΰ³K{—YΟ₯άυ[¬θϊβ|~p)ώΧd«~1hx‰σc›*² Οd}ΓΏeΨF‹\¦σ.Š^–’°rjδ$Lς° `Χ|?μicv ²‰rK™B7d|R Ά}ž0Άn ’ΨTvHΗnV$=V½ §Wχ€ υζWΎΦ f8ΥΜ؞!N0γk€δγδ†>θEj'Νί€YgΚΨψΫ»OŸέΧΥ³dΒ+·uΚ<ΔμK‡E–,Ηα‘›ƒk–2©―ib°\lubΥD\/Ζͺm‡2Eδ`Ω’™λcπΩάσΪI©&XΤΤ΄Χ@ΆΰρΩΚϊh«]Π"ξ%Oπ΄‘cσ'Ρ].X£–‰gIΗg°qΤCdιͺVΝΖ;ιiΠρΨΦ Ί€Ό`ρ…Υ’h†/ΐ5΅J0*Κ΄ά²μ‘«ΖτžξŸWο― ίV<ψ‘Yg―<@ŽržlŽηBtΤjΒ†ιŒΈ$G"e.šŒ-Ƙ%}`:ώMε­τ—MΜδ#v²›V>w”žސ4[;8DK/ ±QΪ'$Εƒ­ Ύ-κzΉ›3ψASVZNWv ΈλEΒΕaΰͺxMž««~a «½Ώm4^.ŠMh“ε.’O½‚nΙr#-_’/Άˆ£H{Uΰ:ΉR­nσγx{ϋy[^_ωEtδGΕΟΛ3x ,φr¬+ŽΌ/ „Η%—’B#Ž’6Ή©X“8©‡χ-RŽqFfϊuu+}yΨ΄Z"œ[·-~Α/lzρν†οηχθzf>―žR›M€Ή©Ωc₯a1S͜؁“dΓμ€ρ₯ŏMΟYbΑ3Φ+ΨΦi,~DΘsvΰ"xΧn$‘)°τνπYΊ'ΨP +kl˜XιΞŒΟExvίΰ+^(d¦¨I]βtcί£e?£Μςk'B’Θ!eΥ{N Na ¬Y8’ΤΊ$πjΤ­(P―μ΅05τ5Ν«™ξ‡£Έ)ooη%ɟ-s?ύ'=[EWΙ#‡Ρ‘Ϋ–“t©@ΩΊ @όj0M1ϋ(bχΞ«xVW­—rϊ³u8'—ΟŐ‘;"©KΛQνR€)7΄bγ}aίl#Ή‘<Εήu©M4γEA§htΏφnŒύ?NŽcΣ»ύπ„/žήRΒKLHˆj‘D,ΈΝ jθH'+VZΈ›Υ$Κt!UR’2NČΥ–ή“š\ƒ/F)G΅Β“ŠQΑx)Ψ¬ΪD|Ήc4ΐŠ gS}–B¦*¦Ά“ϋ±’γϋξvζ™—λ–έσŸΦχoΟϋΠM ΐΡΛΔΉ?ωϊp}ρFζ΄;›Œ€bΑΐJΕh’‹Ϊ”j 4OκΙWφ―š2ͺΖΔ!_œα±_Ό:ͺ#1‹k“Ω ΙfŽtŠ>K+LηΨU}”ŒηKρXX‚—^ΖC€F­Ή°ε^φNϊNbλI‘Λ£±<ο] ˾γ$=Βg°° ς Γή[ γΠΩ^’…-Œ>Ĝkˆ 6ˆ`.OOΔeƒό)GψκšWœζ%³J‘hχΐTƒ“šββ3]eUEΨ1ψκCŠ{“f{6КΊΣνΐ†.ŸΔZδΊ+;MΙτ‚3ιA»΄¨ †¨I™( ,3ΧTρ£βlt]Z½Β£]8„k(,Ψ$ωM•ΗΠαœr5t–Τs€A-<ΕλU°ΏΣΐxH* ζ‡πΘ7νΆέΏΏ~ηŸW-)!A{ŠZ.}Z"Jƒψ!–ΓΦU-ŠtΑΒτ2[η€PmΒ8Ίσ³γxzWΕΕUoΌδ΄EnuΐˆlNƒ%šͺLZ77υI$ wI³?)ΊΫx<œ9ν/₯ρψ†Κ-―EΒΝpς-zκdu C?ͺ^2ΏΙ΄`η€CBU­ƒUPn 9#Su«ςpΨΝ`ZβaΫρuΔc:/χ―7―Οεq'TžoΦ•lΫŠρΛ·kΊ=υS‰2α½Ό·!qgκ-ΓٟόΙsyyε©Όςλλκiς)7O?»FIYqqKJγ‘ΙΑΎΈZaόZ’¬§\ άΏsΎNŒ~°Ϊj€Ξ”{³>Tο©ι»ηέ²E-²…ϋ™,C΄;© ΚΝρjwm§ψqxεΉ}»hΦβF ΖΛGΜ,²σNξ)s&ΐζZkE:U ’|iR–€ώŠpœ¦•§γ•Άϋdw‡Ύ™ °;iΓ’Ωωΐ‘½_Ό“—k’#—Ήεh₯saνΡψΪ-Œ’§‚(νDιQύ ³ 7™t–&3Σ&σ3Œ;½W.ψςoΰΰh½tΆjYΊΗw£½•šU΄‹5Gή‹† Τ>4'έ‹«=JΗŠ.xψ—95πqJάςάYU8@“Q$x¨X©‘+$K"‘€ƒδ)κξCΡοJ=Iφs€σΉδ^‘PΞy`KRižb`Crφ₯d(bοF§9Q3ήƒ±SΕ€Ge3@NԜ<Βwνκι{’³ΫίeΓ-ύ1Iz!ΛvxzιfΟ[)βΜr£Bΐθ!SΪN‡/;―wΧΧ„΅ΐΡ,:¨‘8:Μyǁ4„–rεQ0δUi9Dθ*eΊk$Vzr”§§8±kkϋθP†ΐV X$ŒΑφH$’&­TU€D₯bάX^“[tͺsbμq—tX`1.έ­ϊΫΥ7n„sDoI9‰4’‡1*IΔ(ΦFΞxΈσΧΜxΕΈs΅RΥͺNΧT}τ†&ώοχ ϋΪ6Χ܌ςDψΞ{‹¨—?Φ€‰YT„fJ_@‹Αͺ•i ~Ζ‰g­ΩΧLN°ΝͺEL6ψΜtLMΑηkxeτΪΆφV(πHαΉ9ΫΛΨΩϊεSl“νpΘ6c&€ ΅4RS.b#ΐν²SMξ<Θ*°m²½Ÿ’ςGGωώ:–‡]ήπy+m0’$³5·Lά Ly†‡)λΗΞa;ΙΩ’(Ό7!&`± ͺv&[̎]Δ#χ„_ώFWΕ’‚wΚ’HzώHΐO„8%ƒΑ4MI±–ΰϊr*xςΕ‚†)‘»'9Ξεu΅Q:lσϊσρ­ό81ψOYέΡ΅Λβ «(Ϊ^“dzΥ caD³ΤˆŒ;³εφIήP½ ΥΰΑ4€μ{όˆ6πyCέΌkΔ3όβ :Glτ”€}ƒ73χΪ„έ W[ρZcί«–“Υ%ŠN«ˆIX©LKΉώcnOo|#šSSm$7iy'u¦mρ±_έi¨~νζ&Ψρ€±υΌ?€«,0’&zžL ΧΞUBΉ8FE€ο-•—€Ξψ₯Φ—ΓΆv›ΖH'ΊΤ——oOŸ_}φ{Ύ’ς% ωΗΠUk“gtΏz~ώy+­V^άU»+|?•…4h(Nάδ$ΰ‹§zΨGρI²³ά}vψΨ~χ©M°γΑ‡qU"3°³ΰύ˜u+`ŽI<ΎΤ‰Kγ·8¬Ψi•˜ιD29ς#C—XΟΩ―Ω~¬»έ‰w_ίΩΑ}jGkvΖÏρρœ‚ύ‡σ\[8SŸ=k_>·ΧφδΑ°4Χφ„²{°Ή$}·)ΡkθQc— ϊ$%EΧ€A’½P˜ι^BpVZυ²k)Μ7ν:>81₯W/Μ`W}¬ΖWgqΘ³Τ'©Ρν&Αα—.I½‘Až}NΤΈAK8>-U8ί9™±+%ΰεΧ•Œ”ZΟ亝q­{ZΖtβBωϊΣαJρl]%E`ΞBe£‹’Α+=!ΑdR*!*ξ5Χb«δ q0,ς <Σk|ο:ώς+ουcNόΰžπΛΤ†ά†Χι»π—UΉ_ύΝGnΓ„ @Ξ›ΤΙ_°PΫ+ώλ―—*5‡Τ՝\&Tι6έbn%)Ÿ7Α§(±‡˜’Ž Ϋ6΄lŒθff΄!ο©T†ΩΊt‚—όϊ³ΤK‘jŸΐ8λ֐deYeƒ‹&ϊrθQεj)GLf(Ψ|χλ[užfR/`ΫM2₯Ά«K3Šκ₯C+7Ϊό?ΞϋŸ|\Λο++k„q0γC₯ρŸ«Ώ/:]—’ζλowΘηχŸ mο€FΧϋjpΏδq·/OΗΤβcΏΑŒ'³g~ƒ[Χ―Eη&NŠΨXΆ˜ά¬o–“¨w€X¨Eœv8³wΨw±Ξ„ΜŸ@9ψζυ¨’7ˆ²|=™H`)ζ½Ώ^ÈJ 9ώρέφ7vp›ώ׊ήξΎ²€‹Œο7¬iŽ$ ¦„υ 5USu.ΒV₯©ccώQτMt±©†¦}£ΤΙ›j]ύ2TΈ,gλ`vΦΡ‚ί0;˜˜Π΅( ͺμ\/©Ϋ ξΖΦδr‰ σΖ ΰήEΡ/ρsš₯¬©.γ¬ρ|X²ίΰZVΝkνmk>™ΤδκΗ 2‘ _š«¨hm@;e²π½ΛΊ·σ΄ωΓWM#›±[•Ξ™ LP­©U‰Mζ›α2\Z9dM’ΌGΊzB6§]ΰ—ΜΗy»x τ?IΕ›¬€+kV’ͺM¦Q ιοΧ#6φƒ§Ω9ŽΡi Ό@䕃όυΒ—YΓ|ύAFU]e¬ΉJ)Ι'>ζ€η0£6R)-{ΕόW$θ‡–+`~Bžaν~Υ ΌώV^Ύm4K.…­›'ω –Η.ΕξΕ’ψβeɐΕY4*J#ί₯l΄Χθΐ\™Ξ°G>…™¦Ψ§Λ$ρߏ₯8{RΦIΗΏΑ― %o H§&UE?•A’W.—u ΅d‹©’‘μt΅Κc–b3wςΗxιοΟίή™KˆξιΤξY2ϋi˜Ÿ^δ •·ΥΣωΘβσψύ4 SΫgiK,•NuΘu5ΩeT*Ύ`{΄¦δΊeαΓNzqyU=“Y°ΗΈ.Ηlgώϊƒ§Z”Z‰.wι‘Mpΰΰ Ί΅Ψ΅πζ½ob³ Ο8πŒβC© 3¦MN—UΓν]Œ-fΕΏ΄λ·Ψυw—ε\Ζ(Ξ~%ΨœαD’-8ŽΕWγ_’Αεp"$Ω&hWBEα`h)MΆ"P»η`ΞzγNm‹—mcΑΨήΉ‹ψڞž™nήξ_χ΄Χς&κŒοΝIΞyήbnφΑoπͺ3KΡ.,\‘dΐε—ΨK…—c£2Ψ₯”εEΥ{Κ`Ÿ«šz/*Φμ/G Ξ;R—# ςΕ›3sW–€„–φ €t/βN\ΓT§β4c5ͺ)©αpι:xn…oκΝ:s՞¬;±ΆƒKW Ώ„)E2UΎΜ]"ύΰμΔΐ(i .9.Έjg\Žά0 Zϊ΄°9JΚκρΜbόυ~Ω¨λέΎΎξXš[’«έM|iυύϛÃ:ψGγί½WKsξΖ-GZ[Kg˜R€€3έSνβΞuγˆC­`+ΎDS“• γ¬­σ“mtR έΊ3iρ§’lΗqΨΣ3q3QΨr…ιΘNZHK9†ΥK]„'ρί°½Έΐπ5νN!φΠΨi²J.;p2©¦™ΐ‘„Ϋυζ‡Γ΅kP\©E$Ξ’ :JΩ HU ˜’tOΐ‘‘ςC )³mž|γYΙΉωζ^ϋΚω„>ΏΟό‰΄ξُ?gοξΊh„œωαGεD&s³ ΐΥρAυη?½ΠΆυλμ΅Π§NͺώύaΞζIόTρκLΖΡανΛ†ώd_„Ώ-Ούώ©œΫDb‚œIΈ&ςNΉŠ_Έm]²Ÿ9˜0κ=ςωˆšΒNΏt;=Δ-ξŸώΒΗ>~»h6ΐύ>œ ‡™‡Cx{·z92M£θΖGΫ₯f_”gΡ΅ιΧΌΞ—Ϊ4#ϊη81φ՞Ήώ‹t“ΝωψΆg›Χδƒ~χxύωPŸξo‡c³©ž8πΣω['φΗ‡ŸΊΨ#~{ύFoΏeI/s}γ₯;ΣχΝ.ίξοΜ9–·y€]ίi’ΧL†Ό,Aqκœ<ŒΧΏ5Ρq=seΆγSχι\42νσΎ‚,‡Ί”οŸ9|7~ΐΥ#όB/mε¬ί.΄š# t4}»zxήβkω“oχΛ—¬?Ÿ·u‘»bσυΝλ{}m/«Ίέ@›—ί^˜/Ψ8»k1±{NύζΩΖΰŒ Φ#;fβΪχΒΨΙU“R·Pϋ‘:"ρ£ ‡π¬i‡ .Ϊμ_αS©Ύ_‰žΟΙ§gO‰Ι$ΥΣΏ&fνΌ‘=Ρέ<–™ρxε/τfΧ y;ζ{aΚΌο&ζžϊθΓνς3Ÿξ ^σ’:ƒ0œŒΎœ†˜žΤ3ΧqœΘ|&&=<½<ίνo¨qΈξ`Ξ§aλ3ΘBi?G,σΰm˜§§ϋ?ω· .ΡnΑρνΊΑΫ$^>'q.ΆΧ ΜWBcοHλΌ·mGΠσKΦ;θΜΫ¨.Κ²«Ηά5Τ…ΑIv5VΎVœ γΏr{Y StraΖ%—Α”ωΙώ%ΰuόΉ/ž‹Ί½γϋηm~Bۍύ3“·sηcΡb„O+{‘»;Š’―zίrVγ? 5&‚ωηΚΝƒ}%€WξΏίlζf2š;y«ΉFά’±ώ‘ ³Qύc-Μr ˌƒΓ—άό’½ψ2u΄t΅σιKo7Οσ(ϊ n.2šΏmA~с]ΟS}u²?Ξ›οΙσtxv¦ »|+O KϋPϋΜώ`Ox>μφmh^y"ΟΞ:ΌAώ5ͺrα4_zΕτ?jο2  ηοΪλξΠq‰εEY‰Ώ;Cκ¬H׊χ Γ%«?zΘ3bΏeώ€_'Σ¬~1‚ΥΔΒέ`ΔΧ'χΔ©ύB ζkY{Ϋ Κ/l“…ΠΛ Σ|œeκΞρθ<μ„ŽΞ›Š©T¬3BΏ1v»ŒCΌhώ6μLπ6™η0=‡GρσΠ―εΛ.δA·Μ―ϋΠ“IπsΡοߚΖyb)~Ε~mβχ#Ξ4‘³ Ί ΰ™3/'έζ±9:D>s–&•ŽΔ}w³£FΗμάR—)ƒωΏy\"`I{r*GςΧs@Ύ \&Tsgβ‰βω‘E9ΏvθTΒΩ•λαGχ8gϊͺmοΰ£yΧηάσ]υβθuBΰJEb&6ωψςSύ°Ύό‹‹ΆΦh<‰\\ξ₯6—υ‹I±ϋ’sσ\Ί'­€ΫσΠwΓR/ΝCχΞ1ΗζύΟγφ_ΟžΉG[ΰP|ΕιoξhΟ4”CΘ'ϊΈw°ώζπϊω‹Λπ«±ήΣάιK³΅½ΐώMΑ¬Ξ/K³~9‘|{»πŸ6¦'ςμ’Όίy[qΦ΅α¨φξ .rΖ­β‚v»Ι_9,›5 R,ίΊ€:•bσΊΉ Ύ΄Š8U9ˆ’oL¦Χ^­6¬»#o‡z ζ™Φ" !˜Pν³zd€Λ74«½¨ξEW/αTŽδz†ΥΆj_“-ΙpΉTγ£τ‘W>+Κ^ΦlΗF*rφψ@ι©}%eπ0ΏfκήεaυΈκ«Νζ~ΏΏ§§ΏoΪCyωώΗΊ%ΔΔeΧAςοFΨάNγ σDφsψ₯|1}ψΤν>Ϋy‰6‘Ωό™·;~˜ώΗ +rέ€Sͺ!}υγκΝ€»i^Υθj‘FΔ5uiΰΧK²Ζ6vNΥμM =±«Αqν”’nAεMTŽOυάΪφψΈ|!Ζ£ΏF³SUYyιΧ=wΧ]Τ:“tθ°ƒΑ†Z₯Ν-Ύα+%/]π,ζ(ΗnMΉβθήnΪΣc_}»•δ‘΅γšb"—e}>ΗΟ3`Ϋ(λ ΥΪΏlΌ€Ψεs:D ¦=½o<ς¨λZΪh±4­ϊ¨[₯ΥΛDO‘°ω­έˆΝΊiΧΘT¦‘£F4Ζq¦-ΩτΪ7–ήΑσ}”α OΎŽQΌέ­^μsΠμ#aοېwϋ.ΖΥ:›WnfΫΣˊOh6My[ρ^K7V ΊΪ¬2EŸp|‹ΉK.Z ‡–΅)$ϊ΅ΞΈDΡύ΄ΝψΦ©δ’Rš3Έ?ί―ώθQ“UšœΞ–”Υ₯αι{d‹/ŒΦ!•μ£(θμuΡ^ΗR‹±V’§0GΚ_ρί›ΑS ,­ήo{Σ0e₯”\;Β°βaΡσ―°χ2ΐΊͺDσάQ¬_†dcΚJyeŽ4fάφ²›Ωa―Ϋֈ£₯yiεΘ|-πFΝXΗƜy;gW\‹œ©DkI·Lλ}ζŽPn©Ά8έ ζΠ:œΚά‰@Nˆc-+WBΙ&+œx(Υu~+φ^‚‘0όΪαΞ(x­^} Τb'OΕΉΤζ4 ‡|{//tu72@Φͺ²ž³ιΚΉG₯ΈT£D>bΙpL’MͺW£j)1΅Ή Ϋ€ζ›ώ‚WΔnοδ* tτΨwXŠδ“ΒlKΛΨ°ζ1ΈR›/‘ιŽγΦS’j@¬νΪv&€ςι‘α―Γ_§ν?xνC)ν#Ιw<›χόϋά™ήνΩλ9ΧLž…†•¨17kΒp-[Λ=E§œcΥ,Œ«‰¬a– ElgφVkV*οΘδΜΞΐΓΈ†bM‘₯©‚i:… σΠ]GΤϊž±[t©42ήΑdaλΓ[š ξY0Κaž7C@tέ|NΣΥqrΘzωΣήαBKΧΚΐακN%Υ:ˆΓΐ+ «dΘXkό'v1§$νΖC gY« ¬»|ΠkΖΎ΄v;\nσ‘Y(B4”lφ-°λpͺέYΧ›$}t‚I1ΐμQ)JΑ:+j₯ςWΪ@ξMΙΑ²ΖΕWΥ¦T4uγ-7 4Ι=΄hl†“Εω΅*kW±άΤ½ YϊT ½§ξ±ΰφ—bXγ…υ~U•ηφ5φΜβ&x ˝ƒn½N@§ΌΠW§B(@6†DJZ#:­ϋ4z^Ghf—IVρpκΕϋ™{Ÿ΄žuρEd΄΅6­Πyξ½Uk€-©RM‘k@1Tτ ωY­gz<τG>6Δν»?ͺ2@B1΅ϊd”­:VωΠ ‹ϋ₯d"OT­΄H°A›Vΐϊ@_ͺΦ9:τmΏθ‘nχξ€™±]IΓmΒq–dpώˆ£φΩI΄^¦ƒΉxXΰ–tWUβ@₯AcLš™ω ΅#ϊ΅4΄‡-l*R΄…+π0¦IΓCd „˜X$Έα@œsZu8“Z4 „ΨXκΕ‡šύιL’ΥΫΣζtςŸηŽώ…ŸΗU‘Ks7Cπ~1θX•Χp$ζ*€lžΦΐ‡tπ·ΒΨιͺ³)€œΤ{έbXt[KFΕ¨ΑπΫΉGʎ` œ‡³κ`Ψ]KΣ.xŽFb„-H9e³ σ…miz;Χϋ§φύ¦ΎχΎGvGϊ3=Δƒ6ν¨ΛwΎy]=¬³ΝžžΛΏσ q}6t·—MΞς-Λ΅xM0χZ `VXDŒΪ…ΰEΰXm±ήFp>G@Ρ>λ£:grΆΧ½<ŸίWtS%Έ½7{Ϋί8˜/{μ²gHΗΉφt™l­‰ζΏD.&t_ο}₯B©VηBν’FRaqΤ’eL1&πό©ιQΣ›C7―χ₯Ž£)KGΌr‹:γF…zŽ.«žTqΎ΄ήrfίΪ8όΑΠΦ ƒΛšˆŸ³vlΟ¦Μ“οοoψ΅•ηqΓ‹₯!ƒσUž]§^²6!΄“Š.2˜ž±% –­½€CL©9ΓΑYE0>:Ή>‡^οξδ@rή-΅Iπ Ε‘Iؚθœ-ΝhΧ€ξ:|>μAΆ 8η«§²©ΕΩ¦“―@-εώζξιιϋΝφ)Ζb7ω-`‹jA"&žK+\Π |@ΞAy•f"₯N\ΎͺQ€ιΥ¨R;Οm΄Υ³ΘβθΕnΤ₯htpΖ6ŽpΛΉRΆ.( ±ͺ–X_…/οΩηάjλ¦œ=λIπύ³ υ7ΜA»{όώ:ΊsKGο=OB΄m₯Α©fι=ΦΊ·0 b#*|’€8uUΦJ{|KFΕΉΨ¦[ΙOόψύαΘzνž[~j­+|ƒ4gp‡.}““w₯«@όZΆB+°’ 6#NΩ ά‰Ή™»€ψΈί?GΛΣqι•VAΏ­/ΞMγyU+ΰΏ5¬δ―΅Β8tͺΞIΫ€Q9–*Ο=ΏTďά(ΏD kαKjSμT1­Ωvβͺ+7ΉsIΠ³ItXI3Hίb4Λ_Νof΄uw™Αw/‰'7ΨςΔΫY§LQ1k_ˆ²s!z*£qπαx|ŽΛ/΄BΗυN^<Œε5mφβΧRΧΪDjb$'ΐJbΒJ*‘€ηJq@(‘{•Kφΐ«°Ϋΐ‘ΐ Ν†~6Š #ˆ³΄IΛ*ƒ${α:ΑΩ½θ΅₯μαIΦ:ZλwΝψL­€GΫOΤruΣaηΆ Χn/&όϊpζ‚ž«€­υbξ·9€Ϋ4“pt²ΧGΉέ?|ώvzy+«7―ί~ά”Ί^‡Y_žώZί?ά‰‚δΫΗ?ΥiW«ΏoŸ~¬6χί{Ϊӏ«v[*>|ηϋχGΜm»Ότ‰faΒrϋ9τ˜.lώ·νίΩωΔΏΚλρiήώήΨ<«ΊazV„Ε¦z }­ v½Ύ΅‚½<’βjqϊ3 ΤΘ Ύvxϊμη₯α,h¦dΗ±Ρ¦φJ:y]‘‹q•ΚY—ͺόΧν@°^€ύξΔ”­wΓ]ΏήΓΫΝΑ2Ωοoΐ=’Ζ§"5;Σ΅UKϋ ™T%φ¬3S"Px§.x!tΦΦTSμˆάΜΖε<ά[h·ζ™x2&Ο/›^nΣ3Τ923Ο7ερu΅‘[“Yn˚\ 6Δΐ¦Tιl¦20pN†¨ΑOZ ά†ήeIΑ–bϊ-XsΓέΦμŽΩ^œΠœ8X‰VΫ€UO©0e,ΎΣδhO>]΅ΦΝ i5Ž,œ«9Ϊ|‚Υκπ1=ύκΓ€ΏyεαιOπσΥΛνφ₯S π ώeTrz…ΐόSΙ°†€bžBRχΗ6Eο €1m—3Β±­aΣΉuʍ³-ΨSΣ±ΧώώΆNΤΖYŸ†·~“Ž φ₯&^‘»ΈVA˜€d\R-Εlc2€0Ό‡€%K¦·¨£/δB“Μ«0˜ΛX$­rZΰώ©ώUξΏOηm™Ž|ρ™1±›_~YA€δ‹’½Ko‰¦R°ΕΒ³sT=h 0˜₯ZΓ¬0-tm `G+ίΩ)Σ‚ξTΓ»Έ MΞΣGΚώι?βς‘ζ3υTZφ”CοYn›uβ%θ¨:¬yJ”UŠ£½hWπ…g¦ΪuŸβΝ#ψ, άfן;ξuŽΓΜ[³xNdΓΐέ+Ή,격…’J©TS‰Ωεΰ3\d^–Vκΐ &PJXwχυ|πmΧ‘k_`κ¨BεP}pCυΈ¦ι‚φ,~*Zψ9Ύ#Ε!7ŒΙšά2V8wPr3“2rv4v(ΞϋͺZΖGΆLΦ™Ή `S€ιπc“³r¦œΙg™Ρ!0K3R'RQΑk€†υΕ&(ΐβ°‘ωΑx{0Š{Θ‘αΈ*“:'Π3KŠTšζΗσίlϋOσf€Ξv•Α‚)«ή΄Σΐ¦΅.ΖHμͺΨ%αׁŽe‹χ]‡μ`Uαi«$#,™¬υvχΒ…nοŸZΉΏώ坌° dΙ άB―Ί )XΥδW¨ΙαV|Uζ bjJΘU»―'ŒΌ­θη™ΐ£*CmΆ©;σΝθέ'nΜG«cdgΕ/7Γ$]>όΆϊώηΝαυ=Μ¨ψb@εA—τΝsyΓGΣΉ˜`­–<Ø dΩ+€bPΈΖ|D&ƒ>Ή’υxΓ³φ֟Lμ)=v'Φ_oa[7εΰΗs3φ¦aw_›α@Ί‚«`‡SΤ`ΐ>Βό*ΨHJE‹MšTm=¨œ%εƒ/Z²–\†eλΗρΒxY ύaŒŽά))­€βau J.mΫ•ΔλB”ϋΫX€$3αͺ·ΝQhEƒτξγlϊEx΄zόy˜ !Aν₯?Ζ¦Ζ*j2!b=αkαGA`5wn°Ό1˜K]u¨!ε£Β^sQλΉΔ›·§ο«§‹Ί|l3A€ρn#žή$o”„δ’1Ι:βεα1“ΦΚ«%³ŸsχU›jгs7εύν ΐι£ϋυ°―θC»{Ω\β>ΤΣcγΫΖ›ΖσκρΎI.woξW[—4•>vΦ¦Y½ΑΫa…G`ιˆX”"<`ŽdΌ‚ϊΉ4₯1ί\Jp=Δ"ΓKEGΚl"<΄rήY Χ>σ›OύΡΙ ZοžΣ0‘5Ÿψη ϋž]Q.ΨR•ΟΤjΙ™š ΐ&₯κ βη%.(Ε™Ξ'ͺυy:ςΉ«FΣ±}αuυψ}―Φώkστp?ΊΗ]|›Eρu(=QΨ Jfi&LRΠΊΪ¦ΊT_¬q!%όUgηΏRXρ&jͺ7υw5κbf—χ{AŸk‚οV’~AE+pβ¨8ƒωKΩ4`lτ1Š£*I=)Γύς͙ȍΪΛ¨ς%- X\ΟAςΐφ±q:‡₯zŽΊoΥΦ »cν6¬’{y[4`«TyΤrzƒnδj$β½ͺοΫmΏ}ωxΗΔ/B"Kοζ†Ή<³T|α$ΧΤ(7 Η”Ήζ@ΙlRRͺ \ck$ P―‚W‹’“έYν’Ε£AΨ„iεΞ#«­JCfͺ=ΕΪ‹iFWΉͺ–J –>Yΐ`ψWΨΙfœbκ]&e¬‹R|ΞN7½ΙΞΆ«VIΨ7–k”hvg0ρ3 B΅³’uΆ6ϋ²m>vΌΖΘpΈ8§%š„Νή₯Δ­‘‡Φc–[.rΉU²#J°ΟΨΨ‰”χœΈš™BςΟπό…Cώ·:”κY―«ΫMΘ DYoT)_žŸ&™ρΓΐH71ώ‘>ϋ©λŽƒ—±ͺΨn4cNPμjμ»=Ε±ΎwWμp·.žh‚…ͺNΑu °ΪLmrmΛ"–h4ΜXŠΪeφΉƒ’‘cS@ΒΆt<Ρ>zŒtŸ˜ΑΡ„νJ΄ΝΝΪ&uΰΦbωK]+ β>«gDW-{ΠΡβΊAΒ€š±V[ƒΙ Όξ½• #Ά:ή_ν\Ζρ{£›©F3`uK§˜±ΨΦS5Υο“€V'Ptr«ͺ2;˜'m{aλήƒ~°tΰΜΨΞ²ΠΫ£φοωΡsŒ»ΈψA fΌUΉzEπEZ΄‡Έ«Ξ΄*$ŒΩφ£ΣΨτά ζ³£›'Χt›[­ΗU+ke η˜wε c”4E"TYDuΨυ!?H½ˆfhθ"'˜\+T©UPΘι\Ευ3ίΆMκΠΏηΗ(QόJtfhσsŸώΠ­zqΉ›J  D% M՘ά:Ξ©ΙFΗΦΑ.[ΔΔOAIξ°“j|λhš9­=Μλι!ξ7Vk»Έt`ΥYΔα.r τ¬ƒεnŒfɞΰΒq.ͺjͺή–}r•JŽΣ–|$;9X±Ο£ QΏψqV91”ŽτP7ς°R &³–f%ͺ’γ›Τ‡V@γHGΨ°ό£ΨΆ’=Ό6]\ƒ„!&Β―μŽ‘K΅š-x€(ΐ"QRΪΦ"ΉX5οSk₯κԏ^»vτ­ιΥάUψΫχ¨ΛΫ8N–΅·€•·M8‚Φ‰e ;ω:€^g0FΫ•’Ϊ(Ά …ΎΛ6˜@ubMΧ—Χvͺkθ³D$ŠΞ5%’$Ž]Ϊ€†§Ψc q(φXL Γδpκ(p1ΰ?s΄gΊ¨γH΅ΖτήΎο&R„₯©‘\½&Έ)-UάT¨3BŠEt%$κη1V;|•  \eΑ­νφψJοŠM^;³ΓfnΖ‰ϊ΄¦ “‹]Ϊ8Hh§2Ύ&ŸC†‘ Ιΐ][ναΒ;8P–Ϊτω‘τΨΗ 0:"l‹{ΗP,YΐW’*Ηξ΄)oμJΦ’~a«qΕͺδj“%ΑC8” D9Ι2ŸI>΄Qg7ΫΊDPΤΎίŒ‹`ζ€€ύΝNηωαΆυΘPΞΜ|ωb™Ϊρ«Γχ—ϋQ•퇉ΐΓbSzaD8{‹+ "6g’[²Q9[•ͺΔ’ΠuReθύtUԊ‡+ιω6½!ӌg|»ΑϋŸ¬μυ ώΩs``PŠW±asJ%§δ 7LδXΙΥ>α‡Rτ䀊Ίβ%ΐΰ[bšΙ)†ϋΌΕΣέT5mζe{St^ΜΏτy’wλlΤΓΓ₯‘˜3=6D§Fώ*l‰άό'xμΣ³-§A󯉩&[€·$ίζξρπiš―κΕ«&"θ5\GuœrφƒΕ³‚‰Φ$wC1ϋV€Žkν΄₯d―tΝ.9ωŽsΆηοίΖFvqEoηΈFiTPkS›Π[‘07–Eμ-„½*ΉΏg²‘80)|‘ρvΙP5Jg=ϋψ/‡Φί_CάUJ©£T” ΨQ΅ΗΞΖφΆRf–δŠ΅Πd=”Ϊή|Ή₯»,’μ)9υ@€ŸnDΫϋ£0ςΏ½nϊrΰΙΝd6ξφΏg§j‡­fI./Ιΰ %o²nΝΤDΰ”RιΑλ―‹I•ΐjW•X2""+ v}ΨHyδ΅N\‡σΨ‹ζ‹ΉP1ˆH’o©`¦ŠθRe‹Nη+;Ρg€2Nm†S}˜ΉΩΪ¦`ν;»εoIcŒ:™*Ί58γDM1z°›™’TAγΐ‰ΙN ζF΄#a3­sΎaΙzœΦvψ”ήK83‘z(k%ξώ—Ό|#r―wOo7Ο/όηŠZΌ< 5X&kΌ‡go ”‘ϊ„έhδς86IŠSÁN’Θ‰ΝΛπ ‘‹½υ:"γϊ•κωΝ4ˆ₯cϋRI’Kˆ7‚LΩφΩgΈ8₯Jε ¨O³Ύy”1”'Lœ6%Ψ―B 7ΟνF φΣ_―7ίίw·ΝnƒΏαθ„L~θ΅ϋο€iΦ΄QΞ’\sΦμ+k2χ>p”Ί­¬rz”λkQHsΉ»ΗηΪbQq “―ppI{έ {Œ@<Ÿ/‰s$ΣTsXVm xτPU#i“žDΗϊΘ:Ÿ\²ι…Ύφ’Eσm$Š”΄e֍€nάH |· Ίpb€b"7gZo:[@;'™ΆΌvΔ8ΙnpξΚ)ξ.ΰ¦ ΰ©ώΟ±—Ϊ?lG—sΘ’…Ÿ`ΒBˆ9`αόLπq>ϊγαήσ„ΐφςE[ͺκκ₯«XπwMUλ^3φ €7 %£BTΰ½'msΕή₯Pό΄ΝΩήnΛψ€…ΤϋσzDλxΐΓkϋγosu}Τ¦cNμΆ€{L‘όp1*…ΪlQ‘ρ’7)W¬%©’$EŸ² 3kϊχC9ž§ϋ³<άί<–ΎωΞSyΪK³ΒΖ,Q”‡ͺΟid²+)Β», ‡Yͺ'•’½Tθ•ΰ ΐ‰fTʝuuΈί}f’<ή2 wb.δ#ΏΊ΄½e ·IDa¨.$Ρ”―] M€έ•Σ&ε\βCRΥM•Σ žΞWržkz17·ψ½(šjΩHΩ9ΆŽ"v$6fπ]dš €Ώe }ηεF%ˆ( ͺjN%μρϋFηf­h<»P’φ2Q_y…\xA« Ιυh)…QΥ0-ϊ€4(Ή€U!ΖβψJXΊ}ΨAκΈλSžρωίώχŸύηωΏώŸΒ΅ό”cargo-0.86.0/benches/workspaces/servo.tgz000064400000000000000000001426151046102023000164770ustar 00000000000000‹servo.tarμ½ι’#Ir&Θίω!Α?άa!Σn3o!ΉCrf)B.GHŽμ²$ΔN*x4ŽΜˆανkμ“­ͺ»γς@ @V—gugζμTύτ^ΖΕ·όΛgoγόι›_>Mζ)όΛ2ŸYoόQB΄ΆγΖ|ΦLi‘“π™REԟ‘?»ΑŸυreφ;ύσΏ?=<<Ž'«Η?<ΰGψ²|ΆΎ=z©΄αήZ"-S*ψ,™i›¬Ž‹H8ε^RψSράΓγ"ΞςUΔGŸW«—εΎ|χ>―έgŸΟΎ,‹}VόύžωO|πρŞaΣαήΓG?ύη§?ώάμOΉ.°B/ω<ΞWΛ/Ξϊ―γEΎž‡§g;?Νςωd•/Ύό7€ŸWωlΪχω§D7ΞΏRŠ ηώ=Δ—8qξ'qωσ'\ύΥΒϊψπ׏δ3όδωr钝<μ‡yœ–WΔγ§Ι‹?l£Π88_~cπ%oβ2l’ŸΙγ§O?ώyΆό Ιήπωσψ^ήσmtΨΙ©ύυν –m5ρ{οzΫqόω“]―žσΕ.ύϋγΏ=Η‡Ε-ώπ?ω/Ρ―ώ.~‹Σό%.–?Ša²š”=b„쾏σe1ϊϊŸ8bψ깝 'γρΣΛΪM'Kμv²Σeότ ^^½•|†iyότο°ΗΖqυωΡ§ρ_Ψιτ/ΚοO9φς?§“ωϊυ?z˜η«Ώ°σ·Νe»πΟΕ v1Γˍfό€Δ<ώπηρσα,Ν'―»eYΟΏOζa΄|[Vm^φhf}Ύ„χΦ_ νΟΫ­1PΟίύ_.ό8ܟΛήρόiͺϊ—υŸγ*ΟWΟαψογLΠϊϊs­όώ?Y₯©/·|΅ΙορυίnŸ'€“Υς€£Χ/6ž^ ψηO)ΪΥzKΎ}j΄ŠΛpmπ…RFωxϋ"~Γ½cΖ ΝdJ.E³,Xg T—Dk‘΅it'Ξ\ !.ΪΖR»ΦxΆθΚ“ΟηirkΚ¦ŽϋvξΖ†Ζ½λυ$Τ&雀‰9Εp6χΈτ-ŽΆ“YςΞ=-J>ϊ>ž–»₯œ/°SΚVx#<1ž>νΡώύρ଩έΟ@_yšLΛΫ·]ώR΅βnΔ½uέLΩΫ&ήρ_oʟ υ?Œ ψŽλߟςη ϋ@]Οαϊγ‡aύo?οΫazΝYγρΣΜN§ΉZΌ|ΚΣΐΙ· π«—J―B6Ž ΄ŽΥ›~$ο?t)9ΈτP}-8ϋaΩώλ1΅@’σό>5„'θ/0ΰώ/€τχYόΈ„Σ3χ₯<±ώLͺ†§ΰ|X›π·žLCΝΑW|«ϋt6Dhΰνκ+ο€_γ›Λν"ŒVo//Έ‘Ά¨υQa%AkQΏυκξ1N―mνš›O Ίσ―gη{Ιξέ3«ΆΞμš;‘O½7§‘PΕ±Ϋ~οπRωΕδ₯΅£WΪ±Χh,ޞF$Εmπm£>\±ͺ±γ™υbzp;|οI'Ή§<@^ήΎΰ—Η?υΰλβ"YιaKόX©ΰŠ#„X±Ϊ›—’Ε‚ζbό`ηρrΗ3kπρ(οI t ώƒ/ΏΟϊΟ—«8Zάώ7Ρpk]Χ(>¬μΏοˆ©Γ=€ζ[Μ»ΐ^=L¨Λ»¨#6αΠΗΈ+J§WGεKM»{Τ΅¦6Ϊγ M§hθΛ΄υΧjΧϊ†΄'ΝΠSϋ–―[QίΑ•&ξ-ρή>ςm…vή&~Y»³h»KΧAtxϋ>¨ωJώθΥ½qΆ^ΕΓ=S΅έL_Φup M·€Ζ[Ύ?w½ΎtΌ?τqۘ/zfψΣΖDbπγa"Ζ,ζί1± <Ό:Ι[ΐKa‡.ςI¨_ΓXΙΏB)Ϋ―‹¦ΫΌbdμOJ|έM«θ`»ΛϊÎ{*Ž΅J“8 7Ÿτη O©θ ½ώ_ΎΑι_¬=2 N$ά΄ΥnjφΈUΙΨWiά-T48 Ϋ?:zžΥάƒΣ{ΞG™ΐ%ώRϊŸΫ­?Φ.Ώ¬ARΎύηΝψoXΑζτssρ€˜ςG‰ΕϊS±ƒ7Υkœ»Π:θοΔ±=AΛμFϊ‹έ”Ψ έΏ,r?šYΏΘY…ΟΈΞW±ϊ|–tμbZ¨·;%„CςωΒOaێ&³—ι²!γ8 Ϊ;&ΏaqβΔωΏŸŸΝֿ΄(υ|2mψqΕόϊίmν}ŽHΓΞλξΐΪϋόφ² @Žp2^·ΝΙ 5δžOίc=ΗZx}+Ϋ96³σσCέ@T+dΠΈύΦθ€—ΔI=Θw]#O­ΏζMύcCώ―;πFώΣN]ο η;ΖΦ/Ϋ;Ÿ1_Ξ<1%εΎ\΄΅“ηΏ6p‰ώͺαόί‡ώη³§RΙΣ›xώΣΜ/θ ίƒώοkϋ~‹ZΉνζ䍏ŸΎ$€KτtΘ~·υΟžΊ Ιέ"«ΤΝόdπΊύ?nι#όna΅ώ»d§Ο}ςΏ21θο²ώ5-ψ τ?”ΘωkλkϊΞj_]}œOυϋZ"ޚΥαh `ΏŸ-yΥ9_Γ5ΘJύο w=θξ²ώ@`Ή§ρvώ„+ή΄‰AώΏ_’©ε[τ]ŒχΩ.ŸΗΣάζ2άΆ¦lω:Ͽϟ–oΛUœ=•6œ2}KŠΏΝXYoηΞφ‘ώχ}Φœ^{-ώqzύ9•ͺΎώeNΐaύoMνΛΛ†Tr˜~lz+κρlΙ­ύuWhXžψxεθ6‚"ΫίΪ‡½’ΖΠwŸ‡8*sal»π:UW6χ6Y$YbB³SrZucΉP.wyxΖ‘…cέΙpάWa Δβ°+EΛGς~TH€^£cPm «™ΟλΎͺ+νςα° gδbήμ%7 uώ;쉧Vή«vακš€"§ΟG’xΦ/?lή%βh€ΣH‹Qg΄%3}Δf_β)²υQΫΦ£5Πwοχώu6m\‘ΝΡwTέnΌ‘Μa‰”€t ήRͺ j²–hΒΥυω"ΒΛΧσ`WΫ…ΜͺφρΒΎλΏΥεφ§:΅ώŠ«fύw>θξ@”0H~ΏΥJC`dβžΠΦIV桍ͺ‚μώOvŽΔρ€Τ1ΆωW˜ύΏšM ςO¦uŒ#›Gτ.+59υόοωβλCž–«π‡?ό_°SΙΎ< 0-ΦMγΓF{ύP‰xπάηΗO!χλμξ­4΄αpΨΟrί€±OγαίΎό-Œπ9’ϊ½»Ρ†²ρ_ώώoξŸώώσ,`c‘Λ7/ΛΛΆπ§r’]¬žχΊVζι&ς‘σί›p‰ώ_ιί…ώ²,ςγiκΛψ€―ζ-ωϊϊίτν;#δθ άάσΏ;ς9η>ωŸ»¬™…ΏWπ)ϋ/£ϊ―œΣaύο@›φ_΄γMόΣ"&§Σ­*θ}fαΥl*:ojΗφ`nρΖͺ°ΐ@ž¦ωj—ZlΫyΓINfω€υψ‚ ?^ŽλΖαί²TΖΩ&ο²pFUd2_ΕEΨV\£~OΟε9kvoZ’«ΥΗ»iΏLΥπ-•‹5όΗΟ±χ_Viδξ^ %Νηφ³ΊdοΒM€uu\Š<3Kψ―Oπ%ϊ6ΰ{?YFnUY&ώΧrΠόΈψω±_.Qe³υζΈ ^Q³Ό—>ςL‘ K˜MVΉΞηa1±εΠ³„€βσ“_δ“εΞW›šNδrρΰOWΈ žΣGεg—΅;ΎΒQΊ|ύXμkέ:Ψพψ―ώ9ϊ―[/Δ[βN€BξΌ”ί―ώ3ΧƒύηλΏzFΣφmκ?S₯šυΔΰχ#λΟ/ } N–«|Ό°³JΙƒΞτWΠ7tΐΉΖ‹ˆ’ίH eΌ»`£MEK½¦rE˜/Χ χ_–ω½zδdπσΙ$·R:·`ΡO‘T«αͺ΅ 8ŸŠΎω (Αίζ@ˆ~+€]Β…AΡϋ§†ξW™ ώχ_~Τΐ§π?Ρ€%ηωOχυΣΰ½ΠV5°xΩ> ψΑ~@πWGπƒΚ|ΐ‡ψοώίL υΏξΊώ=¦8•™rΩ”τ{όΞόΟ ζF^Œ ?ζFpνTΤ7C Cθί ύΏŸώωo·ώ/ω—~βfΣ²‘Χ  'λλFώNΕ »?–„σ[>Šγι@ΓAͺθf€Όͺx¨ζδ6Ο+MήΣ&ΰ‘s[!Νo©QιΧΰ§>/y;vjχπ`²νEZ 8ότπ8³γ‰ŸFϋςžjΧ¨±Λ±]ΘΏ?ξ Ϊ0]φ.ϊ₯qΗad̞£aχ…β-@Ζ– γ~τΏΧ €—ψ=ψέݞkΙx μΏ?”όηߞŒ7ΖΊ–p1°ΖΩ.GΘ»*FνC ΄σLχ²ifη]&>iΌΐd·Oπcγ§Y>ŸΤ χ4ί5]ΗUž―žŸή΄vίί¦¨_μˆ9’8₯;[°Iqΰ—ΐ–ηγ)°Γie{gΛ[ζΛUœN‹ΌZuƒΜξJγΉMρƒG6w·²Qύ‡·Ž—«“X‡˜ίθU0υy‘μΜβ‘ΑόΙ5;§μ4ο°šοh±·Ÿ|#ηΏ¬έN=πgkΚ>hΉTΥWΧρυ§lΣφ:όν‹QΪ«Φξ”TΎ {―…υlφvφ‹κξΘ‹χS/q%|€|Α‘©ϊ¬w±_Μ΅ΐlίpΆ…ϊΝmoΏ¬=MέΪπeμ­Ίcυ’ ‘Τ‡pxυΘσ-η±~±K-ρa΅Γ:†έz<Λύ₯Ϊ=ιψ²k}ά©!ΰ;ΰ«i¬tγ<‡/ίe: |σ—M\ύΖωΏοΏ΄jΒ‹Λ'DmE2²ƒ;φΪ[΄-ώΘMG ίΒΤΧ―pŸ¦¨Ί(oΛΗ_@ν2>Wρ PΫ„gg²νΞΤ>½Ϋή³%RϋΆWPΉ΄ϋςσ§9ΰ¦oq΄EΕ“Ϋo_κ—ρ‰|τ½Zƒω})[ŠKuΨf9Κχ₯]iVς³Ζ²ο·Γm•_`ϋZ5.Βλο/»y¨(νh,β^ΛΗπΫϟΆtdΣΫCͺRά0ξψαΪ%|w5+W6ϊ ΕοTG³Ψςγ]ͺωΫ4Γ½pΚͺ Ϊ_Š]kσχ―Uύ?l,Ξ¦αVZΈ³up‡•[¦ΣΏ˜η«Ξš!?=4―Nς+»,WνΒ?—Χ³ξkψI , Σ¨T2ΆωF‘έΑyΥN>o(]Ν‘ύΖt’ϊŸ@7Ψξ²ώ‡^ΐ½(Oϊσfύ­―;θšώg€y),n²ͺŒμ3L›₯dWΟ“ωh‰\g/β·Ό||ωάΜ+l½ΟΧσ"΅ϋ¨'4$¬-7cς|5ZFΏ^LVo£—zρΦŠŠDmG_/Ϊ^_Χ™žzΗ%UuοˆΆ8₯*b폕 ιN=ά ƒ>Tܞx^φα~~’—ΕŽΡν>aM΄εϋωnχυΥ<Φ8ρk¦ρ0ƝŸκb[@z‘98ςXΫX―'‘pοξςε²τ ½Λktj>Τ‘dZόL1šJQ`νφ£_\ͺ[l,ŽΘφC•ΌΎξώ*GOyioΓ_χΆ~ΗU.Z.Šΐ…¨0ύn&±a3}”Ηξ(\QπμλƒύώλCΈΔO³!γνΦΒ.Ώ π»ώ'‚5σh:ψί‹mΈζm‡Rν~luu΅V­Όa±νΧlοΤωΏύWCύΟ;ρ΄LάΤ‹hŚϊ?9ψίAs,yΓΉ©½Ζ» ΖφεdπsύlΑgΪr―ΟΪΚ z―HΧqώο―§ƒώχNτΏˆΕμ“œŒmΙ.ψ€ο@Ϋiό~Ϊυ£ΒχRiώπ•ˆξάSϊ’0”*({Πώιΰώ/†όow’oΞIaλo¬€~ώΏŸ »Ε¬άΑΨͺΎcœΎ%)HSαxf–ζƒογώηOΑV6έxˍωφ™ΚΝΞσgϊΟό'ώΏχ«ύ;ƒώ7ןI9¬#5t|Η₯ΐΦ\ϋͺΐϊτ(μύi–Ξ,˜ΦυE―Φσί«φο"ϊΟ$π]θ|ΖΈ„wφ"#ΕoΚ^Šό»Ζ½&>½ώŒ’fόƒΧπ‰—v0ιέΐΌΑίο4φˆ=_ΟFεfέφ°;βεO…#°·g”ϊ¬xew¬Ε:šΜlYόf 8Š–:ΰΰΐ~—a±…‡zQžπ֎Ά]W„JwΓ;ο…2C¦χί7ο ^βOισ.λ_ν^Uΐ'γΏ΄jΪΙ`»ώ«ϋΗb½”*Ϊ€—ΏuȈιMXί·όΨ^ΧωοSp‰ς?ίiύKυλ-ύ₯M?6Π;ΠVqύ€₯©gεώQ΅ϋυ©&χο;3ίΛzΧH@wPgεβχœk 9’ίn:™―_Ων0―γ8Ύ– |mΐ§ιΓώ+ θθ;λ?wηϊ¨;~ΤΏj2žΏδθ“ίmh{ρίνt•ΟΏlnώ oKτ{φ²SηnωΤΰs—υ_Ψω8ή6“`’™E ώ?w Ην=-ξ6G3<½Λ tu*]μμΑ™α¬σόOώΏΟϊWhnhΧB7σq:ΰ›ΠΒΣ½ζΈςœ›‡8Ž;χ7l[>ΫE Ϋ¦“– Άzv±°oUYςY!f{%œJΏΞ–0΄Ι*MνxΉύ%ΌΘηω.­ζΈΪ-Θ΄΄h WΫΈ>mœ_±ξςΏΙ*.Πͺ²νλ±”‰ι‹8μΌgή΄UχͺE^β`;«ό4K―ΜV1 ϋ\„0m‡U†·-ng¨ΊΘKχ3m…Cη’Ι*χΟω<,&Ά25α―΄9υΆE”wzϊΒVέtΣΘ30O3ϋ²‰?§5Χ^έΤ6 ‡νΌ]qγμ₯*υ…Α‘u‘φ=’‘›„Ιf.ΔyΗ3θΎ]mλY[fίy½J#³=9ϋΡp ΰ†ΧƒύSVGΈB•>Κ_R£ΈWΧkψχν©vDœ†z”_ύr―A‚!ŸΑΑZ¬ύaZ]sΫΉCΘ[­ϊs{u4Ÿΐ§W8-υ™^…š7Vk͞_–§½‘ γoYBpίΥΌjiΌ°`Έ‡Ϋ¦’yΉOΟωsΛ·$0:7_Ρo(φ²Δ/Συx2oΝ’X]κ1ύβE%ˆΞsJΌNfγΫ„ΉΒ«f‡“R΄<ή―8rίΑ›Zd- kςΜ±H}…¨kVc>·π2π?`ωΣڏξaΣ&γ£Χˆtyo½ζkoκτΠνc%ŒY–/1ΩυtU\[Ο€fbxš“zΒΟOS c΅zΕπ†ξZΕ-ΥsYžW9·­ŽΥϟ:ϊ΄WςvC-ΏtwSyΊ²­°Ϋ( {ͺn­ΐνv‘>\žφ£‘Χε4τΰ΅WV£m8Δmκ½ώ6ΛΌΎ[3ψυ όφ…ΰ©ψoή\₯Ι`Ήƒύ§E_K"qΕ‹ΆΊnύZCVӁ5u^νϋЧ ς φ€„ΈiΦϊϋ ‘‹†…Ω¨ΩΗρžΒΫΥ%‘³$ώ„†³ήΡ5ζW·Μvκ [νΓ?/ΐj¨vίυ߈“·πdR4ύ?Ε`½ ώΫιHŽ(ϊ¨IέAτ·ZށֈηNώŸώ?œ›­^όΗθ?g²ι;Δέ^ώ?f”kVnnXιn%'T?9”oΎΑωΏ›?πΧΆωŸ€nΡόϊίΊςΆΓO°U©w»ψΡ‹gm”ΏΞuώοm£ώ»«όΧg θSφ?%ω„ƒύχτΏιfΆ_}uτ“*ΊΛQύ2·τZ&«Κ+lλπUχΰnρΈώ!<£οU­δΆΖΠ3=oλ•LcrμΗjxy‘ί¨ΗΰΝ插)ΰο^"«!γπίΖ₯’?ΐ©όŸΌYƒk=ψݝωι$Rl‰«,ΠΧΣ,_T°*Λώ`ϋΰm?pοeqWW1ŒvΠCΤΦ–tΰ€ηΟa-Έ–]OΛηYœ<ΎiμΌ»-2©vνΠ#έΑ ž?b[mq˜±€ήΥθώΫΏώ+Ό :Ξ3»ςΟ&™ςΕΓΏ¬±ŒmΘύϊ qΓ αΒήΈG $ώ=_„²o°ΨeΑΖκ„­wη§…5ΝΚΖωϋΏύ»ϊϋΟ³€/ωr7ΌeΣ%|©—"ΑωύΣήT@—θ4θνΦ3ς.Ώ|Ÿ °ηβΏ§Χ_Ή^kυί(Φ&όΏ3F Ž~Ή9:#₯Άκ‘²tελπς§)ς(”ŠΖΣΓΧ@C-†j{©;’jοžεARιŸ8‹ή·wa6F:ncδΣνuΎΌ1Y)΄Kΐ/x―”©ͺαvΤDŒΒz6{;|λή…νmγε xή¬ΐE[·αφ9°αoq΄Υή_ΏŠδ£ουY.Ϋ["ΠΆ·œ‡Ά½»qΉ ΫκΕφnέν‡φΨ²ύǍ7Vz€b·[^]»ήŒEΫήΌkΏ_4Z‰TΞF«z‡Ξσ|*\Ηύ»C@χ―ε[1ŽντΏε/o‹ΙψΉPlόοΓΡ}ϊgΈu2·S|ιA?ΗW¦πHXϋΥ]]©~η PΞΞίΪSΗτОΎA·œŒ·˜ύ²WI¨_Kƒr"ΖΟΞΓ"Ÿ„Ά5“Ρψιδ₯ΠAo΅ΟuU7Ό9Ω¦+)”ΩO°²|†c·AάE…"­ζό 76ΠΈ·ΈRΰί‚uW―§+ tŽσζΥΝ±±Ψ—ΖeαρΪz‘fv^Χ„ΞFŜRΜlτ kV₯ώȏ ΕU$όΪxZncόŒ ¦qΉ<_EyV%†6™ήϋφΓΧuΒκκΡPBγ8Lp πi½,|œ―ͺ˜Η ?9φ0Μ8†ί…—ΙK„7ίW€* 1™cΚ/Ο0»ΣΝ-ΥΗΟ?7j’Œ¦κΗ”€u+ψ_ώοΉψσeς#r°ήzύŒ–n=Λ€§τΏŠ6ε?­ω°ώχΒF•;aTQΫ€‘­Ÿ5΅Αη»ŒΆTΚΰΗOϋ²dΉΧ4BζΡΦ>žΆ΅.ίvΩνv­ί&!ζ»Ϋλπλs=‡y=γ[‰vΧΛο8ΘΙ|Ήυ8lF+dΗD}ήvΉΞPνΫ3ݜ΄°Ύ¦υš¨ ΫlAΝ•m­§•ήϋπ?ώu³©Κ=ό°zΆ«€ Έ–E/–hxΏD7ڝŒ¦pχ%φ—ΕΉ°ώχ‹.αšωίο’ί&»™ύ—ˆ–ϊOZώŸ7αΧχx9ΜdwQ†¦XW—J‰₯YΙJ%CδΎ²αiΙσ—vqσχsώοk£ΓωΏ“ύ·r”ΈύΧMωk5Θ7‘5ύj“G7¦pOω\χͺΝΓ"©QHΪ"¬T‰T€όxvΆΘqτ_σ"ιfCDΫάΈΜπύο?*vθAξηΛd‰†ΰςΕΧ‡<=,WαXΎΝύώπ· πόΓ2n_aJzξΛ‘LVo wδλΥΓχhΏ>@§aφζ>.ωβ?όΫ—Ώ…n>ΗVφˆςΘΌ`θ₯ςΓ‘σgϊ?ΨοΓΡϋόΆυŸZό?8eƒόw7ύίr΅ΐ|z©Υ‘#¨lͺώφoήSWέΝκώTΕO ωd>pώο_Iτ.λ_ζrΏeό?ϋ&ύgƒη=πž--.,{”ωzφδ_ΦΛ½Š6-e’φ‹άτŸxvΕ†Ξ°rχ·&ΐ9ΌΤc±ƒΦ˜>ΈρΫ¨ΦŠΌO9Œd1 ΅²υ«‡ςT•ϋύη›„ΈνΝdω؏ψj…Ιb[OŠ όΌOϊχόοCώ·{MσΏ τυhδς?݁7+’λήhfύ"g»γ:_ŎΒGoσmˆΐh —€€/ϋ)lΈΡdφ2-"Ι0tΔΘ–ΚJ7εWΏ»t€§ΞέςΏ‰As—υί€Υ%ΐSλ/E3ώ[ρΑώwϊί¬Q—'Ψι-ύˏ]―ΰ@ΦϋMσŠξσߟp ώ—jΠάeύ±βmύΏ Χ²ιΗϊϊ\Ή‡{cΛπ  ζMjY΅L–ΦξΪ0ΤBPζ²Zθ`ΊψόίίW ώ?wZ8[―βkŸ,ΰ$ύ'M_!‡ό_?ύΏ/7α@Γοwώ{d—ΰβίαόί~ύΧ‹iί)€NΩ oθ™ΤƒώοτCڝS©fO¨|>n½GμZ―A>˜ΰ―°ΞΧGj]jsdhɝ[>ωΣCWέqΧΒΑ`ΰ¬ΓŸ.ϊίs ˆKδ?Ιό»υ/γ1¨ ²±l΄/“›Τΰ‚6νR ωnΒ[σ?LŸΖqΈ+ΕΠβΗWχoql/ξ~ Tž•ΩΰFΙ :³EΩωxG•oCk¨Ά$ g'CΈF2ϋ§vη9LΡ·ZζΎMλϋρvΉηy₯ΓyJ‹1]ύΖϊυ+'Œ¬άOw7AC‘" ·κ€²σrΏ_%·δΣDΎ|οxλ»έbΟN‘vœΟΣτ­y ΧΪ-CσΞq‘ιa “5Νm(c/K+Ο wέΞτ‰ΟJcWK1”/β(ελyΨ¦+/’ο\ΝΘ·ΝΓΟΎΓ'πίέκΘ‘ώΗ½Χίχ%œ¬ΦŒšψnψί; œΫ˜O*Zͺ4²δΖω·"L“ΛΝΌ'ξ~ ΆZΚ΅:>ίmΠΓ’YŽAήύύ1Τ»¦ΰ»Ήϋξίrώάvοίz·ήفƒχο­ΟFά{ 7ο> †χ9އξμL‡ΎΧYwcw>„ΉuH»ύͺ­έ{Ψξί|Glϋδ‹³ψN€{.p;@‘b™ŒDώ/₯‡ψ―;―/σI?πdώίfώΙτ€ο‡|§†·ŠΖ}šΜ‘cΔπ4&Ό%Θ›«5 Ψ’ζ6WυΕΰΟtWA8₯tών"Βο}ο] Sέ)qΝ|*Ιξ­ τ§ιΗΐό_26ΔάΕώΏqύΑd=9‚ZΦτENΰaύ―Ο/!wΗIΩn ^FΏρσߏ#Π%ςŸΰΓωΏΟϊΧ }œ œŽ` ώ/ι έ„ώ$ωVοΌ£™Δj` w?f—ΰψ4œϋ¬Ϋ4ή4―$ΌG‡ϊ/χΣ·Π~·Σ―a²(γhi£mΎεseC>’κHBxςYšŽχ.β8ΎžΘ&O;žΕ }q‡Z”‘l)v±°oί’ί>‚ιt'ώ©2n#iάd•¦vΌά*5έΫ*ζ‹PͺH‹ΏΔjdΛmΡ5ƒ₯P±υ4ΫέgY3AKz}ΆΓ,•©h…zΩ—ν{›)Ύ&«άnW·ΉφΗc‚ζρ{Y“fb­ΖΫ›―g£ύxΩ4™―βVALΛΆVlϋŸcZi˜ΈmΧ°8ΆMσͺΤ-%˜Ÿ,"υZ―bν^lXŠm±%Žf½ZφΉ(›[΄VM΄¬―;Ϋ m=]/ΦΕέπy>ΑDΨ#7 “νP6Λ8žράϊ₯―ϊ–—«B?·‚ƒςP pωσρ}Χ¬§›ύς€nw「§Ή;Ό}ΫΪΌ5›J@l‹ύb²ι»λŽΣ«pΪWϊς,A›l³§ΘAkΔΨ°iΎ8ΉΫΦχE§.mΡ­fΎφΫΫJνχcfξζoν›<ΚΜηG2Ϋ}|“²΅;K푇‹ ²ϊ“{©αί½Λ RQ›ZͺΫέ…Ž§ZΔ—ύ ͐ΐηΙ|΄DΡδD7ΫVσ}ρ„› m#«]k)‰RͺέPΎΝhΪ€/_η@;Ÿ–oΛΌ©<@x½βΗψ±`‘ψωaα·P£’m;›:,}/σ— •oΙbΏνΌb-Xn{Ώϋ₯;τO‡Ήϋͺ%FŠ UΒ/[Φψeϋ=zZšκφιFύWp―ΩmΟr6Κιot ‹‘Tα¬eˆIΝΧh.o·Ά&M'σ―Λ]˜g9Ο~aWq_Δ~›bυπη„όwϊzο·ώΊ‘ύOIΦΤλ{ύοΟ'²=/ίζΐ3ΧI…‡š’M° `Dγ#bφ!’jͺJΜ…M9ΛηιΰJΩ§+ΌΥ{κγΚξ}{/†|όόίΣώ7θnGQαΏό‚ͺ¬;θ©dMύ/QƒύοτΏ©ΡlQCΦ5Ž[Ωl§:P½vαlΥΕ΄ύQΞ΄(TΪ³œΦ°{Ε9*–cϟֱ{ΊUΙ²η°qbψ9 ΕΙ±ςBΝw΅ΥjjbN'…jyσΫτzφη―j€.ޏσρ·/7wΠϋΛ|ΘzGω―ΞέDώ£’³–ψούόΏa©<ΌΧ†X „.ppΉuθΟΝΝ2—˜Ujpθ© G}H­–Œšy`_ί’β?θLC™_ξΑ/+ ί―pşŠύ8ύΏ£ό―ϊ»υ__0θΛfc΄²Λ―EΆ«Ύ΄'γ?T#―`zΘqώ2ώσρpΫ-ψ8X&οxώ{’/‘lΘsώΏu‚Έ]ύΏ–όO\‘!ώσς_‹pΧπœ,|+›ž“[·‘nO©w Xοτ;!b΄Θ.@אvbُ)1tŸ;ΧΓωΏλϊχθr’ώcχZόό7¬νιοΕγ eۏΐNžΨΐ%ρ” υŸξB·ιsžπ`₯λη²α!ΉδΏ;ΠLs¨ΔŽ2ϋ<:ΩΠz Hΐ–Kνμ°¦ƒhq y{ΩxaΪ Hiu•wT…θΚ[OΦξWςx oor–bŸ/'«‚?DΎlΫ›φ§εα½π½‡WmΎ »ζΖ/“Χ8=Ό»ljr5Ώ˜Ό΄ΎώΰΚω>)οrAiλΉ$Ζ¦₯Φ½Κ`Υiάο8β4ύΏOώ/Nϊ―υΏ¬{u=Ε΅nΚlΘzώ_ηβο­ή΄‰?]2Xϋ%%Οwφ8‡M·Επ–(β}u&ίΑT+5ι9σ‘ztΏθ|Q Χ_l> a„εWj£XΔ—©}+"'‹μ™₯KΖΔNG/vΉήΨ½=ΞtΡ>@/Ρ²‘ώσέψE ͺJ7ΘΦ’•ƒώηGΰυj,ΥwΔ“ωroέ‚΄ξΛ!ˆύFη>ωίΔ{ηυο-ΰ$ύΧΊ)‹ώτΏGδ†βOΝIϋηNωυΰq»υο5άϋ½λΟ$«―?Ρjΐ·‘ίσΕΧ%Πζˆ•[f.–„ωΣόy,Λ‚|ŸΜ'«ΗŸφ›ΖΛΥΛt=žΜ›Ϋ ˆ½£*1Έg6-―o.μΕ§ώhΖπκ§λPtωμqχ–ή{e^²ΟUυξΒgp΄)pΓ?ύωÚ£οΊ‡Uώ°)žα±šςΰ†Mͺ³ΒΓπΟ¦«|Λ=…­όση"£Φr4Ι†ώ!=Όελ‡yŒ_ΉŠ@Hv1™Ύ=`§+ζφ8γƒ}˜ζήNΜψCž–9π­υKY^UΌχ§ΰMΟvυπρσΓn·. OΝ ƒpώω«β濁Ύύ*ο ~ψ²ΚΏ?σΕ?£δzυψπŸΕcΌΐw@/koΉϊΫξΥπΊΩω_-ba%Νoσψσe=§ώνy²|€αψpΞB λ—ψP•d^Nζ>>Μ&ωH–xΫr5™NΦθ€³Ή°ΙηOx ώθ)χ}γ~p ;χΟΫi#Έ2BέcΕ=ό?Έ0v%¦pLζΕήΗίΈ<ΛgμDιPϊm€mΌΔ»fΦσΏ~*ο=ή₯ΒΑΎ,M―*VΥ»JΓ(hΖVrF˜§Y–2¨ΣΑnΉπ™ $cΊθς§#KφΛbΆžό§_φω 5ε‡ό%Μ6OμOXϊΊ~©–―s’ΛΏ'Λε:.Ώ0-©όσβKuβFJS‘‘βΣɝΆŽE §ςσ=ί=·ίωbεF»*O0Ž Ϋη‹ΛόNλΧ›σI`Oθώ?ΔίβOEŽ >‚l–Ο0nΫNƒύΧqœG$ο@ίΚM‚ρl_’ΎΗ1C˜Υ>Φl:™Ηϊb‰"0€Ο!Z)“a>Ea€Φ2,3F%AUζ` ½4ΐ΅Œ:~¬£MQGX;&£I·q<™M'Η†7mμC†ΩΎ{YŒΜŠθΉΰ–ƒdAΙLDšIΨgΡhΛο« %‡ΡQ- c–Ϋ`˜ AEθγ‘ΞsφX³cχ~Œd`QCη£N> ° `‚»8Κ3M’† H%°qρ Α&K½£ήzΦΥύη Νv9ρ_kK ‹²‘½HΡ₯d­ΠΑzCαƒΞj*α„dΐ&£.x Δ@'(¬Y€:)eλξ!Κ?/Žl/τbΝσΡr@9%+•RύΰΙθ‡ν%ƒΡΞ³€I–1'‚‘†Jαdα% ξI–œ–£Bq-’υ±κρΨ0ZΖ€‡₯ο1¨Lγžž$ͺ)…Ξf>RbΌ:ΐΈ%@ι΄W^Η’ŠΜ)ΙXf„†5…q±Φ…ͺ/DχŠΝΓ"~― ’χ>Hγ…M(AK]'&rž2–xJ3Λ„vΕHβ,Ή,σ4IγƒHVϋΤNΞ«μ-(H?bGΠ)’ψRUρ(>Ώ†qωοl:ΒόΩΗf’Qόχκ€—E.’w‰ežH…ΑaήΑφΐςD&‰°ό6(ͺ”Ζ#ELNHΨ μγρΑLσρhωΆl Φσ0œŒ,ksh» >Β(˜eΜe2ƒs©ΧMLΘ«ΜΚΑ«h„g,Hx°ΤΑ§A0  J‹† +ddRη£$‰’l_,)“[¬¬‚ϊψ‚ w­ΡςmξG«υ|Ό\E sρκ‹Ε΄" %Ch2šSΚ’’Τyχά)β)΅0–Šy‚ιω.Ή[6Ԙlλ€ΣΊπMς‚¬oΎW“ιδxxΜαΙε²l{™ΜG/•RƊζUώ΅0c°ΟŒξFՓŝ€lί›΄ξω=¨$Χΰ"Ίo™Λ% ½«ˆΒ< ήΒCΪ₯©ρ5*F­MPΪm&`Π>ԝŠ2@šςbί;#³:©Ρ@‰$A™ˆhΨJΘ@Β ή3 ΛH. _Ρ‚ρ@΅ΉΚ@xμ: %κDL ½/Ε¨S m½Κ}70ZοTx"§–!2< €Τ‚Tή›”bΦ$v*T d¨ <,”ψ&lΗr‘:p\XО‘O³|ŽφΏΆ΄\'”‰h-©ΗŽβ Ε΅½8“v Ώ™ϋΝρ›Y\~X– σΙλC₯ƒάΒ±"8΄ψΊž£Ρ­.~ξkΩΫ:Β‘}«Ο˜³6p§*ˆ˜Œ¨SΫc €  epΔ@ΟT”NfΆ(G̚%ΦNͺwzΩbΆΣx4I₯ε―“χhPξ|mυ~β Ζ1Η& ƒ…딨½MΰŒΒ±e$f‰Α0ͺΰ2a`―8ŠΆg4I%°g')H_ΑΚ¨”i—9·7ί;ΎώωpRαlϊ@+Α›”Ε,‚”’œ v€'δμXΠ:Β_AΐΠ©‘ΐ˜γ]gHΣβmT8wŒ^μbUψ]]ΟaŒ‡5 TyI@ŽTd€ uΰ ½”žE<`-šeh0g^λHŒΜt§…Fƒ΅6k„”_Cz άrη\Ί4H¨Š(š8γ<„ΘΉ`@S9αŒ[e,qήd*œάl'Αξ¦P_½nη*ΙΈ”ΰηΪ‚€od„…PBP-ZΙ`lLUςyπ‚œeœ‘qτρυ₯³Ηξl•;πν₯©ε1ŸY;ρ‡οζΩg/1Ε`Wφk|ϊώ<™–do/Mρ½H_SR΅²θα–ΎaΤr9ž§ΥxMΑU:f5ZΖUCΒκϋ©p…*(°2Š(³ Ά`Ζ£υ.©€xf8ωQ[fZ+ζ RŠ Θ(ΊΦe„ΤΡΡ5E,Υ»:—‹,eNYͺ³ˆUDJ&V˜Μqaq³n,©AΆO6#‘"Ne23Ιu‡jίvω—†ΘR4^K穐8‘ξh&ΐ€)eNθL‘…RV ‹Ϊ&D@Ξ:©υ62sOΛΙ,4eψΎYN€‰d„Aθ Θsn}–LD’-¬•huΘ‚s,Κ`€2 δ x@Κν’ΣVCτΣ§ΘώPκ ŠSŸΟαTΟWOXeω)ώρΘ^DW”§κ[ΡD‚ρΰ±ΚH&hΰ(˘ΐ™‘„hΈβ½Aš !FhΒ‚J‰*Ac–˜ubfμόΘ­y/2pί§ΙCΧIπ@°“1•EJ¬ΧθΪ@Zad6P‰~ Jˆ) œΫ5Οε^`KcB”Ÿ*6*ͺ†oΏξψYα%2ρ£bΙ ˆ$N¬mϋτd½C+Ε₯¨JAΕ •Φ,ΪBMς4z.΅ PW’)ΑB¦MF’pp$ΰΛ °V»A}Όβτx7“YίΣ}Ϋ΄“ΥΐΰΠΨΐH-μ‹,JC‚½-­Θd€6Ω¨(Hΐ˜149i“ζIvΒ—νκwsα–ΥσΉ²α>NΨ>ό΄§QρΫ€Ρ19μEv΄ŠŒ08¬ΌmXΨy(EΑυ$œ1ŒmΙY£9§ƒ;r NΧ‹Β vu H3R•Τ!0­ π,MˆpN :εbb΍9ΥfZMEŒ ΡΝcχƒ=ΆΤΞήuzϋ— εΪ/ΟEόφΧzƒYh2Pί`σJA’6,‰ΦHχŸŸ{c»vg£ΧsΏψγK3kγM}ΣυΜSI€lQm8όKΝ`±\„Xm %›¨³Q£₯Α'igy%=Θ*‘p=ϋοΘΠ~m¨>ϊ&ΘIε1œƒ §€™6³ Δ'JAŠ’Μ#@&F` Nͺc–K43ž£NλΈ‚[—GξψσΧ4Οη ύN8ΐ©Ζ; Ηώ€ͺ@Δ".Γ +±,%ν]άq,Σ ΦD¬Θ“ψΘ:Υ"_M'½ηWX" =DK!#‰`Φ7\+ °ž'Rγ@£L*’€Qω·Η3½mj>D(8 θ2ώ²ˆΛe~L;Σrσ‘3UΚŠ.Τsg‚ –A5@&±Tdθ§“ΙeŠS€ΕŽΆΤkE£Ε$PΈΊljΊ¦ ¨έπbp{œήΐƒv(r-U0,%C² ‚›’†ΤΘ€‡Ϋ5,ήL JdΈ…kǚ;­0šX–… ~Ι]•žν§άώδ_ΦΗΘzφb§ωΥΟ‡δR ΘxŒLXš΄‘V*Œ¨Ύ˜‚t$)K<KPζAšV?Ν¬Σ&užnYEυ‘·ΛΥυέ‡ ΚS [–0M` ΔYržŠ°U.“@ΌA\π@ ~hj·„"ζ ½hχ0J¬xmΉΘQnΥ–“ όΘEk3μJ)ΐιtFMŒ“:bδ2Λ, d`§4θ##˜­k<ž^Α’QκΘH†>m$lk°Fšρ€Ω₯Υ`ΔO²π7œ-E™%h₯ Pˆ,₯ Νlˆ ζ C ‚]ίκ¬+ϋΩ±aΆϊ‘f‰68Σ·“’GΊΕ’·ψ#Ž2Ψ@4HL’σ6Θ=,zpω€J Χ`ΤFΆƒ4_3ΆΎ|Ά‚tΗΐ1R(Ο_jcΩ»φ- Ž¨Αθ!u–iζau“0Z;‘2`šΑJγΎtΚ΅J£™φG…ΎΚxl [hη@ηίμς"νΖM(ί³―(8fίΦ,)ιI‘ž£tL™+Νη«ΡΧ2@ϋqœJΓx o+5q%–zΆΣtTk2}ΛηOγ˜Οφθ5GŒκM“"j •ϋK‘ΈΈΠqT‘£[΅ –uiΧΚΐ°ΎVF›²δσφΣώάl’=ν}’O΅4JWŒ‡GT0—]άζ§FΙOmY₯[χz―‹έ§ΡQ·ΓE>oΟ\΄ N9NΤ²f6›6©/k ΉQQm<)JώτŽ•l.Αώ€ŸœΏv#(μΜή½M“±6γ„qžIΑ¨ΰ’ˆNZrη X₯£6oρ1κ 8 eo%o_ʍ}θΠlΩiŸ¬ΟψΦweω6―܎f/icηΔ\G¦Ο7ŽTί9“Z2.70Iπ)Ξ%φΑ0•IΗ… l*QMΠΞjzΡΩΒΔΡvMσΎΜΧ5ΆΈ\›Ϊπϊw¦TAp,‚ Έdύέ’‰l³€3fΰ›PSpA‰ΠGΛΉLaΈμκ<ΔλΠΆw%›°Π-#˜fΰ "0^8‡Rbh°Δ ›EνA^§ZdΖSι=©50έα€<{…V‘{i Ÿ£¦z­w«« ́¬§³ύ¨`Ό',‚ΈGp‰Š¨A†ύP$ΘOΜ~ ‚Φ}Ψύk„Sΐ1Α6 7ZQiŒCΑ.ƒΣ(#1JΓ’sδ ξ0’ φŠιΰ )tχώΙN'v—Ηο=iq™“K²PΣσ /!Α:²Δ@lς)((ήp⇝β“Q]*?ž6$…Ύ₯>βc RbX*ΖΩ¦)”Τκ‚Ι0΄5AŸ΅qpψ)€$kSβAˆΒ=©Ϋ5΄λXAg½ΡχIX•NVί’šΩ—cσ5y)ͺΏ4” ½+>₯͈Pΐϋ²ΰπA-΅ƒγΞ μ‘BL8Y3αDJ2’αD݁ψͺξcvŸ}Cbωa”Π‡Ϊ6nγΨφTAψWJG»ΡŸž βwVη)ϊΙxP))M”)2D>y#­2Ξ)“¨70OB4_Zΐt&‹,Λΰ°©Λ"ύ4_λ& ©οc` eΦΚ€¦Tθ;t‹§D€n«œdF‘h Ј­Q(fRX ηι”ΜΎρυϟΰ`qΜP―0‘„VΦΜ:Ο{hK)'Ϊ»cXGΘ’pΏ…­Οα`θKΗ7³_›ΦUΡ·χ<‰ Z(@¬Ϊ*& Wδ„ρ7τ\φΡ‚ͺM1e†F‡Vͺx—κΟ}nλγΚϊw=f Zh8],Pρeˆ#:€e°-aœN`ΞHr€¬²Zy§-†&9ΗΟ&―δQ,η°G”Šΰ.±»2Jώ<ρhŽ£θ΄Vjšq2ž—uΩβq§‰Άιcύ‡ €κΐΰό‰8ΨάKΒᐃœƒή1eΪj+ Ύ,Β<€ΐ€Φ}lϊtΕΣ—UϊΎώ…ΖΒ―$¨ŒTΟ fPˆLyˆORZ$?ΠzΑ"£–™“Μf¨h8{ίτΑκ<±9§Yǜ2Φ˜ξwΰΪ£{Dζ” «b₯΄Ζb}β™‚‰uTJ@FF¬†9†sΟ ΚΕ©ωΨζlΘ½YϋΐΊV˜ΐ|Qά#³ƒ­Θ΅ιD9-Q ‘ ΊΉY+#“„*bαΖ¨©¦ο˜}˜›ΰ’ θ?hŒ;ƒ‰θjδ1΅ ˆTFA]²{…α>d„fζHh0I΅SD±, <ΉwL€ΉdZάΜTο” “ζ+£\ €uGF@䊁%E²r S¨y‚₯<`Δ(:ΐcŒ@²ά=^:”ώ7΄γVSλD&<Α TŠΈ€Ω5΅Δ [Βl šhβ™Η”Μ2šΰ(K=…h’wƒύΈ’VΑ@pΕY2˜0ΪgpZΔzul(½@Qτ΄ t"#™2ΦQo€«f)aΐρ"‘@^{{@6Λ"zζDΜζ`S7Q”•³3tͺ7;U?_05ύΣ άΠ8‰΅IπD€ Α. Κy˜― 8ͺf DF½ζ”„V Ž₯cΑYU—L>₯M»`j»‚Σ1Œƒ†Π²­…³}YˆΦ€*,5€:%‰&Y-W4E‹¨Œ,C“Η%Ss±βμœ)«žΊΆκ1’›FŽ·@7 Cœ©aΗXn ψ,1In”² $Τ'&aCΑρσ™·‹ζMΙ‡ΪΔμ n8hϊ·€u’¨’:EL΅ξΐΉ{Ι3CΈN:©Δ3ΙΉ H©φ€qv—ϋΨ}›„˜·Ί›‹ήΣu±@θ;eCηJnWBDs!ͺ(Μr!ƒΖl?RI’vVΪ‘ͺͺJNU9‡ύtvUΞUSΏ¬'aδςόϊArΖFηάΝ!m„u }fœ=δp^΄ŽGΔ ˆ<1Đe.h8"LΓqΤ[πM6²eͺ«₯ͺŒΎw·£’Γ±χ.+5 ½κHΚ40`Δ#š+:΅)’GωΦf\‹@mHΞθ3Cu%θΝμ›‹£υΌͺ¨vα4το07`Œ4™€AθH9r@"žλ`§σCΕ0˜³μΡ*ΒΕNMκ¦Su5rοΘdl-Θ ‰9Œ€<Φ`, •™7ΐ«šM@ήABΦa1.€ͺ-ξΝΔρΑWΟ“N³€lΔrrΠK„Qq4 ψ}’Ϊi—2›ξ/ΦΞ€ {gu°mp+Δ°^Ψ)΄.k,μ±bϋ_;…pM"ζΪΐ…  Ftr01±ΖΫhM–HŠΉΓ"J[4Zey»ΈΨ5ή x μκ)¬œi^˜h²ŒΘ(#Κy₯αΌηΙz—aώΜ˜7$0r$K,Γ@rPκ GΙƒ(Y1ΡSΞσΑ.¦-IH7h’πPΉD”εΠΓ's22A•O «X‘Ρ–B !3n˜χΐ;lη›UοŸPΣSRΚͺ‘ΨΖ'G]>wυ‘'β3R#ρ0!7œhά“Ο¬fk:η9ΗLtB΄ΐ`Ζ€‚ už6‘όh^=y»<•Ιx{“UžΩΗΕΑD^}ŠμΛ’° ¨ οcL*±œb&‰ή‚8DŒHΑΟιZΨ"€?œfηνŽ39@°+;BǏkλΨΘq1˜C>LΛF₯πΎ‘;ε ΄šΜJŸq„ΝLΜ׎% £@Ο ž }Š„zι4VMH::‚΅Ζ"?SMŒc9χ6wΤ%yΡξ'@ $Ή 'rS@›€ο"e ―›”)汜§ Χi£šΡζ΅;sΔ[°»ˆ!}Z/7”ς€H?YΎ  pυ\°ΞrƝ3Ύ‚¦“@_u3γ™ζ•¨φB2C%΅˜IDΉŒu:{b§φm˜ζλΥΗΐ ,€‚ƒiTΚ<¦ΠΡ³P%™qΊq ³ƒŠϊb΄@šΠΑsΐρνΤΎιœs4­’θΡK>™1s)―’απU’—IT`VO ΞDq<ͺ‹^d0=ΘΆš#Ɛg ΓΒ©ΆZ}°hΛϋwZ°ž:-©ζΈˆπΜZ8 1=–rcΔPΓ¨`1aΊ'{¦ΌΑt0:§Ηx4ΑKΘgO%ό>9œ [σYY‹oƒ Ξ{ϋ₯ 9>ΗtΣ£Ε²‘S­χ΄ψΜ]Εθ@F9 …YŽEΤ M OAš†]I¦ή‹R+X1P`~&Μ΅Λym*Υ»„Kc³HΡ³,I,κξ„€Nd–‚ cfWΖb…TBQ„L)-?χΚtνΉΐ±η,³‘‘+*ε33N¬E ά-8!F £ I C%Φ>jXKVΧζϊΎΘW-QUύ§;5π°»@Š€6 "`RC$Vuš‘™EΨUr@,ƒu"%P«€hȎ΄Ζ]%HλRΚ„ί2tόxDk]ε…'ο}ΙMΚQ© €'ZNBœsτK! fEGΨΤΜ(‡sˆΜ*ψ )vmΪΊψq1σ¬€ΠΪrΤΓΌΧθ΅]‰Z˜w—LuQrMΜα“oΘ½[1B.8†U6‚βΖs—),5‘΅Q°u%VdΓ"σ˜Ά£Άΰ4S¬:¨ΧuΪΆύ_,ΟδΣ,Ξθ­oΥ+· ]QμΊ¨¬η- 3ΥNbqi‚Υˍ˜'*&xβΜ€"šH]4]-˜κ=EΕ.J‚ i†”pΏ` N ²‹O6rΘH ΞpΙƒ‰ΞsuζΔƒ‹B¦Žˆ"YήΉeάωυ)„ψP&qοή–Σ(UήΘmۊjgξ˜ΝI‘‘η{° dp¨LΫΔ4 θUŽEN1€‘γό»Vtώ­±œ}―&OYŒ Ό˜ΐ6_fю,Ό Ϊc¬*Vx5h TΚ[Bˆδ€cα„ΫήυM}”†ηSίsOSFΐ:!±t§ΌnaぜΝΑzqφ#51Β©]˜•Ρ ŸF¨"Uυ» ΙΌ?Φt^»±Δ”J=MΊέͺΕ·EŒ(‚·KΰυŒkυavνΫεQΓΕΩ³κ~·Σ―Π©³l#ψθΏΧR8jή―ήπη,‹¨6ΐΡ„ρΒρ$%FEΑ‚s˜μ…jΓ²\ό0·pšςΓ—yl6O$σy XŒ‚ŒfΚ,€6nHg°­0ώ/p¬8΄τ ΛΘhωl1œ9ΰΝέΧ.ΓJˆ#§JiFŒ‡‘œΥΣ}š±Ι°HVĚ³&sΚυ$γΠ[ΰ:)Κb† €BqPΖ5ς^Jθ°΄ &Z‘€Šd@,’ϊZ2Ψ³€>AάtA#ˆœ™Fπ­— ΄ΠΓΦAΐA3—VΧ2nθΑΥSΆΔˆgQε šz―2ξ–0§JΩΘ±0ƒ± Yi‰eݏΤ+ Κ€ d/ί.OnzfI·ƒΫk{΅Łε°p„RO°ΐ¦Α2ŠJ₯Β―\Hκepοΰ™4Ζ pyXάb:“Ϊs©ΣYΒΖς xΔΒ^½ΚŽLΜ ‹›X0AbuGΠ}š*„Θά‡SœaP…eΚ£ ΟΌ]ΑςiνŸ—;ϊu²π ί»ώ-+,fZqqSΦB'‰³\bu ΨΡΏΘ"“&+ρ$«ΠUa –Π•Αœp8 Ό₯yο΅'€o”G=Γ5“$Γ,³θ“Σ¦Αx.PΑΆuSkjΤ{Χ–X ™!!i2QΑ ˜4‹™tŠRΜ”δA$p yπΡ„1" οŽ˜ωn—Ηez=ӝΐΎΌ<­ηΗ’«ΥvΆ΄½ )›«UΓΈV―˜bΙ­ύu«ͺn„Nž2Ζ΅„Φj’ΐžΗ6οΨΊYt™-ήg7:ͺmαχΏ­ςΩ²­ΚΖ{£ˆα» )΅zH‹υn>Φ>T’u“09h(Λ·t8ρΎNFΥ}εΧΩttΜ&τ³χeΛ­νΆΆΏ²kηυ:‡}σpκ~IΚ’ ­½lΛ‘μΥδλοΐTcuS’½¦’<ά€j/[–εIH` zy„ §ΏΧPNΫ‘ΞΞQu)³χ%[κΡ'Ε%{‚osV” s“Ru!eFDΤ’―Žάk¬ ΦڌΧΦΣώ:[|ΏΚΟ]$…π™wν§HR„ωɝ wEˆΝƒB>Bh…3$$₯α'ΙJ”‹$ο&e$η@Ϊ©Ÿm½œFjCΔZ™˜_σ`νmς>œ₯MM»7Ϊ‹oRό4ŽΏ‘sa»sξ† ±ώώ‡ˆςΆω|μK{ηζΪ[˜όγ»Ψ-\χηϊVΝ―ΪτBΣ­₯ΎΛΈƒπ~*'τΈ-ε,„τ^ϋD΅Ι!Tα^„ ΏG Ίψ‰U»[5œφVpΕνta-7ΰnͺυΉˆ wցŸ_ί~ݜOΝΐe+’—˜z9pC2Ή›¦(ΆL=…δ\o@ΆΆjtκ£:η'ηπxΘ…g~£§›sH%5π…¦1XςΰG-Η³°FίCdαž@vΤ@ a Š&|΅΅Œh•^ς!εKΧ:K§IέΟXνXg‹LεCωΪo=½΅[Z"Κc‰οΞ Άοϊχχ§oτrσe·d ΖάƒV!€glšͺϊv‘ά"VΥsc_ΰ₯² *–’–rσ "ώΪeίDΣΠπ„ΔξZΞ^^Ÿ¨ςύšfwli·+yυ]γ‰―@ΡQ²>}am©FκUNΊ‘dέirY±‰ZGΖI‰FΔO€nV¦]Ά©3ςžyψ+1mΞY¬ίxkW¬₯…Ε».„•Ξfν{‹Θgœx•”j±VbΦo.F:Ξν²ˆ­_‘GςI,|Δ‹_Gk?9Γ[­­Ρ@y‘6π©d°ΕD΄0.™˜,ΔI Ψ=ηδa˜§*WΝ©+?6ξmά?»θ—Ξw©λRΓOq΄œΚ™ӏ±›υΫλ Fΐ‚œs”ͺSj<₯ώQͺ™uΟΨ€FΘXΰ}PΪZW5ή™ˆš|ˆ<―Μz:7Πη§Ω‘ΪΘye;kθ t1ηζͺ H¬ͺ3N€‚:c3¦“l%ωTπ5Hl PΗJžξΗΞ3τιυ°‘+ψΦ«±dŠ”t›ξ©8έtv=•ήΘV*, σέ1ΦRI){f©ͺϊumβ‘3=ί<ϋΟLηBΡiMŒ$Xψp–‹λΫΨ}Ν@μΒ—LΚΪfα"#ɝ.°Ψ]΅?ΦFϊ©qκι/,,ΔEΐοΠ°ΎAαN’κ=k[zFΰπR+֍žΣE‘aΨ;φ)RΖfγU=ΫrρpΜ@’'―{“BaΡPYξeƒMH‡»ΰW*R3_h9‘ΟζΉΧΖ+«‚κšΒΏί-J+UXMΡφ|ρaΕ9ςQ{ϊ|ρΜlŸ¨4œ^"ϋδC·IvΈP•οBΦ$ΔΓΙΓέ±ll—Q­—#%ΝVΎpvMm¬4₯ݜb¨YηŒVZEbv蒌Θg ‘mUτ Α›δψ}’:θRε [μ,7Ϋ–OσΧ·›Χ!q¨±Wy―ϊΗ[θΑv#'X©ͺj •Ή3‘ΆjA4+Ξ(m€ΗoςΖeΗzom‚!Š’r=Hέ2Χ §,( N³|™(κŠ7ω ;€ψΰΗ$-ŠήΫ6ζΔwφβημύϊτώ0{Ή[όξ‘Ÿ^ωߐΦ$Q ή―ƒζbεβ{ΕΎςpŠΊήz2ΞpΜ,Uκ5v+’ΰˆ2άΐW‡£ση§³γ^ –SϋΙ;Σͺτς:R0XΒΘršg³,<ΧΨ­Ϊ ΫJ‚ΧQͺι ααΙ£°O9ώ=—~Ω·o§ξ’·G&τώΤfί·Œ*‹αΈku*΅¦ny₯ε_±LwτϊzΌT“38‹ž―γԜΐΙ&ͺ&œϊ{h―Κ8}(ΔA Ώ_ΤRι ϋmαeΩKυ¬Ÿ^„ƒ%Α4X¨²a…ΏzνY“’ΕSϋKxφ+ko€υK%ί0ΧT‚έΉ”`ɚ(fY-εnΦ$idJ:ΔΛώršΞ™ω'λf¦ήΫQεζ άL.ͺaμK·T`€C‰;¦ΘFξZ”Κ-±-6ΩPΛΝ`Sgη€1Iιρ3΅»­ξΧώ₯ΨοͺΜΚu¦zέ²\·›-5λξ-#€Ξ›pc1ΑVMuΥόKΉ[―KŽ;°ΤΨ).ˆ WΨμ¨OΎ «rdΒS—‡8㽑ž<)T ͺ¨"β° )­χΡ3Ί΄pδfQ…pΒΪθ»6Zo€Fω²ϋύ=›Θ·ss;$›C‰³Υ§ΰ³ν•¬ Ξ€Τ™CΜ‚3)ΛτJ“\B³ϋ΄…ΫοΨαoάΓΣ±ΉMΞv@έ ΙP²ή;Ν*“uYΈ*έYλ­΅Κ°σΞ₯Θ+J#¬’wΦΌωlΗύοίΑKOg&ώγ•AνωΤkΏ Φpk;FhχΒo57γ#‚˜…IO\J ˆτp9I}΅«½­0χ‹f_ ϊ†ώttFΏfφΒw|*'™ΌXΑεX2,ΕS6Zd–”0ΜΐΫθZ+ω¨gmb·›’Ιύ@Ί΅§]ΝΓ'­ϋZ«έωπ[[nΥ"£·ˆώMΊ”«+¦Φ}ΚEςz€χ @6jερjT9“'eUoΘ.΄­Sxΰ‰MtΩώ ‰˜w±`—sΙ¬„Π¨jHΔ¨DŸz²1+νΌP€ΣlMμl5RγήGηνλ&‰qNς5“vή¦i¬‚!ς^{tKb,šδΖUJJ9@κ­SΚΪͺjΡ‹’JΒ nδ0β;Ά£n:5δ:ΐάMΑ¦u¨6―½fW΅χTYЧCUV”€ \ œ;‘ςNyΫΚη§η‹“±rj7Ο΅Θ!SvʸМv&ΥhT4d# :E+²tBφλCoY ©WΝΏwρΥs§ίΞ§†AŸrk‰ NOΞtWœORE)”β¬GΨh«€Ϋ―”œ…ψά‡ΰ‰l­%Φϊί—YJωΓ[½=βΡ‚η›6©OΙοΰY·j„…Οί₯ΈωŒ<šV¬΄ e#‡O©v}›ˆrΡ@WΣσιsηΧn―δ“E”Πθβ w½ι•C4ξF5)ΑLΙωRŠo­#€ϋ•λΩ Ϋ‰φΏrΞΔδΟZδχS!θΤDR/S2ptEφmun­:'dŸΘY„qΘ&αQWkΌU5'έ |nς%ΣΘέά£9fφœ”‘GP(’‹XΎDNmυpCΜΖH³™ΐŠA#€dόP%!ΆΝՍ)Χξ₯ΘςέrΰC\Wko;_ŽiŽΤ³δ‰W5§GΥ^ƒκιFοmώMx¦@ώ‘žϊ{Ρ ΄­mθBΉΠ“α&jς2«ΝΩW»"—‘Dι†LΜAˆS=Bp Υ)Ηhoφzn-’Rzͺ&VΉ# ΉwvΒ\$X³3ΐ{‡ aBPƒP©θΨ p΄Xv#§σλ¦Λ+;¦Žk₯χ:£ΩϋR/Xσ/7Ώύ .vδŒbΫ9ζ,…ΘΚR+TCˆΖΚΒ%$κΏί”Ά’2iΎ6εώΐŠξφ„RνΉ’…΅ήΨΌ¬eω―‚'g(HB)ΨR4¦f²AX–»_±ί‚ ‘…žr¨¬ ‡ϊd*―\‚q,€+Αύ1puκΣ}{{žf=؏›ΉCςΌι4[>ώcEΎΣ‚v~OQΡLΟY{VK½4Qξ±UqD` 4ŸKk8x•‹‘ϊΐΒ* ―p¨Ίθύ©Ϊ›™ΡqΧo7ηΛΗΨ‚γ˜6ˆ)ˆ­ΎZg‹ν.F-|N€t*θk6+R[`ΎXro @p€˜xΫ#ΘΟόςΆιΡηβyφvGevϋώΩ’} ˆ †Δ¬ΊœJ΅ij6½ζ΅π eνTΤΩ#KrpbVgΕ”G‡χσζ £IyeyiΡΣ½W‹άΌΨΒVG›\’ζiιΒp]$ڐ€:Ή·Θd…=}<βΉζ ΟG΅όS“ykSE}{ΙdURp½wEϋHE•¨αˆ6ZΈΗ?B ήjφ¦Y!2cΝy|{~ςόύΈΗOΟI½v+-x6ΐ=`Ž›Ι%#§,‚ΰ’XEΰςά”άe&U1,5₯‘”³ >»gZ|{]θ7θsd”ΗhwςP*’jFvH)ϋ&•XΑ(3(Z*“£©Ί” Χc²TΕu΅Έ#Ε͍IʌβΫΩY%¬#žΎκΦΐBCΖΐ‚KΕT―aΊ › ~Ϋ‚w%‡Έ/"YΈWΥ-’rΟg, ύηΖ{WζνΧ)<3νJtΊ&a.,RL df ΩVεŒ₯”0 `n»Ρ^Tsή›|ψΘ°…lΪ•«|9{Y%%彟ŸZ\Δγ'?}/Rυš³T` )”ŽφŒ€ŽΑβ³PΣr.οrΆ΅!ν“Πͺ[Tx2–1wΆ(9Τ’ΌΘ²j’„ΉΦˆη4%&'6k @$₯Š€¦ZΉΤ)€¦•D‡τ;ΨG“μ_Η…‘pxςۏšœ­Τ\KGb­s.ZΐB=Γ½°V™ΌΝJΤ„‹‘QΦ ιdC‚ξΝ—ςqp0TsZ–{»E7ί ¦9μνωw»»ό#Όπ›ΩθΤϋΝL’Š}:Ω«?hŽ6Θζ»½’υ΄~󍐦ξψ­Ύξ~χˆw΄νPΧ/Ξ6Gu?θœλ` wsLτrωts‰€ξ Oz(αΡΈK'’2¬΄%™ΰ₯Ί(€€ΰ‘θΤs’z9«Τiκَms―ςZ[1φγ³ς—oάξ%½ίtβmζfηλναά‰ΥZΏεUIόωyΏ_5ΠuΔMξIJW]MΙ“EΧηEΓ§ΈB©)’AU\UVBU‚?τ€ζ­-Γ9ΖΛ»Yηι-ΆμΤσ@)’c9ώΎl€ΞΆΦκ|UΪφ8r+ aύoΦz/ΊΙ+=]δΚε£y™/žιiφ― Ιζμί7GκΙ;H’(|$ΤΚ5«`ΓκV3&9¦ΦX``Ώ"*ΕΈR%»€˜άhz~_“ ”FΝVnύ―W~Έk,S²Ψ–‹ί©r»><Πύz]σ.+J»?τρ³ήΟΝ―Π&œW™’ςΜF-wrπC˜(Ψ΄ ω Κ¬Bf₯jŒΖe«U'―btaduΊΨΎuαϋ³Ό7Qc3°9E?<ώžΌ¨«-¬ιN8;Ω5NΔ]ͺΈ’άΞ±ΉZͺFxŒΘRτΡs@FZw<œN@΅?¬I°6§Ίg»ε[ΈυGkJcυ"vM·97iΛ4¦UψI PDsαΕ1&€ΪQT‰ΰuD\·UΈoΗN~1‚χ·{ ’Ξ·WεΤ™eo€“₯J)§*7x‰«ΙHkΐ#—`΅φ¦°―ώ@χ€$kXtτξŠ qt‘5^n―Κ4²^f.rϋ[’ΞrΣ:b>΅Yh’»τ˜FalΘ,ΤπιΏ±Ϊqυ\C`UjΣߝ*ίΎΑv`Τ@˜γΪTPV”QV?"§oެOe M Υ"!Ž#ZŒ&UάJ}xαΐ λfŸ‘}ψΥ­κ€™ΎύΊ«σWάm―’Š[Λ9Α~μHcYΓb±]S—ΖΠΘΐΨJ5εq˜]2­¨ΌFQΎfυ…Φ]jΎ£ωΙαlΘ©$κ½yαnVβθH€cY ™\’ΞQwΛΊχ œ)?Cb£Zα*³—-Wή9™ξΝΩΟx»Ψ:XίJνΒ] ‡Χ>[άΌΏΟΞάZ \xCΈΏ}΅‡„ؐΒ&t.*UiΙ·ΩΈˆ½l΄Ι4λ%ΰ7FόΦ8(ΐG.ΕέΟ o~ P¦–)©ΐTU]lΕ{$’Νvϊ ‰9Κ=4ΎΜΪε„‘²ˆž…AvGΔ“ZKcμρŠ倬ΜΤWI‡S·ΒˆPOIΙi5°ϊδ±2Κ·"θDN7—KAz—” ɎHόΉ»ι­ΔΡeΗυΧΛΡΕΠτ–”"biFz₯+ kŽΘ„Š΄PΠ–lτ€NI˜KBee—Œ²Fr¦ΤΛV^Ύ§΅KΖ&_m>Œη£Βf}¬σφ8ΓV]Μ:|γSr¦ž@+$—uΰE©₯΅Ψ»«έΐ- zμ%“Γμ#r(4Œœ<;a‘Ζ5/ΒPz|(GUηaQQ3t-Ήb§£hοεPΌ·ΘWZnp,i§#ΟRU₯’‰%sμν ρh/»ωΙrwλSΚY%«³₯5kŸu,΄Jl2+=ιΞΘΗ…ϊžΦ4ΥOu":—D΅<-k•'Χ,πδ\ ΕΘώΎˆ=’oΙeΈ…p ͺΆ”"ΜζD£E8I±GͺM§/γΠςω›±=πΩ!Β9U½¨ϋ“υctV‡Wr«‹Έα_|δ{•Αρ?ϋ•9-ΪIeΚ髏(§Lˆ²@―1ε’ιBΪo¬+RΨξ”/a Ν"ΰf_€εa@+‚χŒ\ZξU‰|Ομ νΞ‚½Α„θ$Υ¬Ρ&$ΗQ—Ž0¦½vmpΨT-·”=Ω ^/tdqΞ#™ΦΊ΅:β垰‰ZŠdω—X²…ΞyVο ϋ~z:.ΐ©τς–»Œό\Δ—-φ^;&ΑΪξSœΧΫΛς©―Ÿ—§ˆ―›φΩ4·r‹ΉΰΥӌΩ%‡TBΉxΏžμΩ °λξόμ„€ύζψχ―εζcΰΣ>’δήSΩ=ΰά^sΧΑκή αΎΪ}Π x·qΑ,Eρx³<ΆΔΊ\ΧY‹ΟΨε>οΰ-LΠΏ>Ξ_ΪbFη tΔ"ω>«ί6Z§­qψJ˜\gΛε†ο†Ί΅ΆΛ†tΖnΞΚκψwR7v.ǝΞVΆΕKΧXΞ‡«ήω~ηΣΎδώΰfuωKϋ”οϋ’‘=±άλ.ΟΪ§εŽάγΦΉ½­ώ’MNθΓώ-6yυίo…ΣΩήΏΝΨ>icŸ!±=g=[8\ξkζxNFŒρ_=ΘKΪΏ¨r7ΐΧTIE/Υ™"lmέiurΥd ΅bŠaΡT/¦υŒΜΞy_λTkpαΟρ! Ϋχ°škςS«šJωnΩi)VΑydFŠ%ΕΆ-Y_ΩƘIτβ•άΰ·ΒZu?&$‡χΗηSŸC6­+έ΅φ›¬eσ¦ŒΡ™ήίTΙ5vΚ^ΘPu6lσΖ{δΦўyφΥΕΓ­ ς’dπ”Ξ§{Γ³Q’n’ …‚Ε\KΗGdΉξdΧ|ν–»wuχΩ„~ϊΐ}˜ϊρ½!^υ°R"Mέ:l‚½Ό&δF1)²]„iŠ/ ‹ΣΉ±±0άQr«λΞhΓά*9¬ήθΚΜJ+ο§h¦ΏkU²₯ζˆLΩq+₯GnΤϋθ”KRuΧJ°η h¨yέ»όŠκΨA#ΎΧτaΘƒίψφ-{Ξct΅L½/1cς«7Ν+i{•π~o―UuOγ‡Ν ΜσλΌλ”¨—Ÿ‹―ξ.=μgU€Yr‰Μχp:ώϊ;†Riμ]L‰•xdp’’ΙΒKZΪ }@ƘS± šΆdzκM…b―U­ϋμ όλθkϊžΨ2<Η”Ή]œκΐ=χB\d:VέY§‚•ζJεœΛ*²MΘΑ„_b¬|]:Γo}W…Χ 1 “|Π’θK«ΚέϋnuQΘψ‘:j—©z!Qs6·;Ο…Ξ<ϊγΝkKB+Š€R²›ΊΘ3§jr+Uͺ£\Υl]m–ƒE$Ώˆ*@s‘:}‘ώk}#–‡©βΤ§SΑ”3ΜΥΌk©ε*κFΆJε’3:ΑΤz(>θXI*¦šp Υχ΅|}t›¦+oίjE&ό&ΥTw»—nϋ·r€Γoό":„υ}1{ϋuχ:šΥ_ΪƒbƒΝΑκ³ί ΈΫ9’mžΈ!=Ω5xpW%³Sfo›φέSZ―Φ}…ρσ¦τσεn‰Θ±o2Έu­6R„ωϊ‹u׊W-Ϋι’ΆdRΒ”.€ύpϋCxΞTΤΩ‚ξ½SΎ`%ΩήDj©9G”ΎΠdnPaw0RŸσJ•»Λ?ϊ?8;Ž’Μδ,$ΖuQE“mΣtm-9kώΕζΟ‰3WH*1|γ4ΌW₯_πV;ΛBςϊΨ7ήΛυͺ€ς„IοΎ°χNl=›¬U«η­²"rX_½΅Ι…ά\³L:62¬”ΙzೆŒC’δ‡Ν΄2Kˆΰ­H₯ѐφ«°”`½4Δ™τ 5Pλ ΧfЍ’Y―˜αΨc0.Ω`ΊUVY§δΏSDN,½ ʬƊ³W§SΧνˆE‹²>k?\κρ‘Ψξ!ΧΉ#¦KΨξ™Ÿλγβ`-¦Οΐ³.‘θˆV€Ÿ4˜;z`Šna:Iμ;–&Mγ΅FtNBrdόθZΔ―ŽονHγϋ}9¬³ˆϊ°3₯„―nͺΚR²ΰLθ€υΕ!±R-[φ™ΝΎ"s¦€„$›vΔg‘C¬5ώ¬s*• ία!¦Ξλ‹­cΚΜeωOLš™>2HνL"˜½·Α›lMd“*R±³Α …½έœ1»ΰL-†μ;¦΄ΦώιIΫιVύέωJ’‹>WLG‘ηLMά¨ΐψζbθ•W£₯hηEΦcύ½0βSe§ς™§>Βsγ›Α‘ύŽHŒγԘ—υ?ψυΏγΕ[τRw8`x«Οω›ΤήB0­HnΡκb€@‡uΐ„žΤ^yΠίλγrFwš-κ&°ν½΄mγύ l;Ρs²fgΨ2·mΥ/•Η<mpάΗξkκ XtΤαΐ:ƒ)J-)£­k>K:!ι2٘s”Υ€E^©ΰάIφ¦@χ`>vgαΜΠίΫςΘX¦> ^ @š³ΓiU­πή.›R’˜:~ΤUj0(η½j֏AVa¬‚ρ„5<Ÿ#ΛLδΦ­δ«/ΚψΪ(ΕΠCΰξΰ™΅νYs©’`X‘¦bπVά€"a`CŠT2Vύ₯ŠΆ½†«[—mdΔ €ή&¦¨[·ΊZ[ΰ―zδ"ΈΗ&Κ­>t%M―žΈεŠΔn>υΠΗ@Δ|φΖχΓo.ιΝ\YJB ƒo=<-aΗ—!ž;—ΝiV菾ΉKxωpenyιΰφSiτHGΩΞ‘οaτ•}KΟοOmφύζ ΚιŒHX•‰baa‘0Δ‘IΞB'YλD—Ί:–ƒD#·XΒNW)d3*3ςBt>ˆŒμH$ώw‹εΘο;² Κ±–ϊ ͺ+Ζ¦θΣp죫nΘΎJbtφ·kίx…έGwγ–Œψ ‘Ÿί†Γ²JŒελlρύ~—£u—ιζc³τ; wn°€s…FES”lφ±y9£Gvή΅25 τΦ+7₯Kd@δπNa"ρŽVšΕ½gϊ)ZίΧΕζžϊθwΉ»+·wγ}Ωϊ1_|yωƒ'ψƒψklΎΫ·Ϋ3 Εμ¬1:«sXyLB6‘jϊS8=1ηrI“κ½H­TJΨ\š™œNΩv™”0ˆ»yΟψΟΥ‡ί}xzη›ΟBυ• *IJkVΎ +<@„T+λΕύ7φ0ΚΤc6Φ³*:’k&ΫδΏfn²Ύ›)ξΝ&μΜ¬¬ή~kΨ«„ž)XαN17ͺ_²ωδXΡ%Ζ}4‘^ΐΥΆIZŒŠΑ/$}ϊΦΊΡβiΣ ρQ2p7<ΘοˆglζνΦ!¨:$‘h²•’”‹gߝ³-Ψ0DU#ωΰZš–Θ‰-em“s&…Ρ3Ρ—£©Ρ’LC½{{yXΎρΛlCr~¬ ΅˜Ώ=ΝN3 Ÿ-ιω ρ>ΫBot·9¬ΎΆ]eθΌΔΗͺΤυzρ}ΒϊS•Dkϊγ+ΩIV=Œ_Ώ«Ψ€ΐsξ3ΝδηΘδ1Š*λ΄AΨ«g?ωi9Nπλƒ0β,eΙΕζώ3Νόm@ˆχsXμbΦψ‰ƒA aO䐯XυQ±Υ•pt8Τ;"U“‹ήΥ}·©λP₯Φ’DΎ09αŠ,½Yοz ΥΈ ²1⇧{‘Α“^ο+Ο;·γRR±cXW#\ηNνδOμΜ½}HkžŠkλQΎΈσ–#Hψόv:(~9Ψ»μ­Χo†―›π ­Ό?άΏΏˆάΗ£Ti‰L]0Ό‹6yTP.’ξ^ͺΰ`Kύ*‘#Ϋ­PcΗ[Χ=ΗdŠM°f?o_Ιj4F€Όv—“«Θ„’b)xBΉT7±β^kψ‚ηI9{Αvm•/ηZΟρ-Ί.ύΗΥӐn@‹αΌj砝iMŽ€ΩœΫͺd±–άuTΎ#ΥμΑQp¬›+6wοH„Yύ j,:εμ™ιRƒH±]*"~Tj‚9c&Z¨AΦ`—S°Τ\πζ0μώώ£«ϊΒΰηm1½½’b4,Tœ!%WΙϋΔϋSy’ζρΘa)‹0”ΤKW‘ψ)ιŸO)šFψqΫΐ}(ώ’]š`š ά’%¬YKˆ, ˜>ζhMΨ²Q5R"š %b­ΐσi 8}WΏ*4φζκρο7TqΈn¨αC•όΩφ,2ΉΊ4§X‚q₯Ω¨°zΉ—Pͺr2T1Άzn†₯ύΡ6Οfͺ‘"Xp6₯³ΑΠΓi=Ζ!ζΧG{Ήϋ…QŸnŒ›~πΐœΘ\—αΜ`›H‡mf%2Ί, Φd’1²υœΰρIΔ tJψϊBΠώύSξ‘NϋΦ·oYϋ’ 60B²ή:δLώιTnΐmIy©¨μΙ"£¨T—³ν.LζΆKo£s*ΉηŸ•_ΟΞΛϋvΛΨoέT­©5]‚ΟlCΝΨΞ5‰ς9Ε %ΞU€’ΰΆ*ΰΈ6pψ½ ˜{S#ex§σΗmYώΊΞ~=ώsgtλ–Plλ¨ΊΤ%dΑXξ‚±jc¨)m:1π:§"t2=6|ζςP¨˜JnΌ’ζάψ07ο’Ο¦ΑδVQs΄JΤ‹zOQ„°rIΐp‘0ηžΘΰ% G.­­§αθωv ό”λαuŽ™ώ~.5[‚μ`iΟ΅X«‘ϋοHΕ‘’sžf’o‰½¨Ή šζ»†+³9Žδϊσ—Κχ'\ΓδVΤ!’fΠd ςω&7ΞRρ ΄Κ½³‡Ώ-ΎGΈαΔrΏf²1τΦΖξζ―τΟw!l,ο7Ώτ€=₯Š*#•7>4<ΐΙ'"Šέ&…5Β–RW†#a–χLXΧ ½ΤŸΓτπ&{«uͺ ο `zoΐ;*EΙΞΘΑXΜ½Œ¨+γ‹±½Κ%μ˜ͺmσ£c8%!­1‚©ρgh1Ye„"*,Ϋ"Žk鞴"€WΎΞω₯2&WWr6t«ˆλ5]qκwxάw’—jsό±ŽοτώqvͺΦε&·V4)§ΤR„«C4˞Q›i9#gοΝ„•‰_FQ Τ„»›E°£σλ}β>=ΨιΟ“T ½Ddπε1hξZ”vrΆ‚,ΓcΓ!7§ή„Τy¨ΞΏΤ2O€ίsίc†“ΉψΉ8VΌΌΎΞsυ ΛύΞ <@£Ε―»ο3ώ±Ό3K±*Ξ`ε,x .΄t$ε†zEJZϊEΪΞ5ΓιJek·?΅›.wή~(Oψ_9ζ‹γuαcNΏιIΈ(I†Υ½½H―’RENςcO)†¦J YΞIψ"ΈΣ4ŒqϊΝΌˆHτ[Ώ_“°φlLΞ"Υ³pΙ'*’w²@!/ΰύPηΨ€ΥΑΖ+nJ.'mv!Υj|:GΖσίmIdώ1:R©i]pΏys–Λ‡‰ x1Γeʝ¨Σ0¬rD ιV Τ’τ  ΊΒqIΐΣc\ΎmδΜΈ―ΨΗΗΊSΐ{δb'ΏJKΝ`K¨.θ” δz‘ϋDdIΙ“ˆP&nHd›fͺ¨Ψ8oFHKVΤ„¬Š’ο₯΅{πA«¬Xž΄ήoΖ9q|en†B牏}₯›ΐq±YBLΥ*Ε6ΛJΰHκΎ’Ά!δlEθZuŸ¬νMϊΈΖu―šœψwσ₯I˜žŸ‚\’#nίΙ@0\lδ›bBP$κΡH,a<­eJΙ"•Φ°KšR΄§·ΓFϋμOˆ[‡₯’ΞΙOΎΈΡqςΪe€M-2•Tk!΄¬CnPa9W9xŒRJ«½‹…*Ό 5˜k» λΣό½Q‘©Q·ϋPeΑmώSϊL*­AθιtZώμRdΌ0£qϊ½ζi ©!±Ξ±εΤ’ρBn―-Ÿ›Σ46ι$ςΗ’\’ςϊ’ƒήdFOρ–ήΔM_ R„šΨšJΞΖnϊ»X8ŸΙZx,ψqΟLΜBξ˜…ΞΆΜ} ΌόόΔιuv΄·‰'žΔεΫν»ƒœ±R»Λ[8™Τ5G D¦z– ιΖuΆUN‘bJUΌUœfΖΦ>} 8<ϊπίV??Ήkϊί»ύΈ5@&gm€…Έt €€ φΐm5œͺSG.ME9π ˆϊJk9Β Υ_:_τΛηί―τφΨgCυά–]ύΦ—€β%r,ˆeQ‰LR…1pιZθs l ΉZJΦds|”‹!t9wkφΔ Θΰ\oBέ”H‰Œή΄ΠΩd¬mοxO½VIΕRξbφ₯p¬1tŽcωvτμSΦi՝7rv-€LHδς₯€ΞPσNUδ :lQ™0Ή8Χ,Θ½ΧvχΆ˜έl«ΞΗcͺψ©ˆC΅H;Σ=x`+α°Λ9Y­‹0ΈTίl΄Ζ9Τ Ρ»Σή²Ο~r+³·%έΊΟ«sΉΝΑΤg‡=}Œy%-5č}0X8ΰpΧTT­'Ψ)€&]mšΧΚVnŽ Uj9s‰WŒΪl%ώϊωQ?φ›jΫz Ϊ`7Y'%Θ灡©>υd«ΖΈM¦a ’‡›uœb!Βf£Ξ#tRΒΫ:ΈΪε–ΖuωH˟D‰;τ―7O,J‡S Ϊ'_€str"Θ^ωCΕefŒ¨Ξ»›—Sm q~tφ₯φ¦βΜ°?~λΦGΈΒ€PSθ}R¦˜j³ώ^c;q­πΏdsPΩΙυ˜΄)Γi'γMψΊ―ϋLΌwm-·lμΐx¬%΄Q—Ic’ϊ­ˆ( (‚Β ΰT=’„€€S)€²~e•§Ν>>ωζ;if%3φyH ‘ρ5@χĜœτ|dQ၁©+ιΰS†»~Ϊ.g―άξπϋuφ"—†' ά…ΧΦΏG‘6αΚpκλ£I© fOUqΓ—MoͺΊx|cbΘ)q—άα΄A|Œ`¨q\ΌΠͺΟԘΟ[ξg''0€2ΖΖjͺJ–JKΥF²—VŒ;§€€ξ}ΡΈ‘BΒod"νu₯OŒzυτΧ zϋ;·_τ@ͺ€yx΅ά€›mlBΖε ΰh3);iΉ6λBΒPϋΠͺΕώ—Γ§Λώκ†Ύ4·XlΰΤΰυά»²‰Dς64λ°ΌΩΜ0η«΅€<.θ–Ωχ[MΐΣμΔA˜žΎ~JG κ„άήυ$' 0°eE" ϊ&φΪDa*„Hxp’]HD.ώΘϋΫμiysνT©jκ"RG%[ρΗΪj,M]ω¦ 7­kδXύ@mH,·f€YntCΫθ§ Ω?ΥΠΊiH³†’„#.Ψ<5τEγΌ-ΦΉ\ΉHS–>œAΐu’ε\\T€[υ1Α]rπΆ£€mlρ—ωnωϊ4{»½Π@«\Z‚ΊΦ$Ώτ"—ΨΫMΩ EΧ5φ±ˆEΫ ΐνΘ}U™½HuΒccΉ«~›mω–w–ύ$7ΟΨ²)Νκ0ωIο@#ί£‹Ή²Xaˆ/HΜ«0τ²άK,Jξ}ς€Ύ»”jsΨ.6΅+J¦φ$”Π*μπ©ώ±"UŸ‹y;"'ΥΣσ ιTΈΛ«A‚‡œuώIςK{Ί=rIaK¦P“ΠsH?šΠ±±0 KOΧ1;#7*Ωιj΄ }h<—By£υTW$ ϋπΝίΰd]΅ΔΒ * ¨%­V²E Lξ ₯σώ‘‘HΞJ&€ΩθCt—[πΆ‰@c€•ΫRvΝ…2Œυξ’cΩΎgRςδΊa_Εh]ΣHΛ‡nΝϊdΊ΄ž;*ήr˞˜π?ι0δk θC“€8‘mΆΙψ$}όdΈi~rZœcΛ€r~ορ‰³εR »oc-;ι«!g]iρ₯αU–ςέ’–Δ!ŠH+ΰ"€ M5υ‘Τ="™Σ©ΑfΜ.WξؘχκՏ 'WΫs6Χ`»Eͺ4€ ς>ƒC©Ά  ύ3° Δ½J₯ RDBΐΙ <7Š7!›™/oΟ0ϋYΧΟΕ`"ςœdΌι܁ƒΰ&΄ŽΝ†`ώR,MΤg€t[Q} 4œ]―χ₯πήΊk)ͺ4—[dπ”±ΣkL™lF >μ l”}sˆ+yaBΖ›ωεvEnwΊ‹ρνaώr.΅ε~ίgOXπϋΓφUύχι₯ΝMρ•‘ΦJy£ΚR·ιD@Ψίζ\oMD8΄\½"ΣνΉZνΓ)‘ώ»›|³J„‘₯:Έˆ&]Ή#νXge‚ΏΙR—ΪŠq’υDΖχκTΐwN{$£ΗΉ„ZΞΦΥK;ΔŒΓ°ξ–Ώ^ήθηΉ%άyΧQΏΪδ™ω°m½7νΒΐ™J²Ύ—ލπά€θO]€,iαž…9€‘·;οθ >ΟΏσ}›-ξέ§Ÿό A,:YΡA Β―g}f9πΞ«ήR•ΦK ΕΣ3—tlHq¨’|ΖlψKBj‹'©γNΘ‡‹Ξ[oΆJ…EΌI;όUŸ0Ψδυ:rˆ Lpϋ/V—‡$δk¦8Ή«'¬gEc—c‹#‚‘πŠqeg4!IFκΟ’ε]uhFΐ'†ŠυΠ6ΐ9dK¦c ¦”"βe¦Π«μή@_Κσކ=}W<ΦΚ/ Ρ­t[<ιΠ{–9έ*Rλΰ°B€-2JǞ«\itF¬Π©§~aΨ›ςθO {'Šœ₯j˜Dό€`Ϊ«(š¦Έ[PΙ~4B₯¦[^/j–Υ;,:μΐj[bDσ΅Γ’o@†›ͺΩ~h@΄ΔξωŸ#xψl+υΠ¬„νύ|J€ΘijΡKdGY³…%ΈJ X 1©IΎΘ5‰Ϊg#-TŠ`D#rΖ1ͺ$McLB«aέέλ”Z©ΤœνrT[δΛάmBα@Q$†α™¬3‘•μrΡΞΈR‡a!!Τ¦†ΚgG°ι;–u˜ϊπΛ&Ά gYBΝ½ŸŠΞ%ΔZ•lU*Δ,ΌZzP[Υ^»ΰpŽάAͺΣύTK~ώ>\Κδs½κη:ύΉDGζΔF₯X=ό’u|iU“ζΰˆ5³FE$­₯« 딀ΌVϊΤ±^ή3Ÿ¨Φ—F*Η57Ώfk9n€9#λό™ΰU’EΖZη@₯cTIZ…ŠM'f;‚πΚύΓΣ―ΧΗϋ…tζ.fZEqœ©uΦ7ZX*r‹°dDΣs7Ά‰ΚC§š΅)$±hKHrN₯Y4A+²οL*β»_ο7τ¨›pv‰κ_SVcΑ%φ₯^--ύ€π†‘3³Χ²£¨5W4Ο0ΦσΆΔΏwG·ό2€©sϊl{E ·D”K—sV@ΩL"₯αͺ1l³’ ς}鍓‹…,²I₯όΘυΦ •AlάΒΆςtGq+O^ˆ!| Θy„„|«0«ζ]š\Θv ™rΣ5 ;r` σŽ΄\S©ρ:υ΄KH|Yηrψ{(NΈβk›ΈXˆ i1vI]uhν…«I4Ί[€η.ͺ^›ΤΦιΘ@ΌF©–—;:εV#Έ{\ΐ:^ησγ•Λ“—¨yέ}λžlΫΎU‘^‚™"€Šά>!ωkΑ%_‰"œ¨Ž<ŠΉ<ΌΣ’έp4“©¨š•. –: Ψ΄œ{Tππ’Ρ—š‡?―Β₯P!¦#₯˜jΑbφz΅[­σχ—ΓιnΑ}ΛϋG――χο/›+'Z,θ׊he#ΒΉmΥpΫΕτειίζσ·ΗέœJ/ίiOt­>"©™O₯ρV—Λm ;R|{ωuϊ^π‘χ}ΖOm9*ΧζΟχ«VρΝ·+‚Τέ ΊSS[YαΕζϋ5©Ά4jχ:ιεϋ‘κΎDΥσ“ηοYͺ―V}4 W!ΙS γΎϋk9,λ†Υk3Ζoό«Μ±+v)#/jLJώŠΫŒΦ_½-fuy^ŽnW~­g½ΚtΆβΦηdλ₯΅N+ ŸVάzμΫΖΏMΗκ©Fΐσ:wϋǜvΓΎ’_σχ·ϋ‘S¨o6Ϊϊg―Oο³—εξK{7ΔO°Πωby²^oΠS­ί»ϋX‡k•φπΓηε9ε½½ Πσrd'd[/μςνΧξW{ƒώŸ΅ή;ς΄ςXΙӁ°ΩΊ4΄ΜΪlο…%? ί@¨Z*‚{J­˜n…ŒCδ(&€ςύiσοHKlηŽ~"€Ζ;e[³UwΏzθ’o1“=η’E5.4CQcžjuέp!‘@Μ]œcU­Χd"λ(-.I+ϋΣ ΰ5S4:›Pqp–;0Ϋ_\Άύ€dؐχΟ›JηθΊ₯Xƒ›‡­m'Χ1?αΫυ™ŸχΎΉ(d³:½9e―n‘KζnͺN!θ¬ –:²·Ύgl]b’ڌwδh-ϊjzˆF΅L°eΟιi˜‡KυɁހzΆ[₯©kelθ‘u)•ξ±Ϊ.P"Ώ\£ΨK¦kM B؍9₯€t %\5R}–ŽaοέGΝ“D₯DΊuγ-WRΙ{UΈ‹δ­Ν¦vμd«²v3ΡΊ7!xΑBο©ϋ8 ~z7 M–ςa<·/Qnα₯&Ζ[©Ίφ€ΉΕκͺ‚/"%E½Ψ,΄―Šν 9F&ΑΛ·sΛ΄hΗ½ZOήCœR§œlγ(M &ΧlSδά½ŽVjώ„²}IsΙԌ5Ιͺj’2·ΨπňEJ~yΩ»|d₯G;oςB O]،Ί¨#†0ψλΉHS‘MΖ“‘ϊ†1gͺk^ͺΏXΛΉwοu|œ—x‚1ρ6K‰£₯J•ZqNH=R·–2ίϊ^UΜΦeJ-)R³ξhΆGηΑNΙψ±sΒptY1ΉxpΜaŒΉ7bΘΧT‚ qlΆ L`”OΥGΚX^•sΛ/g)o=ΉfoσuK―χkΚVόΌŽšΓτ9 c‘MΓβΩψ£₯m£*’jXΙ[Η”@œRΒ|cH€ΐV6ςiΕ»Ν¨·ΓόηS6 Χ¦j{'Θaκ§Ωλι₯RΘδ^Χ ΓΗΉζ§N%geυx—ϋg^ότp»>^nΞ±ήύ™^ΦιΚΛ/Ι‡π+ψ”εG²Υ3|ΉξΐW ^^˜Ά;~xΊysŒΡ*™½“’2ζ·rτ¬»M.sK©:™κ.5s@Y«%.¬Ό6#$X—³ N:&N²½L_Ω―Š\ί‰p’—*MŸlͺΡaΚgί•T#7‚CΣρ&’+—nYY6€^η₯W‡s)k:ρξC-ςΙοψl()ζV²δBθΈgŒWW›(YίΙ­+ˆu}ΕζtRΩ"δUγŠM§Υ…ψη+½muϊ‚Yφάφ…=‘³“ρ€1¬Žž&θ¨ήυX’ΥΫ?p·ώό;μκΝQ ~Ίΐg~w'WX/=<½°οΗ‹Η―|Ÿ5ž9£+|ΠξχŽγY-³°=ϋί{ιnοPδ:¬ώΰY«³rGΓο­ ¬a’ηZΨzƒĈ?N+ΕP ιzu8mδŽή…+η`>°Žτ‹G/―¦zyτϊa‹ϊe96z«WMΘϊ9ώ£ΣRζ?ϋ‹θ°­N1Œο–O³ΚwuΓG4ΒΝ$'Oλ[€Γ+5­ξkαS7Cϋά]S­Αύπςή‡ŸΌεaώΩ–―w”$£ΈΞ~οΪϋσσ―¦ε:<Ί=y«φ_fσ>ρΏάξ?|<Ύ8φΌ~˜^__ΩNψYΗΏ³;~Ύ½~ΒσΌΆ]ˆ·b‡αas”Ώ9ίc]ω€}<ΑκΘόβξθ₯-ζ³vωο/³Ÿ·6ۏ›ΧΝ^?iΖ›G­yΜ*?lδδμ}aœΫ…ϋώwψœ:=νφ·¦j0έ?O‡σ΄~οtbNDΞkΰΙEsΕπ7Ÿρa4X_‡^ρψ'―ΘoωτŸhνΖ‹ΰΔX¬3₯+f§6κΊLφ/^έΘ_­Kϋq‘w’υωΔx™#ΌξžOHtξ^η_YLςΆϊ›Jυqση>^ΨΉ²<ϋOž ύΕ6[\W}±sd8Άϊ;ά™νVΉ_{7VίφQΤ†ϊ™ϋ9†Ά˜]}†zψΗdΑΫ«δόϊ™ύRqφUΖθk+¦ŽΣΚ¨£ω­‰>Aζ66ΙcF|’oTκZ‡Άΰηχ7ώω[Οsφˆεί€"ι°i;#{ΫRΞσ3ρHwϊζ½₯=Άμ€««q6ΆΨΚt·]χξcο©Άήb,N©^R¦μ2«ΪεΦΆ‘ΦZ‘œ½+ο½―kVg+mφ΄Γ ιRλM»ιό•ώω.­ΰεύαΥ₯Γ§&gz-wώItƒ#ΜJhΝ„£6­…ΰBJg)£`½ή '7>λGNπ&g[.u¬ϊ ϋΈ+Δ²7{›ί8˜/{Ά’δ‘Žϋ”'ΏΤ‰Κ9jB »Š±'S„Ν¨f³ΣMΔd•Υ©`¦7(.œKs‘ΤΜ–Άwm·ξz Ιw…α*ξl,L‰ƒ’˜TK­6K"‘—UŽ> 7A.5t—Ψ· rρMυλΊΌ6‡5£Γ}:"™~€Ξ©ΚΕwS^“k&Ωαe£*©Ί¨#χlYλθ‹iΜrKfG›ŠΠΩMΙ‡Θ&ϋ($©€υΪΓI’5%“3>—ΏO͐ާJ­{&e‚vdΎr7ΉaΧύ ~x­?θιmώς?›Oω;~ψ·Θ-œ]xπ,όW(ΉιΞ½)χz™τh™(εςgξя+AΓϊrl?<}W‰³siΊ±B}|ρ4'i{ωcΕxrξώκlΙΞΦΞ=ω^CΔΕ<θcVXΰ_*1(0ΊMύδΩpZο+MN» v4άO λ―—Ωυ[ψέΟ^€ΫύΓΣϋj›Ÿ¬ΖΆ[Z±ά„?72žƒΥάήθ86R_7oϋ'ΩtZj] Gο5bXΆ.(ι;V鍨σrφ9ΧR»!u€7)”8ΊλVς—oΧw`Ν€αRΞ0Ύk*MOΰmu`νΓ%y+ΤΥ]κ&­·ͺIz-F)_}ΔkξΎcδδ™±·¦‚Γ¨sζΗ]ΠΒ„7_ŸΞ5ψέ•Nΰω‹@~~¦ΧΥ{^f?%poΊ~Π/Œ―­§l₯χΕrέ―Ήyιu1›ΧΥΙΠΨ¬ΛNŽ$­§ηΕHBΛί­t­|v>±{όΘ©"ιS(J6š«Φ8a±‰*I͍άͺμγ{6σ8.6Έ΅[‰¦y'™>ψV¨₯, FW.F#%qΩ«dUήL \dξ΅ U7ςύΡ ψΧΩβϋύP!uX;8}ρ JpΥ™ΚNY:η€θ”u’ΒQwr@½"3…Δέǐε4ƒŠΒΔ’›Λ§w˝ό΅ό8§εσέVϋΗΉ‘oΪδoΝ¬»Θc8†‚ΜI…άΊ΅ήΗΘΘHt Ύς€­|…@ά ’°’ΔwXS/w]£­vβ$€brFΰBWΥDԊυΊ&€• Φtf‹Ω7Ι¨`}΅ΉY2‘t>|ΤΩΥQόqt.~eιΡ‘θTΝxεξEtu^3qΞ­S)ΪδΧ„8“Σ –bLjZ«½Xc‹θͺ‘-ρ˜B₯HδU=ζnδ6p^ΏΙ1ψͺ`λά@εΊεζ…ΓΝ8-:UψRC¬o#©f;;/XΦP]€Π‹4’Τ"<€HΪΎυ-Œ(ξIΣΗj€ζΧ7L·>K“˜4Βz €ž;“Y#θλ,%Ρ!Ψϋ R‘ιV„'.Ή1J­U'E/όγ~8"»AN†ό»l΄Šε€OwωΕR§ξίnMΩH‘Θ, {nD‚ψ0LΒ„|gC.¦› E˜‚πV€ΏŒ΄!|Bm{βe|fΞή\M;1y„E‡τ xlkH΄,)˜“M.E‘t…!U+]sn0³μ)Œζ;§ž>Ožaη‚θeͺ„‹Υ!/+Ύͺ(²ΰOΨ£mΞι0Mc‰UI₯€<*•ΊβIψ}Ε1ωΠ F‹έ³}ψ˜ωbSsΎφˆ΄g‡ψΰ}ΆΩ₯»<=ψβαi^ψ ΖλΞήέμΆ±fωJ!dԟͺ82‘ΝΡΠA‘πήmψόΗΛ0άΟmœπPjϊύΖQRšΟ3Κμρ ¬1FZžOΤ'όΪ§6:&$xœ½¬*Oχω .tOo.ψσύι}ρώI’™ο›Λττ­ΝΞnνŽΰʚ ZΚr¬ΪEΰϊΤ;r^kΚΨγοͺ’oh7y?h–ς‡<#ΊΔ©t{μ0ιVuqΊ`Œ:yνα ΘXΓΥ°‡ο4Ξh‹ά’CΜ•kνΕ· επK—WΞΔ}Cφχώv{‘Ψœ8B„φέ†αψ²q,Bsr*JϋT,›ζ-E—}rΎζZPŽ=FLϋΚR‘3₯0[ΞΜݏ²7ΨΞB=a\eXB_8fŸ1κNΪSp‰ ΄M•`Γd”“‘}­©tš§γΈŠoO\xL’j_εηš’ ›θ­ού)#RϊX…Dˆ\ΗD‘₯`ΰ(vO‡― @ͺFeώCy «Βo`JχlνˆΒφώωFΫ$uδttπ‹η::θwΈ7v)‘t2)Σ ί₯ ΄©Ψ7]*ΨH˜|HΖ3©ΨXx]Ε–œΤτ―SΟ―΄ζŽυ'υδ%‰8₯ ^tVHhL©I*€~δ!6[ RΈMtRΌX βŽŒeηY*NΩϊ’ή™α|ϋ±8Ί4Ή 0GZaΥR•‘ΊΧΨζΥZΕ.‹ ‹WAδβcΝΝ:“"ƒMIεŽΤμtΥκΖ혡·Η3£ό8αΉ΅¦`b82m¬―Ψ€)…ψΪ»Άε6Ž$»Ÿβ?nΐϋεabΎdBQU™%sΕ † uρΧοΙFΠh’ήΣ–D€ ‰Ίdζ9U™yzIMq΄Ϊu„ώΦ87‹φα!Γρ@„jaΔΨύέΞ`ŒŒϋybŠˆ^‹;lΌ¨Z£Τ@“€AΨ§Ξ ;Ζ€Œ{Θ‘…κ|fKdI‘:ύχο% fWκπu7l₯€:¨‰θ+’q¦΄Œ? €’…+v3.Η8ΥBvŽΑώlMb³Ω.Y ‚χ.'$ττΐ7ΏΓŒ>§}₯D]KοœΐΒhƒς’| žk‚ΞVٚϋΠIΖ[MU•VζΔJ^ξzΏyΓΫ1ύ%Ε棜kŒ‘}v’\ΏώνUω•PKλ½ΛυΟ’VfϊμέδΫ½ΑύŸ_ΖΚόΗ»??<Uςϊ/¬ήέΓΤ»ΈΕ%‚j’Φ₯©b@t{UšG Ο¨ΨΛ%2K>š΄ΞL RB**άg“Β—ϋ½aδ]|„Q―ΦOw/7χ¬@Bπͺ’uJε€ypΥqΟ"„δ(—ιμܐτ7’}κ”ρ0aΫ«v³[φΈΏΧ1Ά‹ ™$PrΈM d°~Κ:°?˜bξzΠΰL…,‹EΆ½5 ΘΉZ­ aΌ»”Us9ϋ]F:Ν(\>ƒΞΌ7ΉbAjъ#Jω./‚ΣZL  ’I΅3“‚ †.3{t|σ·Ίyw»Χέϊ°’Q‘$ΙΘp9Αup›ZuοΔ"ΎΪk’zoΆZB ‘“”Βy¨J.εܦܝ§_IτŽ.Ξ΄ώΞ;³£±]~‹Ε‹©—§Ogš:™₯±/*7U±δ@z€ν₯š²πΛDJj *ͺ(–όZ‘L΄ΜN©*=\“$3°6 vΈψΝκ1,=M/p‡A―·ΓΗ―ΟΟCŽν ΥtπώΚνu—h±}ͺώ ρWlΘ-σρk±‡Ώζ₯­½ιB~₯υΡ£Νχ­§‘Άϊ W•tL¬9*ƒˆA½ζ+TΩJρq¨F πΠ\u«ςα$GΨΠά­ΠΈžώ7tΠχ΄³ΘΙνέΉΥ]Γ"aR±ΊίiΒo§ξ]—8ΌͺΎφΫ“Ÿ^Ε ΝΫδAζE2S%ΛNcWζ.ΡU•Α¦²3ΥΘ} \$ ΩhξJƒ`Ό―q'Mlγβlmcβ–.ΟτΥδœBP†ι„BμΏkTUŠ]4"6Vι™ΈΔ€θί|ζθs υ‡½Βέ^ž†c—p:‹χšΖΪ+―J"Ϊ¦Y)cl’ˆ%‡Aa 4UΌΝ •€©θ­jm0eΝΰΫΐ4ΟΞΗμπάΪΕIΨΏnb‹w―†t‹φr§Ρ₯ωjLb†³`„$ Ό›ά¬RΊbP–ˆοΑ6Ρ!ΎΧ$σXψ{M’onΎώrσ‘ 0ςΈg`LΦΓ™ '½ρ‘ϋ؈6f‰ΡˆD0„₯»ο[£°u‡.ΞΓΈ°x]‘½a_ƒžΈ˜ΩŠ9X΄Ζ"šˆSΠJK[dPDΕ]λΐ_£ϋaΗp±QΓQ 9 ±aρ»=„NΉΠkΡγ»hG|ϋX03ΎY]£ΫρΨ&E“ΖΆP,uμΑ—E[†?αΗm6χ·?p‰šΐD•fΐ„`±‘r’†έ­.>fƒ†?m%W)Rΰ.ά‘tŒk­`7žο ηη`ωΫu ΖRσέ•8δΜ„νί1Dακ†Αƒ•–βtkα-9‡CQΡΉ€ͺπœƒΙ€±α;ƒήAΪ‰Ω/.#!j&bΟ–„cπ† ΗOΪ+j`'«Ψαδ<Η³r ΕkλΪ_κ;yheυμš` Ε―ΙΓ‘γΩΑΕ^s:ϋK_Θ3uΠnΈ“Ϊ’AoΝω@₯Ζ”u™γ„IμrώΙ Oδ,8ZlΆυiF7|―ίω]‘V(δ|pι,₯D]'¦@6₯bΪ<;5%Kι”ab1ϋΘΞwΔ•DEΗΒ±ˆzζ‡CΜ›y8Ϊ3,ςςDΝ« λ₯χaΠͺ)κJl= όrVc’ΰͺ °«q¦ˆP‘οQ`X`5ο­ρMΒW~Η8‰ύΚνTήΎ‚η_OEθ~Β”›ΝλεyΏ›Ά6ΛΓ ,Ίݐ˜γ{ΧrΗ€rγ\bQ>*mLJ%₯Tƒ!η¬λ Χ-;©%yψƒσ#§rq€άS΅β ‡Z›$•°˜.έOK7–œ—S’V)iͺ΅ΰ Jζ'1β©ωžž&ύˆ9ΏW.Ν1J€t₯9 :‰B΅υ¨bΜ=tn·Ύ`ςŒP0•»¬δT‘,,`OΗjΏ7Ν 'λaΊ΅Τ¬>άOξΨ–ή‡]„‚HJ}4s+_ΩΒ<ΑΰH)›m(ΆΆ(ΗίF›οš Ϊr6rφ#]€uΛ΄ΆNιŠτβ$yœB8[ΦΊ4lΙΧm˜`]s!+/ύ5 ―b§ ¦x˜£Λ3Ω&Σ”€q<«±CίεQo_uσΓUΒJ..ͺ€ΙΕ\o \r?#Χ‰Φ—₯U‡1…‚δΑΫκ“υͺF}Mg¬ γόΆzήάόό­qP@:Αe–j‹$ŒšhdΤ5t ρš‚νΫ‰b(I2/{/έηπhξJζωu@9eŠκΆu άαCˆ‘ρ~[S%9²ͺ¦Nρ1²tf°Jεt’ΪJƒπ9›=ψόm%UΖ7Ο~di R#`TΏ‘8yWajΕH—ο£³"ηhˆ4BΊν!€ΣP£4΄ΓΞΏ—~^ϊ/,ί'„=ΕFΫ‡]$* α₯€ƒ¦60 WZ`])”R¬‹,Jk’;67‚ΧǏ›~œfλεΟβ»²JDί(…¨Tσ)&QΫ ΦθŒ’ͺΊŠΦjοθΒxŽžε,’Έlб3Ά6ά/Cζ°:SoyzΩ1J ›ρ’QΚ Žε’λΧ—ێƒΗXŽδ3―^ξ7Η C3Κ_Ά (ΟI΅Ο9-­Κ3?–‰|νς¦›< yς»Ϋ„.­jv>IΝA…΄Σrξί€­ΑKIΝ§Υ`@ψ§7χΛ—oΨh[*F)I«—N‰|‹΄VOͺ ³NŠ0&0!Ι “Ζ뫝k[ςΪθζwO];•-cCθD.gέΨg ½ Δβ5!ˆI3κXΦΗ7WαHkŸηίϊκεωnš?Δ n₯ ₯"έ΅‰₯%²pφ†m―1: Ζ0ΰž@ΰ1 ‚?šσ9ΫΤγ}Ώόδ΅ύƒ@HJ*¨^ΐO‰uι’a°(€†Έ„ ‰>'PFπΗη+!ί*Αγ₯–’*’.Ηƒ\ΎΜK£¬Š1W δšRjefU±σŒΟΤ΄\pΡΞcC!2§³5|«nζΊ|Ο†_tyŒϋΊβΣ³κ₯O‘\ξ¦’jΑpc“©“[‡ 0Ωh€ΨX‹£tϋP΅WrΐXαόf ½ΰwlii±μγΣσCΉΏϋs[4=q K“Hαγƒ@–αΐ#'p„t8:›(ˆwjF£tX«+ΞFx‘€]Ά\ψbήϋƒέ΄η»υΛ„Ψ™Ε»σՎ%½   8Ρvxπ¨0J­j₯"WQΊH_e ¬§dΪKΟΨuLsΟ–Ή‡«xƒ*^E†Ε$ Έ©ο’uΕ[u^а€υ π0Ρ‚„σtΚ;[`―£ΉE9IΊ8–mRω­O¨³Ξ:e[tBG(Εn7ΝX›ηAΰ=} ›±»œΐΛΈ˜ήAΞν;ƒψ:Ρ ZπKšx’QpR`Θ}ΈγŽR «Cυψ—­Υa ! W% Β¦ΜΠη‡ eΔ Ν[€‡Š0κJΐߝ•‚#30μͺX1ι₯H’Bφ d,„3Eꔏο€Υ^#–yΪ)ίά 8Χg%žΜ?"F;€NQ’S3@?’3XO©΄Z$Cn?Ζ. ,9†™Λ8ιCδΪΣc ήœώš1’Η—Υ*ιͺH0ώάΣc!}ƒ^³@΄]i e Ό‘mέ•N.§tεεY#ŒrJqΥς[ΰ₯›πNŸ«;έ²“Σ’ί₯΄9@OcΣ"‚‚΅ͺJεF]ΐ½&˜ž}h‹ £lEJΙΛΆΖβμό›Έε{p1³ιNκFƒ τ΅ Χ ~’DΙ³ Άɞ©>{νD όUI]Ζω 7Φxy‡}n°Ξι₯ΗβΝΝw€NΆ„]‚-)Aޚ„%2Δ^jΩ8i‰Π” 'ΐΨDωG₯9tΏΝt^ί^ΎBW"0’$Α6#ζζζΑΫKMYK――^Ζ˜,–ΐŸdΌ||εΝΘOΫ“œξN / …αα ψΩ%! ΣzMbβ1ΜΉ°r›»‰T-O―6Ψπ›?ž^Vλgώ|Η_?ίi ώίby\ηΦ€γ«OΎ'S¬΄d“*ΦPΔεu’JΠΞp>%Λρgb―σ¬ϋ9hύ;Ι=\ό^‰œ"E΅«ξ ϋΤΊΉ,βB%ή1X%‡ςΪUš₯οϋ\"ΦδΪοpPΫ΄Δ‹kϊφZ‘―ΰGΊύD4+qPΫΘ΅'˜€RT½kr±ζ#Ο4ΙΡ΄.ΞER•ˆƒͺ΄™<Όϊϊ°.χO³Tή―ο9š}λΟkfo;Σ7Ÿ;#xŒ°ω˜9I>•3Ω»AqˆΕzΦ&ΟΊΦ(Ε"0os>Ζσ‡€oσ0jσΊ^?=Ώ|Ο4μΏηζΣ‘@…²4‚•xoε΄LΕήIT€i«λ€ͺVn"»dtΘ¬ˆ|D4εΫ½œ΅›ŸΫ?γ‹o>c%λf²2VΗ’e¦J/ΨUDΩUPNΉΡΕfr΅RψgNMK™Y™GrGϊ'ΓHΛΞι(II*˜ Θ²βχΠΏ…&‰!ΩJO4—€ΌG(N«δl-¬ιNO_E ~5†σύqΚVΑ¨]jκq°ήOΔPVxόά¦‰ςΡσΉ†tiΈ±όΧ;“;ώΜ›Οnͺ›lRˆΉ’ΜΤM„]©F99¦ ‡Mή:|QEψŸDΆ+lœN3yς'σ&RΉφ uΟ”…ώΠ m΅(n>AΑΛ; Ε Π3{ωTΪx7•SΰkM:‚ΑΝxό*ΔȐοlΘqπ₯^3Ag$7Ύξ΅6ή™‡7Ž›OEφ"N cŠ X=37•!Εr["Ηΰ)ΐι/]©{ͺE•ΈWςΧXβ%ν‘‹VφΞ$ν^xσ)² Œ?)B   †Z–>&ΰfAγ,ŒΛ&βͺ0)0#̐tzTΞι0­κ;£ΤΧ‡ϋ­Σzoό““m³|«So£W* K¨¬5IΣq €†–΄σμZ2Œ0άjΔ,ˆš–+ΊHΟ@>O½/κΩ|¨—_qRΙδ(Ω‹Α•μk‘μ©.“Ψ‹Ώn“―Φ„€7Ov’Ω’“Ν₯QϋΡ?œ’άkŽωΏp%©z?έτnω\”Bψn² ΈO•Ωe]Α·}sQώ‚ ŁιδŽ`­ΐΦ‚t’πΕY%¨δ ΅ο_ FΛg χ^°ψ +ψ1“>Υτ}£Φ]ΈOθτlGν]>ΠpΔρώ |> ό|΅Άΰtΰێž»«Œƒ‰xΛF΅[q“6Χϋ‰»ΌΙ³η4 w§›1_Š_Ϋ™―οΎςξΰbΈS>όβUšηg…ΝOš¦’Κ‡;ϊ”\Ώ^ΫzΪ`Κ&ϊ•ϊηo>žνh}8ΖθuδΞuͺ>|ζ`ό_0’Υ^{{x΄[‘ωYΨώ˜ΣτΕλδG‡~߈ΦηςΨώψΐζΥ^χςΧl”©τ³dz““ͺͺe _|ΦέHν+WΘgN7<˜’ήΝ…Χ»{’άLΜζΈ.'2 SΡεIΧλ½@σIΧkcΏ ύκΖ^θ/£¨Γ—η]ά=l§όΜΫlέύ†χ°Κmώ’ŸΨά?­_N¬πŠφΨ³β Η k8jψͺυύΨΫϊ@+aφnΟζι^=θΫ2vE>φ—»<λχ6σ°jΫηž?œ±Ÿ/ΧμεΣ¦™ύ|‘“ώΙφόώΝ8‘yΫzσ[cΝόi΅~ϊΔgW|8ή>χ‹{n₯ή]’νBŸρΎŸsΈ*ΧΑΘύΈΞ‹ΜJ‰½­Π|?υk~νw©9όΦ+%ΆšΙ?²ZCxϋ}ψώ_K°s@Έ`xήhό—tπΙ±ςή–­`bΜwΚ Κξ\ rΞ+5βωΟΟ{ ΐW•Zξ―Ο§ΦqU'ό;9/7½“Έ4υ«Yζ»ιΏξΌΝΞ8δΩρŸχ7―:4ΫmL6©ξXN¨ͺ1]UπΨ€­ƒΧΉ+[­σ«j²τ>'ͺ…MsΙ oλ’ΈΓΜr|μ_—ςΟgώόŽ&W‚4rςΚΆh»œB/Oς-Ζ0―ΧΎπZτzYδi `=^;βΌϋρ\{E[ŒΙ“fς$?¬_ΎMž<&Ο~~½4Z’>Ύζž|MαCpΣ\œ³?τΦMYJ³5ΑMېfQ9kφ•5™»ˆ2Τ&ξ¬λΆ²’¦Ί½†χ^cK’>ΜΑ9?‹+L+n‘q’ή›>i―[a€Ψ³/‰s$Σ”4Ÿ‘Ζ°V[¬ul{bΣ…u~wΙΞ/τ­-jΓΖ Κ³"9¬™u##έχΊœψο :Ib ,ΆDk5­7 ₯“νσ‹6‘a7ξ*o:Όρνΐ‡>ό€ίπυΑ΅Β– H7[ƒ7‘{–όκH)a)\Λ…μΠόzν ―ΠίuΆŒϋνηN>ί?ν‘ͺHoINσXΑ²2^ˆΌbpΠ€Ώ"֍Œτiχοj³εΑξ7ΞΙmνΒνΩ΄κσ\›¬Wω6ήγ¬DžςΣέΛμΟjYΡύE[xζ3Yϊ‹ΧψuΧαvT­}Mπέ½‹:F,†ŽBυΆ₯‰‹΄kJn₯ƒˆuΕV<ΏκUg‡φtσϊ OΪdΔ%Ή©p₯›C«Ξ›|«R‰i«―V΅ΐτ:U©‰‚‚Β§€γΗόΧδ(α―yBp|гηFs£ΪLRδΟ…σ>ΥΕκcNMτ|]ο5Ϋ.y«…[„«ž"|1ε ˆtι(ewEϋωI¦γQατ;eR/Ζ[Ί}Ϋ›ν‘ώΜ Ω8)]>Ÿg,qpY$ίBk¦–€»ΖΜ±ΘΝ{k%3…/oθ‹ <ΏžΝΉY~K#Κ‡N΄χ\Ί AΗƝ΄E@Ξ| VI!~ŽΉuJU΄‹m~Nζρια—04™}Όyeή^I—’U()τ^ ]Θ’Σ•"ωiU.UΩ@9Kο-nIή‹Ÿ+Ÿϊz·o«o.DB¦CΕUΝ5šŽM₯]r >Τ&kΘpžξ=I"α ²F„=KQφ&|πάΆ©,§ζ³τήͺ˜αͺ ΐ!Jίχ(έή8ΰ Yͺs$ΑIR%uhŽa8]# €Ϋ§2ξ·2'³–oόQuυ‘œ‚vπq>UΔ1°£Τ³L:–€€ΨBTI2ϊ’–|΅*έcόω£†-ήρίηO―λ7aμΛgΏή­oξ"Μ_5†‡·-gŸ½+Vgeά l©V•]Δ'υΎl₯υŸtWԊ±Ίη±ήωXΰqίmΖΫ|zΪ|Ψπ―ΑužŽ'αΏώώψϋγ?ώΣ>ώ[Αώcargo-0.86.0/benches/workspaces/substrate.tgz000064400000000000000000002654541046102023000173640ustar 00000000000000‹substrate.tarμ½ν’€8š&:Ώγ*°ψ3³Ά…‡ώ‘96{μdgWwΧΩή΄μκm;Φ›‹γrw:p Œ¨c{A{{cGίH€ΉGΘ­f:„Hθ}ή―η/»8‰μ<,;:ΟNόθϊ‡`ρΟ8πEΘo ›ΥŠzύLΛ€ήš›νj³2Χπί†ΉΪ˜²ό—~—8±#Mϋ—wϊϋξ4νώθ&χ‘Β?β“mΐΏξΓ°—»Γ‡΅΅΅w{°tV–³έ.«†΅Ωμ>nV޽9ά€―Σξ#p€.=%IϋΓμχtΩ-œΰόΪ‘›Ό&ΐ9=Δω’»‡ώ/tυ}h''ΈκΠβCΧίίύ―»QΏ9~Εd<8ž όδaΐαυα3Ϊ Ipφ¦ώ-s΅m~Φr₯Ύ9~Ψƒψ{ΰ;.ˆΏέόgνΏhχΖbΉΨάί.Ι%1:²\Xχw^pL½ΊΏƒτ“λ½ IΖύ]rrcEA”urχݎΟzβžA”Ά2λϋ»»Ϊ¨ Όδτ0rΟnβ>£Ϋ@ϋjΏX<ΐΚ3ικΌΏ{Qμ>j²‚·ΊΤχΰ™θΦ φΐμό)ώqΏμηΰ<ΩG€zH·&=vlθψ’Ϊ&Όη%Ρygœΐ%υU|NzΩ@‡W…λ'χηΊ$?” kΓ.)ΓƎž~§ΊΊ΅χf|/°'π'Aj=δΩ»ρAς=ˆžj½dΗΟbτχ’ƒ8vCZgΩ)Ž>ρ«­u…°>ZHΌήϊ2δxΩ¨«Πs;mu'z “ ³ηfcށΰ:>Α΅δ:]Ψ;ήyσδœlΧοϊ4‹Fμ;Ν5XοαX!}QΧ;€.ρ•κΡΕGΫWG§Y‹Ά…=>λmk>qB[ρθDγ.?δϋA³»$ΊœΫφΉZ¦:ΘΆ«owφ%9QzΑΌ jΏ@€ζpŸ‡kaοΟ§ϋγΒ ώ/ΨΨ»IΎ1.P&ΈπcΌωύρ˟u >vιά#νο?ύς'ν³gΗ1zBΌ8 Δ+ο¨Ύ}Ζ—₯ΫΡήAφP›Ε‘σΰΉ»EΟ Α‘m·k…δΝ:βt€žω7ΦB·6¦₯ζ_ώ―!ώ…•d‚ΛΛj λ? mΉ~<₯΄Σ©$’ α»μͺgͺϊUGH…D]3„>%γJυ ˆΰ»jή,<Ċ‹@΄ ΰi|PλficpZ ’βU׍bτŽωΉύ_ -,Τώ?γό"Έ’ΣιΧΟη¨ϊ1ŽD}ςί4ΦΝω_o,%g—‹xωv·ϋβ%zEfl/wήφl€*'¨λ–€Θ†ϋ―ΈΞΧ…ΎγΨO i–„›zGp§^˜4εŠωήι17P~ΌΏƒo‘Έ ψoέs‘ΐύ¦fΠ»δ7€žow9βϋ€-οΠξa_χΕcγq²G'pKτβ†Σΰ6•Ηƒ'ΰθθ·±bnb'rΓ\Τ}ό@‡}?ό5θ5'8C‘ζξ< Α­>²£W- ΰQœDΫΉ>:vΡl’D@ΌΥ%=?Α>šhLϋΠQJΛΏ­ύ$ Χk₯Ο-ˆΰ ƒ½†vgν;άγ54„ƒ›‡P₯Ζ­O©/Cϋ~r= \ίφάίΠPβΕύάΦ/gˆμ|τ\jdϋ}ωŒ–†4}»ϋTΝz«MύΔμβB@‡θ«’rόΎs:§Ή=’ @_ώΧ ΕzΦηeK5σλ‘' Ν›ηjύγ¨Η—0 ’„Ρi6fΤ©³ Ύ Όύ㢌έC©#μ)ώΦή’;+˜£e—«+u’H“rƒ!CΈΑDŽ.ΞpΤ–±ΰ„$ :ΨΘQΛN&p»ΥGμqΒ5Η"Œξ‡Œƒ/ηπ[βάtΔ«ξtΔ՝zΉ[ώUΫΒρV’+χŠ,hLŒc―‘3ύl;Q€UŸͺ\Χlν_?ύό£–=Ψb?uuάι”™jΊRh„α?A*ΐόΏ2'€ΒσλΔ*@~œIύ–IΖm CΕIΐ?ω8Iεœ(Ϊ9E”!ΡΆΏχΐΞΖ’ιήZ¬qκ–λ?½~²γ“~ΆΓ΄ρ5/“Ί£η# Gζ†Ι˜)bτ‹κΪ¦xΦΘ€OΉΘ΅—–Žω–”ξ‘ΓσΩp₯v“"dΜϋ]{‡ϋGΰ8ΈVΪ»Λ[pt Θ³Λ—ΛΑ²+9rϋE;lΑ Θ–œΈ} †΅¦·,Μ'3έ_³ o jv/V3Ÿ½]4€ΟοMΛ…€–έAŠd»IRΩwυœpυ. Ž*P¬ˆ}RΣ©tωXJ…SΏ+Αrσ?Φ¦Š—1γ½=άσΏ6Ά„Η²–jώ%ΔνάδΰΩΗ8UH¬ϋ;χz:6iκ‡ “Kθετΰ˜’ž0Ÿ!^|Nz`•cΤ‘&gϋE‡=ΐ‹χΊ|€c©ΰΝ% λ=«†ΦΆκWi‘-Νϋ ο,κΒCٜ5ρddξH΅‚Gxή0ΎVcNΈ‹ΟΌλσpΓkπ°Ν€Σ—*Π՞E7zΫ6ϋi ~Ÿ]:8JΉŒ»b ™{ϋφ;†CςxΆ¨aε ma’δυ1=ά‰ιΫΩ΄˜Oκ–B.ƒ a9ΑB EUA)sfέ‹Χ '―!ˆ›œŒL،qΎ»=ΦΞΡ~š©ιnaθΟ—ͺ{lYŒmΞΫ\Wš›Om@ϋ©iU¨ώ¦£"t‹œ«"Λͺa†m@ψkz z8φN̐l₯όΐκ'HYlˆώoͺϊRηΏ²{Ž6τς?‘ϊz₯ψeθΤό/΄œ3W₯̏χwΏ^‚Bυ§΄Ic= ‚ZmΦ|€YΎϊ νοpH†¨e΅ώΐθ-ϋΏΐΥπΛ‚ƒ& θUS‚’κ7d †π?ZŠρZζoΟcP@Ώό'ψ7k52δ)κuˆΚΔιrU­‚Μ˜K‘*dCPΟv‘˜C/piλY@v D˜HφŸ€Βα2ΪΙό©Σ“ρ¬‚_Οΰ•κ7b†Δ―•ώ]σŸξΛƒ`@―ό7šϊΏΉ\”ώ/UώΧ„|Cτb™­ιΈΘ―$%­Ε Ό+Χ#S~&ΚkόμκΣΏΙ…ωί ¨M-«_ž œΚσμί)sΝB‚4Χs”€ˆ ΥoΦύ ΰ—&’ j—8 ˆ“™ψŸWpξIώη΅ͺ%Eώ·‡KDπU5€.”IτZTB‡V–˜?)Ye“₯“]QFY?7ͺSt3ΗΝ”"7_„›XzΆξΐ³ωcΟF„ŸyUƒ†κΝΉͺ ‡d₯žfΚ±±γΧΑ}εςϋβςΏ«>L'πSEͺvκΑ$›{7Άwp ΉΈΈϋFήΨc½\yb}cυυΔ—)&Ίhυ M­VέΤοšρΏDώoSΥ•?©­φΦ5Θψ―΅₯ζvύοv4΅‰•5©ϊΪlωό·œJh,?)‡6Λώ? ‰Z©ψ9σŸn"ΣΏ{ωΧk2ώίX*ώ/%ρ]qm=ρι̊0μ: Γx-’|ζΘfB¬!Ά°bY[y Ι@ΥY΄dPΕ’ζΉˆIα\žžšVδhˆ›€₯raڐΎπηΑV­d ’r,g”k&k¨›g—4Ρψ—3ͺτrΆb†ΙΖYy@ήZ ε³ρVJ˜$ W$ ϊ}Τ’Ό«Sΰν΅lEηVLV£ρΚ œΥvπι Q–€¨μ(oYώΛπXͺώχΜσΏsύ?ΨƒΤχ'2 Ώώ7…₯κΏIΐiθΘγ9ˆ@*υ?~\˜χw‡ψ3±eΥΎNv|χ» F¬Q‹x©ΐ„§ηβμ2[η).ŽγvžύΫλ#Κόw‹’qθhpΜϋ‚²ΗΨΦbήρ‘ΗΖe(ό΅k@Χϋ;›ΒƒλTPΡ"`—ΜΜR’H~Ϋ{= ―YΗZΩθ£ΡK¨QΓ¬εaοξ¨0]Uz‘Ω€¬V˜„»AqΤ’U«4§Η»Ι|ϋ]σ΄΅œ¨ΤQm¨ΘφχΩΒ5£&)ΰr±Eλ’¦‚"-v=ƒz'7€θiΔωC³%3Λ‰“·§ΆΞΆξ‘υŽ9¬^‚Μφ~›-‡Ρ}ΝΦ|&Z'€θՏ/ρ·ž(³¬όΧωάȁθfš‘ΥTO―SΣ௜Gϋζ…“ϋLAζƒn^{jeΕυκΚuφΫ_AΩ« ϊΊtΑ<*δ_sH¦‘\sύ3%²4Π**αΏόY‡[»DΊ{Š΄Ώτ˟΄ΟžΗθ!uπβ<`]kΔ’XσGUΣ;Α3@ΥZ*ϋ―€ω‡β}Ξόoc³Yό/ζVεΜ£νμύΚ@7Φέ"(mΰ½ξΖρj# ΌK‚σVλζBšmIΒΆώ(pΣNcΞp'ΐ·} „˜•!Οgΰ½"Ή<ΨύΎr μγނ㲍υLaͺχδͺ TΟ@’X5€5/oG”;ΐΨυγ8IηΈY›6™Mνή™ΘŽTκm=‰ΓιΙ%₯ΩΑΜσ@^J―-Σ9~Ίψ§?½ΑYΣά+ β0zΥ—ί=}u#PfΙ§ΗΨ`σŽξ‘ŒrmΓ‹± Ί―~E›αq*ΰn4b»Λ38Γ%wπ'ݏ.’α—Ν ­β?$Ε°`&ώ‡ΥΖ"λΏ.-5³ΗOη€mυφ  υΌΆxϋ‰lγ%λη8rOqΆ―ΙlIsD* πe`Ψ'ο!~Lj3τ¬wε!O7¦χ;6TαY–YθͺȁυP\WάΎ?d 8ξ2λΪ |„½’φΎ‹όW\θc<ετΞ»Œ ™ΝΕώΩy› Υ-‘ΫσšΝ&©1“%ƒ–'_ΣΝ―ΟV!Kδ±Ά•+IΛ,Ώβrϊψ0Χ_cώ7¦ͺvωίdf5Ε…(HqΜm”W‰6IΤ|QF‘Ύση Η v²OΐˆXmS "’YίvŒη€ˆSΒ_ψQ1«―όζ‚Φ›­’rζΏ²½Š€½όΦа[λ•šYφ9υηΰGœ΄˜Ν6ˆƒΟ8φ6+z ¨E«pE¦φ2­Uνo’αd«ωͺκτ³TAE%Ε@ΐ!όί–‘μ?’ζΥ~™‘cΉΪZdόΟv­β?$ΨPδ<*εd@γC{δ„ˆŒ¦―Ά%ω­α―ΕK”/ω|Ž:ϋ>ƒθ Β‡spΑ„%zdϋG@Žcu=%sΉsLJ{ž'›6=x’ήι³lΡ…έ9”υAψς('JW¨€Sψ&œ‚2HχKkΆζ|mβ²rΡφΤΉ0³W•|;#±&½λ‘•”°' MΟƒΣ oΚ9Βd>‰7‘ΔzSIœD τ5ΆΖ‘Uσ‘δλ³ε\₯ϊ·‚[ iΑγ·KUIžώ—ΐyμ†iυŸV¦©κ?HΠ(Ω׍ύ½ͺ!fΛ„Υ”ŽvΕ†!}bυR π•‹{­",›KeAVϋΉΛ³Ε+kώ—ξ™Λ4·k2ώs­μ³ΘNή[œύήό§κ[΅QM ¬­³iΝŸΗ”6ΟΩ\(2|HLΒΪύΩ~Ρaπβ½ξŸ3LΑdΜjl½«ήlϊΑ鏽E5y(ΔΤL#_αΛpω₯οΌxgu(Αλ, ‚Όά²›BΠ g;α©γήΌdb¨τσΐu/Κ•ρ/¦V@œΝnVαΒξ%Ϋ"«ηBtΟZ u΅0ͺ±LΑŸΪ›“˜ŠΣλψΌsTΪDξS)Φξ"₯S68Εb‘»°cφc†qŽ16;d°μRήσΤ^ώϋs~)γ!Χ­;hΌμJΎρœΐΓ‚sˆΔ+―ε³Θiζ’!ΩΉΛ3Ο»ηΠ=χ©ƒεaθMŒ@υ‚2(»₯=8μhΐ>U\Κ7" ΣΞpTWO˜¨j<κ«t7μΞΰ9Eφρ όα·SφΑ¦Jδχpt½[ΊŠοY ‡<χP\…ršψw%Ϊ’ώμJΞρf― ΰϊ{wΘ.δΝ ’dΆΘ.δŒ9ηˆ'ΚkΉγœ† F ~βm±{0xv%ίxΑᆑ‹όΚaγ ΦΛςn‡hfٝΑύϋeΐŠΖ—ρ„v°ΰμ#^‰ΐθoΘϊnο‹σžΐPu!Ώ’oΌΨ9ύΕΎ²βRΞα;Βυםl. qΫ»o'ώI»t’ i―#ΦΐΏ†ˆΘμBΞΡ»ηΑΫFK/4\είνh―;—hˆΆ‘υςPν…σ>.ϋ`ˆ‘mpΦ RO˜ƒ‰6b,ŒT@βvpi€ξεq*U[σpεŠB†?ξΆ²Nxο"gΚβΊŸB‹οβ»Ώ^† šμBΞΡpQΒ—]Θ7ΪsNΗ;Ϊ3…YNZz§;8ŸΣε-κ2Ψ*ͺΆL#πwΠ ŒnΖΤLfU1f†ΪJ)™A£ ¨1γΝHvƒ…lz!ΰ˜Β6~Δ₯εiΰcΥ;aͺmYΔϊ aσΛ―&ٚ dνΥ9:9ZΉΤ‹”•TΧ)aŸΈ–ι2p¨ύ˜ŠCƒΖ^Š(k7pάμj¦ͺ"…}ώβΓΩΨaœ€θ`;)‹dӎ@Ά»§%ϊ·χ #1*ιώ©wΏ³ζGξ…¦6a1··\Z! θμ;u‘v·ISΣΊ[d~ΉΎf©7­§UζλnUšjϊΪ^–f…'„m*Jί@w{dΥοi‘η°u5ΚMθ=­r»wO³Τ\έέ(³2w7*-Γ=νΞQOƒΜπΪέ Ϋ »›†­žf©½₯§Qn«θjTθϊ}ΝžNΡϋ.H5»ξV™ŠΤΣ(ΥΪΊeκOw#ͺmΊϊN)–»ζfHœ¬DΉTWθϊIN˜Rίήϋ/+B(j|,U] qυPΎ)6g»`γpΎν•#Φ”–όxΣ Ή=6OδϋaΛq½2hM†šF»r/­§lž5zœ"ψqήD‡²]³~΄άΗ³―|³…Βh™o{υ£•}qβ5δ;Yγς Ό~Έά²γͺΚη@½ΡCα΅©N·J:—P― ₯rόWσ–3+y•ΔΘm‘)ΚϋHχΡF?υ£₯²–_U§bύmp*e «v°ΊƒΠ(˜Ϊ0¦‰ „ΥΫ–B‘yΤ^TNd ͺίΩG-9E >P¬fˆΞ₯­΄Ci₯‰ [˜4ν΄κσ,&Αzνέ# Ÿ ·ϊϊγ§ίόγβΌ'₯ο•|Uϋ?±@δv«κ?KΒzΞ!ͺW“ξΒX zζ³Z“υ0'°šΙόιΙTbU†’h~{Ν-[$umR|υK†°wηn8C•M"τ΅£‚}5΄•3gkRnijΑ©ΦT*f£…i΅:zΚ’ηΏΟΊμ΄ ˜jΚ'†w Ό ‘Ο΅8€6­OΪ΄΄?|ύτ󏠁½V/΅ώƒ†,H―ΨΊu‚7 qλx#Φίό쏆 +[χwαeηΉρ©Cξ΅X΅Ό†ΚρΊζJΚΚέ4HΰΒΉQυί₯ΟΏ("Πξω7 sCπWŠυ-ρ^O™ΡkαοTt™Š.sbΊΜqD•EHdd‘CŒμλ¦ œ—Θλ©sf#υΘπ#U)Ύκ†…ΆΐlσžŸν_ώ¬C±«‘ŽΤ£HϋϋOΏόIϋμΩqŒήά€ο‡’Ώ™δ4Φ₯ƍ½°ŠQAύU“Κ°ήͺόyηΏZ½SœξΟ0–ΉΩσΏά¨ωŸ]ο Μ»–ΌαYϋ‹°©αwŸ~χcb·Π>§Τά±†^'’vΣJήnνgνΏύƒ\’π!3Fšξ »η€aNFl²ˆSZ/R1­|sJ/υkˆ3TύG9σŒαG'@}όΟ†Iς?©ψOe™ΝώΣωYTŽAΊ€2B ¨Ψ5ω|Uefςw‘œ&³ŸyΜχ“ιO--匩Z//εtlCmΖ‡ϊ&8`oγ5iΤ–8•”뺍WOΝV¬©‘KE,E~ΉŠN©@UV@rjUΐZ§ž‡ΙMT Bί-Vƒ £k`Φ`žVIΟPΉΤΥo&ύOœ`HόΗj©βεΜV‰P` H?³AΜΏe)ϋΟmθς¨ ΪΈ"šζη†λ+ΆΕY`λV’'p‘²QvŒr‘^ƒs±¦R$Aζ ΤJ…xJέ"C© ••¨Εω‡ΰSՐ3^€χς?“υ_ΰ1Ε1?ώΗ³_+fʏŸpŒ(mz£ωžωF‘UD{™š*[ύͺ…a-U¦αUΤ•!ƒ?9yE$0’5ƒώΡܞ„dS‚&G#}Ή3Βςmtjω/6lHόΧΖPυ?€α?ύ|Žζ‹Z­(υVkΕ- Aτ·ΰ$L’Ά­Κ}»xU0σ`ζ Όt΅ε‚4C‘'4Χ›'ƒΥ ½₯Ό;>#ΆΥR† Ϋ«αYOYοp—dλ;ϋ ΞΔΆλλ‘νχXά uXώ―υέͺͺ Ο΅„ιΥ5“owpk=7žRΈ X’5BpζE›ΚRSy˜υψάΨcQΩe›^ŒκDγX}!OφP!ζŠX΅v[ΎW¦c 'ωρΗ?όΏΪΦ~ώω«–{n.‰ Χ†Kυšpθ^θuL―]/ώ—£μΏRζwήψŸ5M3UόΟmΔ(ώ—ΫO½ˆΕŽ/¬άΪykU4Saτω‹fre<Τ‘΅ΨΊτ]xΊšυ/φ‚˜2H1iS1† bƒ$ΗX*[Κό;)m άπgγΆΦ+ ·‘ψ?ώWψ–ƒύ6ΏϋΉΘόαΆvBι)ΰvΕΎMEΧΓμΡ2δr’εZKοθί΅ŸΑyׁ4[‹!Gp봟~kŽνC`ώ7Ίi₯ΌΧ@ŒzŒ5ŒWαω(ΈO¨`\vxοᡞ—‘—>@='ί-γڞϋlDξѝ˜±¬Όe…φ§ΔRωί7ke•3>β~HβωβΏ6–±%ζ½Qψvόνnη&1Z`Tg ‰€R ΒW¦3°ΕhΥ‹•žmηΎ'ΜZ¬Gι'mΞ‰bKβ €‚‚ώΜΛ_*ptψΠQ%œΎ<ΖΪλw;>λ(!f} Ζ‡…Iτƒ˜c9–w#ΊΞ’φχ:Ǟ 5ηΤ’_ΫΎEφt†sωΜΎK!Ξήδρ|8š7ξT©΅‚ΤZΈβvΑΛ Υ6½”ƒΡrͺ8τY»ϊ3Τyφ˜/›s‹kF³Ω1\ύΙγkYqΆξh!na’δυ1m˜‘³OόώTΦλ,<σ%uE#Σͺ!R ½•βΌ5<覑b―΅ξ²c3˜Sͺ‚ύ^UώΏh{FΎΐΝΙήαM…ƒν€jaδ<―ŸD‘a!-"n»«2ϋE²Φ—‚1?Τό¦ώNθh’ κ‡ΓΕσζ#τz «R3’’ΟšCΞΊdςjΞτן΅βq§΅΅ƒ(SΛϋεΖ ε•;©ώ$Β ΤΗ` ώ·υr₯κI·,ηΟ€»M•“S)£ςjm3ϊ#Ή$Ω™ΑzAmΗb¬,š}΄yjΙ *`§ F₯|΄tηΤΰ“Ή~ZΑ'=oG@‹€žm?)Κ7Φb8§W³²Sψ―Uώ €πίώ­δΏΤω―(Ρ#1`ίόo-‹˜©ψ$ΰΏrΝ κόz ύ;~υ[­ŒίjR™]¦0…|χφdΕwk—μ5ΧΟδθγΌV½κΊI‰Ιτύ”CφυFρΘέ£Π§[k³9+k₯ψ%μŒN<Φ¬πV!ΨΧΟ~B;ͺΟΥ3tϋΑƒ@gT@E!ηGO“;sμΠ­τόP9ΜͺGwYϊ, υΡ)Š6Η}„ϊΞ œ'\Ά»Σ²Oυx’Λp”©#tΊ»ƒ NFΪGš°Oξ#ϊŠ)‰xώ? ‡Ψ\Gϋϊε³Α)ΨΗΨ‚€ύN)±Όφ" mn;že@x£ς_Œhώ[YK₯ɟЍ{ύ?Ϋusώ7Ε2?ώ“ΰήγ™Κo.€7iΖΖjμή’8n€h^O`gPϊr©μiόd }1E’­V_³p’O_~ͺx…΄όzq#°Χv―Ϊηό^0Δ/ DaΘs4ŒΣkz‚tJώΧεp,8mΦ–Κ‘1{pΈ^ηΛ²Φλ5e)ϋίΔŠAl.ΧFG!>es£˜䳨΅u£dώ‹’ZΕΡ+SŠζyk%•`δ¦θ&Έ”xQWDΚ, Ξ,ŠVΖΈλ ’ R 1₯ώRDι+’ρŸdώg•/eώΞΠCeŠ£ΰΩ…_?ΓmΩΥΓ“₯„λεXρ_ΫΥJρHπΓ—‘ΈN#ΓΤXHIΈN]ό@Έ΄‡ΦΛaa]BmΡA8κβE>¦AΈύΧ·„ ‡ιόθIFλP ΥΠ4iϋώ€νœΪkΗ–^ύΏήΗ§ΥξΣ­‘ΎŸ΅ινβχ‰+ΞωΩ“£#ΧHw5©¬Εl&ΦuΨbαΘ9&πη[ό#ϋŽΩ“ο*t <Εw;H&zsωκσV9QJΑϊθν―ζŠ8σΏ|ϊσŸόσhbKΛοZΛοzL†NuOYU”ώ_Χ‡Ω„ΨΆΦVεɜω?αΌ“υΏΦkΕπΎόΏΚ «HτU«1όέΖw(V4Άιαπϋ!Εh—’ωΏ–*ώK*ώƒˆ?²g €¬gώW†IπΏ―-Ε₯βTόŸͺ€\M 4O~Hv˜KC=q’3χΧ{/ΟάxύZB£`ΤZmρ-F6΅€‘ΐ\]۝¨…ΰ‰όͺΑhθόoΏ4Π§yψ‹Yτ‘M§˜¬•M^αώ­αRω’ζΕ>‡žΐβΏύσoYYΧ4TώυιJΣ»YM€ή,wΘ‚Ιη&•‹‚WۚL£ή΄θ%ΚΛT’“˾ӝΒX3XΎ‚’ ιLQ­€όΝΟώ υt τξπŸ8οΟ0±VψOβόλΑα€ΩυοAτ’Qϊ@ώ7 ’ώΛΖάͺό―·ŠoΉtntDυΙ\ΞUyld ω'g?K‡Yο>Ώ„£Ξθ­' Bb‡δω—ΣΎTƒίΕt0”φΉΟA˜γΈ₯\j© ¬7E·οκ7Ρ†πΏ™ŠKκόΓ―ν*ήυ·–©κ?)ό―"ύU€υεΗ‡zbΗOƒ’Ύπ…ΧΏ{ΠvwεΜμ\'ΖΎΔΤςJъ–œζgΫΉœ¨­ωu―ό—Sq΅UυŸ€ΰΏ£λ%Bƒ?μΏ+“ˆ0Χ¦²^ώSρο ΞON₯βέgŽwΑΞs›1ξ}₯A:ψd†‡€\U"mΎΫсfΫq‚ *Eπ<0i(;Κ}ψOdπΗ0όo‡œωGa‘=gόχΖ2ΆdόχRΥVψ_αy’Β3œqrCΆ{,ΫσΥWŽAŒΪ2Ύˆ΄ρuΤυ !Κ±11š½†Ι #:ΩΛ΅Ρφ\ψe‘8CFlφρn]ksμ—3ιΝ’Ψ~σϋeΫΙ„cMxv~9KΈ}Σi”'ͺ€θ.?8 θPΎD«;|ΪλμLOuYέΉDΟ€ΦσC΅0胇=ΓZίΕQ>CΛxΊΉƒ³’ςnΪΌ‹4³U$Άϋ› »jŒI·:Ίy† Ÿο(u'wrutΘvσΗ―Ÿώςϋ/Ÿ΄ό…jG{Τe·Ιχ"eΊyOϊΏτόKε˘uΰ^–ˆ,ڟΏ"ν?+CΩnΓώeεΩ~Ρaπβ½ξŸΣ$dRtnΰ_ΞΟ>Ζf£’Εfa*ϋэψU¨αϋ‹ίˆ‹·+Τρφ]»ΉΔΦΞΆ{>ΓΏDt¨ω¨J/x£ψO 0[k'eώΟzΰΓ/ΜWce‰Uό―ς*όώVόΏΚ;«R·ήΈΟ²βΐΙ Ϊ±ΣιŸiu„+8Γα’a's“iύk¬ύτ―g-…Gs¨X9S:–ϊ͏εΦY-•ύ_Κόϋ{ρdΞΙΌZQόΫ΅š₯)ύORˆ`ƒK#―xΘΰ".C9’nΐoT.‘ΪΞν–ΧΜ„ύ̞£tP₯Τ\5ώ“₯πŸŒωχ‚$Ρλ¬ψί€ΤWόΟ +ό/Ώ5P[›l\αρebqG’–kŽΜ›7ΝοΡ ΠYpώΐΰ―Ϋ…ζπβΔuά;p΄?§Rgς_‘σwŽdγΣTό2ζ Ξ;z……©½ω&‰·†+€‘^Kε(xΜΥΒ {"μ":*εΗπX3G΅δ„ΘW Jα<―ΙΎWιο S†ΰͺ(iώ£'Έύž1(*Ωώql.Hώ_/ ώουv£τ?…ώ/Ί?Ÿ#(βvl“γ<νtκ—ά ”²(*s™Η+q'ΛU`ͺŠ^RJI›SβΫπŸ!τ=‚(]…!T/:*αΟ­L |WΩ'&NΧUĞϊ^‰"ς3ή[΄Ÿ³½EϋŠφ–L™”EΎ ₯m̏Ʃπz«κΏ\ΡόW6 ͺ@_ύΗ w΅Κ~«ψŸ „Ο€ΓηNΊŽA΄ίZ€mSλ©έ…anθ)Π.σ³6Σžέ‰ςœΗΐj^Π;#ξ}ωq.»V-βh1œ¬n;x`ŸLοxj@©WυΦχ†-Ήε(ȏΰ$Šσzπ_:#lΐ}ψΟ λΏl֊g~όχνξŸqΰΓΙΖ²CŽ)Ž«ΧΟE~GΚιΕTΟάQζXΩb£¬j~[d(γaΒ°ΦΞ œ'η?ΒξNΛvΌ8nΈ6•5αž”G΄ΊςWΏωp/„ό9=γ\Gϋϊε³…υ)ΨǘqέυXΓ₯ ΄οH5}ιπ»Ώ /;ύO<UxZ9ή•όοΓm€μμVςώω‡Ϊ§»Η9ωߍνŠδQφ_εWώΕԘΪί4S;=―ί;ήτΖηΆΜ+ET‡"ΤΗS’νέNͺsš#N7ή*JWύΖβ?ιόο ˘ίužΔ²1ψ-Γ«ψολΓSς(h ω{ƒζΣU4ΊώΊE•²¦HθT2Ϊ¦„ΘXΎ)|ά#E²? ΒζΖTόΟRζyΓoάύ “ΟŒƒ½ψoKΖ*ώo…ήK•υΞΉa qtpζUΦ½GRI«I₯I1"!ί.6d£Αΰόk₯μ?2π_p8_p^ώ―₯IΪUό§Βο«ci°bΉCKΦ<3 œ–·€ ·sή8[p {럽aΥ(ZIƒzƒ΅΅\.ΟE₯¬€οΙφ/· ɜwΙ€ό_λՊΜZ*ώχϊπ¬ρΏu28δx§οθa<»Υrσ΄φ0]θρ²(mΗΧQcήξy” ~=(ζΩώ>΄™GΙΪσ RΤe¦Rς™g |ΣfUν¨1»υ;)A ύΕΟY`_atκ ½zοΓrͺwΧTsgfxF΅x|Pv{zΎΫΡ^w.Ρ3h™ϊ‡j•9 ½tΨΣ9lv_œp$^΅£έηZΌ8Κ;$5ˆCuΫ@}o­Τ0―/u›Ϊαlj­› ΨΝ ­hnΈθ²rΜbJΠκΘjz»B=ηDn@“ΐg)ύ_ΖόΓMλεuήψΛάώ?s«όΏΧξ;Ϋ/:Ό^²Χ=ΰs:M•¬rT—šqI\~U΅ή²co2Χx¦DbjnΕΔΏ!Q _Υ .?<”‚β eψO~ώΗv©ό?2ζT‚³β ›2ž~πΖΤνΟ5šσΏUώ?w3ΨΫ>ύμΎ°sWη|kΨϊfβήrπš―φΐ6nJΙΚ*ά•_KQ’•’DC’dDΫ.ΗΜ(ƒΒ!όΫ•²J™ΰpIΏΞ˜Aγ±V¦ͺ¨πŸ²½*Ϋ«βy›ό/Άγ ’i-—8s€Βl(ϋεΏtώΏ΅’ζ?†ίΞώβH μχφ?km)ώ—w―ό7C2£@κ`#¦xfžζHω―' Ncb"LΉ8σ^(ΖGΕ)·‘_UΖ0x±Ο‘DΑκΏωΩͺ. Γ,°ZΉμgΒβ€!ψ΅Uψ_ΞόCι²ΧΓ π„iύφ_"wSσ―μΏΚώ« ΅²r8ή w*t4$tβ)νΏα¦Lΐύς_‚Ά+…€ΰΏ,VdXΟόC¬GΪMKΝμψο۝{=Jη “Kθaω|Ώ\˜ £­œ·Β‹Σ™r[‹ŸW8X‰@‘’_1tζδV©Βg.š•›§Κ$ΗH" σ4ΥEύ AϊŸάΒJ~Uπ )H›€wXQr327 &7σ{ό‚$΅Θξm(—G±ν\‰Φ‘=ο<šΕW§4 υ»5ό/2pˆώg.ƒΜωHΩ«™+’e³UρίσΫeπsΎ^ΜwA}ˆ²ƒXUΧνΒΌ‚CΞi­8M@pH:% ’P(55»α»Θμ3Ν0z)v0ιrΈwF±«(ΊΘ9ι" ½΅W7G0ΩΟψ8‹ς9σb6"^TΏAψ€28„qc)ύOΚόP$―sϊ,cCζš+₯©ψ―Ϋπη!­θΡ9Aρk³*G¦’€βU[18―αeuആZ§V«"seAc’k³Uρψμ •ΟιΆ#ά2Y:‡«)Iazυ„dϋŒ­Κ•2™dFόΏΚ%ώOρ?Ύ/ό/1+|d‰8 υαήbύλ w\ƈƲ½hO]m™Χ·ͺ―ˆΛ7Δ¦#vўYgSΤΫC[mόI8Ρk˜ ŠΓ${y·‘Ÿo¬p9mΏ°pE υCc¨έ —ο½ΈNλsBΏη”NΟ!ΟΪ^JΫ"g0ΖψP₯.[άΡu½!ί ˜;Ν―£Œ[ά>H{Υ<Ίύ©²ͺNe$Ά†M—QTγKυ?ΊoΉΓ ]β—J§€Τk2‹0ΌšΟBMhώΚ‡Pζ/QϊΏtϋΟZρ?˜ͺ¬Ÿ8ώΧ0Vι7-5sΫ ˆG?ΫN@ιWEιΑ=·ΪοΑσŸ.;ν?(€ŒXƒo xA"žλΓ©ΉΤΒ€ΎRΧGfXξχΑYΛοa`g1aq€ό.ξοΒΛΞsγS±^†‘Ϋ–—Q9^—α΄τWeΗUΏAψo ^0oMCρΘΠJΎήωκΏn·&Yu«ζ6π?„gϋE‡=ΐ‹χΊ|N•ΐT…bίO‘X"ΰ'ρ £v~± D0fΪχχcM§Pησ•™h€§τeχΌ=ζz’ Ύ‰zpJ±š‡ύORΧΆΞΧUmΙoMϋ9@%Jοο Ϊr9ΓWhη s…)Σgš©gSϊ,*ƒάγ’Ι­Ί6ώ“ƒΓxζψΥΥϊjΖX*GΩ؟§”Xρ%ze¬$–΅–“’TΠ―F]‘ “½—šΎˆΤγӎΔ-fKοNxHΈXΙ§¨yΊ<Ω0^6ΖJE°lϋΈ¨¦$ΠΞΆ€B@Σκ ¨Ϋ€~W‹―"ώKΕH™Θφc;γ±_‘ue΄:ΨΛΎ6ΙόOΕ0Ώώ1Δ ©gΰ€0y₯J>_Šΐ¦>₯ξ\‹Σ…¨ο…¦υρŸq9…›pΒ1%²“jM¬D\£ΆPΚK-“—Σj€|VΚ„ϊMŠΖͺƒψ? …eώ£Π₯τεbϊόo,UIώG€N7δx|HαxυΈξx.\΄Σ)h­ž‘kcՁva¨£ΫΘΝ£vθVπΠCε0;ά«χAγ+αιmηΞ“s²]Ώ»Σ²{ίγ«€6@uθτ­…Ξˆ~=τm_>kŸ€θ`;i–@r’Ί υ-fΖu:~Ώ Ϋ©ίΘ1pώΫXKΕyMσ_‘άX°m»nƘΛΝRρΌ—ψŸvΘ“nI΅Œp‘Ό‘©\Pn")=9?»©}~¦αƒΈ,·ρ}ϊςSŠΜ(¨¬j‘“Ντš:q«0mΘώΟ‹ψεΏΉ\[ŠUΆόΟ ¦φp­GΒ«ζϊ俊τ•ζA>Έ—' ²½oέuβ,ŠΧžπ²άK`ευϋΈ―*εPy»i)†€ΜA5‚Γ ”ΓΆΞ€ ŠŒ Φψβxψξτ[`T™0g²;Q’„e Φr•αΝyχ”ώ•| ₯³\ώ˜8„ΕΪ*ϋΏŒωΏψξ― –¦›[’ώ―eUό‡ς(˜>-£’ ιΌΧƒ ιd&ϋo1")s0<5Β§€Ά…Γς‡_4;Ž!Oqx% }J$ž ΔώI2›ΖRα?σŸΈόˆgΕ–IΪ͍²+ό―π<ψ_ρ€(=fdeΤ+6ήWΪ‚ˆδk©œF—Μ €˜@©οINJ]ΚόC! ;Ȝψί Τ2WJ»>ό―ψίί»r*Ό=§‚X kζͺ΄bLϋWHƒR—³HšL°N‰Σ‹!NWΏ‘ψO6ώ7χΜσ4Ώ8[8 ΠΑK"ˆ΅°‘aΈJΠΗ·Zρ?ΫεFΝμψΫπŸ‘¬;‚(snΏΰTBG?ΫNΔy¦1B°yQMΤΈO‰‹kΦ•ρT¬€ε~3’BVX›On`Τamφ|Σν‘‘ ,ΰ£hφš½fνΊ{Νqjΰœoλα)²g@'έ—Θ¦΅Ρ֝ψΟq#U ]ΝDF‰~†λΔΥ“‚OM ΗXΦΡpΆC&P\’ŽD£ΘOΎVΫ|5ψν=»{°ΧΰκFΞ~’%';ΡΫΧΌΐήknο ’ΰ¬₯·§‘zξ±A¨ƒ@£vp=0 ;5M`L‡CαΖ’€θμς0$€ΆKKΩζT`>ΐ=9plψyŠ3χρ™Αcm•ύ_ώk€ΉδδBτQθLƒ FCίνψ¬ΌΌέΦΞΓό9π2’­ψV4”7 ŠRΤρ‚‘6uμθΕυ“ΘδϊΚ&€~|ϋΏ0ΠϋΟf£ψεΜ?ή$‘ς½wc'€_ϊθ`Π~ώ’ώχώ­ζωΏ»ΈήΎQ| *›q’γ3)ψΠΤP˜Ζ―Ύ“REd*”yΨ9ψxΊG,?.Μϋ»Γ%WΈ±MεcqDGVŒ-¬ξΐ }|’§ŠΟ²‚Iΰ}ΰ{+ξ*²ύμ·h€»yΓYαξš!«ι©iU€/γ#«*π 9K¬Γƒaΰ"3VεV‹OV§΄Όoΰ₯T«+6τθT§pf<#j_p;z6‘΅²c­Κσc³ή―½+ΰ<嚈ΥA¨ηΰ’.š<§'D€ΩmρΙ!ƒ_ΑόœΫ˜λ#α&ιw—{―Σ†τe”zRμΡψͺέ\tω­kŊ֊=Ύ€ΙΏόY‡›·DΊΟGΪίϊεOΪgώcτVtπβ|/€nBϋΐ”ΕπρίHM`ΫVΕΙ™»ωΗŸάP€°―—ώ_›†²I°±Cυ:*Ÿ¨Μ›|$ŒAZͺ ¨ςW=̏Δ`kψP$‚H‡ΟΉN=±y’νA€ ˜IGΩο­VA"<„ΟφšfΣ‡±•ωΔ—εΧ!NςγKά Ϊ³6π_ηsÁލ΅…ͺ’t‘|θ“θaXϊθΉυΑΘ5ι&t'Wd}…7NΎ­ ‘ό‰τ†‹Ή/,|ώQC=:2U‚&φPϊΐΰΏρn€!ψίX+ό/gώ«°FL @_ό§΅6šσΏZ)ώ‡ωρŽΫ§Iσ‚}ΕΓ>*Έ§ ?*ΤVΰk†}Ν$/„΅ΞΆsr}ΠΙwViΧ.φ'Γs‚‹‰\ΌT΄bΚƒiυΟAa΄·+…Δ€ ΐ«•©δΏ”ωΗ’HCΰ ν­Ό2ΘψΟ΅Š`ν«Aδς,6“Y^,£žΒЊ~Θ€ι¬ Βμ€]e+ΨΚTΠΪ4˜'-‘ζώΑ=^’"ΊVφ)WδΫ©νΪE€‰άŠ_ΆόO7€ρ0 Oώ/­ιUω?2δ™β«;xΝdΠςΎrΚ,²A>ήίύz ΚfD―…ΰZ ;oΔʊŸΣ„δ$Πυš‰ ΄‚q₯·UŒiβ†δ:‰ž•‘~WΈ†ƒό?[•!gώ=W(ω_όC]Ÿˆ2!Pσ?ΏόwNQΰE (Y‡½‡tΐŠ €Œ;—ό‰G”QMphd•’Φ€Š šΡa!™xL;7Ξ£ŠV¨²ο Ύ&Κl¦€ ύβ$A˜δ·ώ‘%Γ5qύW}η†ΦΗ,Ρ„b@’»#η_Φx~γ‹CM`H ¨w‚½?΅.π‘7˜&u'Td-dgž„Άο:ϊ n ^§;·ΦΦΏE7DNβΝlαΤa'ΤitI£·‰έ£o{Μτ6€ͺ–€sˆXc—“q7•,8(ΏΰX,?‡όΈpvΕ0ψωΟ?iEςΏTEΞsoΨJΕ"Ι†αs΅VρRπ?Δ3γΥjEΞZΩeΰƒ\ fιYQΨIΕOv|χ;f„Ύ¦δ_Aώ xΞАLΘς ηΎ¬Œ1Ή °J昩;;ξ‚²yφNkDq=7ψ™_M©/πΏž1)μ³0Χ‹ j€υD}wτŒ[°ίrΉ 3½ήεΚεi%£δφ£ Λr¨›¨·lL ύ‘ŸΣηπT""0N+uV²±Φ$WY*nB1’]+ώΏ ύo₯πΏŒωίοD«ύω$—i)ώϊ_¦5Uu’§ηβo,ΧΠίϊœα]?·Ν'°Χqg;s­«QZγ4Κ!~†j1›%₯κ؊V7)΄χb‹ς`‚ά>)DwPυ¨dyΆΰ“œ xt.ύ«hτ֜“¨CWŸϋ49¦―~`ΥοˆΚγUs2ΌZ/jα,δP½œ€‚Tψvχ~Zzγ}ύγΎzΰ>kTμ:ΈEρ—p'ΛηTΓΨΑ.α»J« \bxνWt?Ώ–šk™φΈ―T mOε’ ΐ‚α όonώ“Υ0`Ξΐe½Vωπ?Ικ»X™¬$`-ΐž₯ˆ@6@ο§± )-Ο·~dέKΗ;3χhϊ]^tΚπϊeΨ³Τ}:“Έu&τμLΚΤ5AΒή”Z† ’…^+ώCώt%>‰ΦŠ™Ηy%ξσiU+~ΰR―₯‘ώίOψ?ΙDΕω-+T¬~#πŸώ/Œ ώ“9φ%²…ψzζ½6‰ϊ_+UλZπzΙQΨcV`(KP’Hpn ΣΖχ=ζxσJρ~'™`ža^%’ ·ˆ ž›Μ/Υc¨5ΦΗΐGF'‡ Ι­ΊΨa!ŠΊ½†IΠΧy³½ N»‰iνnCΛW’o¬Γ Άƒ!—uΗ(|+~‚BΤmT€£ΩΫ~¦ͺ63Α45†Ζ9έφΐ,‰ydo΄δ<ΖόΌΦΞ°ή#ΦΊέ~h{ΨΦ 1ξ$1Š©Nhη°ΗH7γμξSœΥ­(—όάΧ*Ζ Ϋ;ΨՏΝΕs\ƒCO·`eʘWα ΒΈY+ύ_ςόομ˜CίlΘψΏΥFωo_?ƒξŠ™π‚Ϋϊε¬οά#Ԝs6 +=˜ςϊa₯6ΣΓgSv°έΑΨ(Α]ΫυΟ—β¬y£ ]E€†JS1_΄`Θ>S.ΙΉ¬ 8§ϊ ι!IΆ‰1κΐTV„£θ xο „λρή#l,’n-Νu.€TY]ήΎΥ‘ ΦaPΫk΄ΊδΓ*7xCF"&n—¦ι Α™GψΓ*€ˆΩς$Θ™psF(e*šΈŠά§ίύΘb*bΚE­‰ƒ«0/₯7ςξΜK}ϊΏ4ϋ‘ς?―Αώ…γλ€τρ, ’{emΤόΟoa3τP{Cδšpq`¨ŠΥΊ©Π©ΟδνtΖΥ]9Σ₯€Jƒ(£ΐ»Ί}Ί¦šaξk*yj₯Y°ήά¦ΥN«ΨΞ§Ϋ So#–ή9©=Ϋ4 •ΡΞy:½/³†Τi„δYμnž.Χϊhο:§κ!WϋψϊεsYΝ!ΆON@kSJF₯@By­Υο–ρXpHόj©όΏ’η?ΖΣηs«ς―A»%·ψΤ>in5`J†H<φGΰΓuαhι&‘#6½†fS{b|VI@Ό0–«ω Šqξ’ς–Κώ+yώΟΆ±==Ά7τε™[Βώ»1ΆJώK‰‹A”<žνΔ9₯φ^ca‘=ul` psρ™†ο#τNHΐΝτ9ΠΩo²oΚ¨<ψD]γϋA»Ηu¬c² šxΗΕΟEkE»ώQώΡυA-θ*τγ ΪWJ²ϊί(#ΐύc(ώΩσίΕ”θε\’ό?k•'G‘ζ›‘L‘s&ι©΄:φβ5F•*Ε .Β ˜uΨτMͺŠΧηψϊόύF3πšPH^ύFΰ?!₯†δ¬-…$Ο?6@ŠΠzλ­ώ΅a©ϊΟΧƒIΞ7Ή9λn…€βŠi*[KMY μΆ0ΉrαάRωY9WœΚUhΤώDsχmρ|xΙή@8_φi)υfjό'@·άlώ“;ίρΐρ–±¦Δ+ώG ψŸ―‹ΪaGΨCpΓn4dWš yΝb6έ”œ}ΗϋΏ¬ϊ?*ώ_Κόƒΰ\ΰ7-ΖυΟ2kƒτ[›₯А =ϋ·ΧG€[C9…Ϊ ?8‘Ήή<ι½aτθ·γ³ΫξgϊΛ—­žΪvJ±ΟmŸ+zΒχ^v„ΪO EšΕ‰ͺ]8„Ϋ'?ΤμG³: 69!ކ>"4½ΦΪq<7Ι79l2΄}ΧΡOΆΏχΘ0„JŸ΅v,y©τΤ]>γΑvΊή.Ρ–#.َŸΊ^1>ΟΡ]δvέ(:=š“³ή%ϊH˜^i½!―Μ Ό@< /Μ©Θq•αЎP$TDΰ^π_χwίcξ)1ΧΕ!ΙUώw©sqxΡv˜Τ23Θxπ"hΊΖ‹Y=ΚŒνP9+PT†ϊΩ~έ‘έψF ŽΑYσw3@mΟ7d‹ϊ6†7¨ΧΒ<ΘΌΜd&]=MΫ/}VσΠ·’¦5Φ€βrÏώϊ†elΆοβ)εaι1άΉvΑKz!!'κ­ξΣΛ\D‘ΰkπίψομ,Ί]’»B„}]‘FspEέ保0 ž]Ψ@;ۏQ}ήτΰŠ~Ψ»H­EvΤ zπb¨b'f Κήρ‚œ4&‰ xy JρV?9ϊŸΠŸ‘ϊΏ΅^©όoΉσŸ ˆιγL<ΧMΟVιτ–@ΰ?»QΰcΙιeΉr¨ͺNˆ±2™PΑνT/Βl¦(ϋΗ†K˜πMδ'ΖιΖcΤc&$=L7/œQ¨fΦk_ΆcSr»Υ±‘YeŒ™vVt¦eΈg€½/ΧCΘβA‚Ά8fιŠ Έ©X:=„rIΫGœ Η A°7ݜ5x“1jœd~·>{°ΗΞ€τπʝύaΟξUΓk”ΰdξ=ωπ&»…nΤο δΏ΄ϊO…δΟ?ΞJ {νζšRIΩ$ΰ?ηpΤέCφΰ—οδώλKJΜ‚vh‘dG±P£ F…ί7J$,t©S<³±ι†—ƒνΕ NωβΨΞ C\$pZ—™Ϊ0¬kV¦6·τxˆoƒc/P]―αγJγŠ„ΥΏGF@₯iΈωƒϋȞ{φŸŸ~Ρ’ ³"Ÿωu@β4HB‘βωεh8Δώg©ό/9σχ •ωͺQκО>k½έXώe“€ψψίφ―Ύξx_FG"ŠhGK0/ό½Ίo©ϋΧ,3ΣXΐTΉ c6ΐƒ±B£°–­α―YC’\οθλ†qΧ΅Ή±W™gJ+RΝg0_•­š₯˜#΅ΰ}­—μΗΝdWθΗ ŽY“υS£ IΈΩHœ4€Φ >2ŠΞdΊ:Ά‚*ΨΆ“¦LƘ2]Š(ι$δfήΪq³ιx>ϊIΘθΗUΎm­ΟB)~‹©Πsbsͺ’Κ#*‘ώ£ΦOΐ ανRD§Ρ¦WέϊZ{"5τμΔ‘‘#δ°δ,;¬nHΝ»h&Σpgaπ°ΛH¬Σϋ“ŸΈšrO²,όρλ§ΏόώΛ'-_mΪΡήC-: Ο/νlώ:ς+—fž oε­ύϊŸœόoΓRωίΧ‘£ ΐγl}ό«%Qm½έ(ώΟ뉦½ /θ–Ÿ ኼμΪK½‘F€υrr#€@Ν]Oe'8ζPα[oήZ/ΊΌ‰υόܐ“ψαFΡ Ρ AuΡβ³T(^­°ΉV8žkζI΄;ώ “}φ©}Γ5?f%`΄pΕt ΜώυΛg εϋ1N$@‰Έ‚Έ'Σ:^‰s@jΥ‡ΖιCπΦTψOΚό»>όώΟ6ό—0¨>ώΗνΪ$ς·+₯ΙπAπ·ν, Λ0‘Uo¨SŽ‘‘ŒΣΟΰΜώSHa=y ixδΓΨ\[ŒΟ¦·0π˜Zΐϊ °E’”’\¦VlQ2ƒ“Š›Έν €Žύ_Δώ‡νRΙ)ς?χtΝΗhl, £‘κΏ\}όΟ)eB[¦,‘-1aμlξ Lˆ3v}ΗΝFί,ΪMPʐρŒ%ιΑ.μLΜ+–冏هP97ΔΠ ³Ύ>b—λ?½ŽQσΩΞN­QόXzζyDœ™1ΝjϊΘΌθ’?δ¦k‡Έώ œ<… g©˜Ÿ2Un‹‡nu‹ΟΆη='_W+Α»/h[οο~Qΰώςb0­ΐŸ5V™{§ζfJ˜ l κ1NΩ±ΩrΙx‚͍Κλz“y]’•Ν‹»GξχΟpήΡφQ[_™`A‰RU™χH 2ή΄±”PΌξο~½Έh=η)_Ά±εS]D\b*Δ:‚/jχ™ŠΉ–4'±XΎΜt§zKv •ω2©†Vh™5QkΣDg‘# (η’ΐ <6»D #Ν2Q܁b‹ ΄ Ρ­­Š“9ΐ,όΟY{΅Uω2ό?CC=λj,₯.^J E!Χ₯Π‰ˆŒ(€4ΟPAδ ηšoQh‘ε)+‚°KΑ‘"Β7’ŒϊI‘ψŸ·ŠM*ώGϋΊ 'PoώΏIΔ¬V*ώWώcσκΰ˜ΰΙ¨ώ°1K<^—c=I2«υv„%ž†O9.Aτμ:Μ<͝iεY_°xZV€–—-ΠZž]ͺομ`΅•O2>Šά€VXžjΔεΆγrΫpΉΜΈ·™Ί_₯ΫB·‘†“u©AUš”’-Όμ<7>;‰]S½)5Fώc‚--gώƒΓ Σως¬­Aζ―M'—ρW˜Ν{H,•Q₯‚~ Σs)G¨‘R5NςͺΡ¦Iͺ ώεόθ„—Έ$0eS’²•‘4ϊτΚνΌKWΕ9πΜ1'ωg«‘­δ),ες†s…ΫρŸάόߕ╃³Hέσ? kIς¬ Uσ*β?ϊΘwQZ.X(ΛΙμχπln‘bμsΰϋβgtqJ£e΄°—4ϊ€-‘ˆ™ο•€πΊβΆ ΏbpΕ“ρ>χΩρŸke‘3QΏmι¨ψ“λΔΣΧ3–[’ίTυΏeΘnΟω#.EJηίΩ±λhΩ²Ζ~2lGAΎ±ύ[ dςI6Ώ»)cώ>*?™ϊ±ξrꘊ[Ξό/χΓ;λεŠΰ0Χ–šωϊ΅ΠO_]ž1τŸ‚ΨΓ2φ2V3CΚoΦ΄T”›ow–ΥΆ—{Fj©γ+Κd₯tŠΗ¨VCͺ=@ώga @φ\=A=•½<Μ₯(ΐ·‰ήG³ƒμ«:αGα "›˜šύΊό―·Α?7M)ΦiάΕa3G­iXρRBί.>Ό΄{—Y»Ž.³B ΪηS˜Μ}=‹oΩν’Μvƒ«σ(W#Ζ±²Y™τϋι|̟Σͺ„_Ώ|–¨οOZέJΧΥo„ώ'”ύqώo6ŠOΦό#Ψ9£ί\­Χ€g©βΏ―KŸ½Π/—A‘NcHΡ¬”‹S§'Υ?Ηsΰ Uν[_–)\_š’z―ΡκΑvΰ­ΚΑ©ΩGρ[\›ό—aZŠAΪό£dmψ ‰Β€½υί(όΚwνψ%0”’ηRuΧΐκ-A'²EΘβ4q[œ.n±”Yz‘Ν'–Βaꃀ§Xβ{Lνΰ{άύ"¦ΓΩV"dδO― n<ϋΏ 0$ΫX+ω/eώσ*YΉ ₯'‚κ³Xa@Ωf‘dύŠσ'v΄π%RΪ¨Ά)+›"έ΄Π§!ŽΣωΔ γ ƒFβwξΪώ~Ό .»šΓ'ϋ‘c%{Œ?ΕΒΧΆEΝb½Gwχν.e;ƒ₯«ίσΪ=^;•?rΧfy${‘Υ#ΙΎςΎ§‡t‘«¨Εƒ±š[ “ωd–We―Ήω? ΐΈ€•ό—1Qί|ώ?Γ0,²ώοj©ςΏ$ΨZΈ>χnΈ)Έ©i(+™^\(₯±Ε(Λϋ]Ό Ζ¦ƒ'ˆ¬6L³6΅Ή k6(Δ,ΔU>­š le¬š?¬Ε€EVΩiϊ¦Α/Θ#™]„°Έ~gVΆΞ;ιΙkβf"γύΤP»θθn~χτ°rΜ¦{ͺY1·έυAtΆA†ΕQŽž¨‘ΔΤΰαΞωΐυpk}d…η₯ς’†0σ-;„žΓν^5€±ϋ™Ε#ςxe˜½ΦΓς£\!βσ‡ύΎΫτ; ‘r‰ι,t'z “ ³ηfcΞ<†6›T3•*TuΖΎ{/ ˆpΥE·³_­ΗΝΊώ DPΰtυ]΄‘€dσžι–qC51‘φF¦¬₯+Ψ?³β „>\W…Π]jΤhίέδ€?=οwzX u‡4J‹L£„§λζr| ™³σ ³‘ΛΗ+,ˆω‰ Sy2kΥBϋkbGI¬ΩZΊΘΰΨ‰CΝ?Φ.! –aξ΄τiАώ%XΫΈŽ†φ€…φ3&νŠ5$/~†Q΄Όus–ΙPΡPα’κ7±ύW6—ς˝ωκ₯΅^›υΆΚ##ώsο!˜-ƒjΞ?ΈΟCΙ…‰1Ô䝆)»‚SZμτ-μo¨†ŸνV˜ωv: ξ0#.i3c6d9-ͺ˜MW¬ŒΑW›₯1fΏ°₯kρΌ ·QfMl΄NΛ—γWhC½B?AνΓ£ΥU†¨5­ aΡ“§*αΦi]šΤΐ4i΄™Ι}]²[cnΉ–›ˆ°ψΘ:­„Ώ‘π·nό/±ώ›ͺ%IΓϋχ~7_ύ7ct½fόΧZιτ?2 ͺ[T!sX¦ϊY‹&7gΕ΅γŸ„„ψŒτΥ ΅££o]C²©ΠΞ6bπmΤ„Qg¬9Ά CΈηώ–Γ‘Ω<„Ψ·ΉΨ&^τ Υ6žν[Κ8.h—\i©ςδΜκEE‹@t?!W•/Cώ '{bckΒΣ·@Ψ$$Β77wι;{W₯% bΦ‘œsNqK―ιIŽ~.Άp½κG.Ϊ΅~›'9ϊΑ=žίj²`?1c"qή'LŐΩ΅$Πˆ‘Pτάλ5ΌΧ§υP°‰>‹@Ωπ >Γ H­&a^»jω/±¬ΧŠSΚό!ψβ @}φŸΥ–δάnTό‡ό眒ΐ ΠΗϋފ ƒsξL.pH”]¬ω‹ŒΦ±‚λEΜ( „Lœ0;ΰθo<$xIπΏΑ.†0$M;½T)?4)ξΙ?a-Λa©6ZI½‘fΓ©άƒ"j’Ύ 3 ±l΅Ϊ₯Μκ Ÿ“{c’υΏ­­ΒδΏνΗξ#ά³Ο™,Η!€v’ΌV[i–ΐwΐ£ϋaώΏυΚTψOώ+g]wp‚e†΄P¨OqΚ,π œ~½IΣτQA„ωΓ"eά«ί~ύΪύαβyθQꦝRUΕθoΈEΗh‡'†X-τώ„σ4|K©η€ΘHύΧ8σŸhŸόΣTδ)ۈϊMΆ…CκΏ[Ϋ•Ϊ%Ν=7iΌ!¨/s½$ό?ks₯πŸωOΙφΔ•’žmΈ:’ά‚˜] μ±Νξazf|β„Πd£4Z”8F‡ϊ”1ύΓϊg(σT(ΓΔƒ§Z±Π€Α&"ΘLΨ‡4΄βΣ—Ÿ δ£EbeνάΗa€!ς»VωRζ?ΥbFυΟvMΘΛ0TόΏ|ϋοΗ–Ϊ=f[`«ν“”›‡—νϋ`g ˆB:ϋΧšςO­ξΣΥ2ΙOεΟ͌Ÿ3θΊ¬ίΏΐθŸaρ?KΕ:σώ_·Ο½%ύΦΚRώίωυΏΜœέ‘ތs»eίΎέx·Εό±ItiΚ\ ަ@²ΙΥΒX΅8}¨qΡC’’ΩλτΣ°t=–Η±9 •‡Σ82– ζͺ \”«`ι™³rE©gw,Κ\ο¦:X°ιΎά>­jηz«6Υ‰χnlοΰ'Χ1ΝsψΗ=όχΓΩ~yτΐ3πƒΓ‘RΕŠ•"č’Ζυ Ε”šΖ΅yOe·œ·Κ>bœ2™Ώ<τΊ+!Ŏ[=ΩνjπCΦͺοt Tζf†·νh•²γΏ»\ό7cό·eφŸΥFεJΠωγΏqΐw{4χΞ³Ÿ€©G‡½™ γCPx~Ό=-όΩ…;t[0x—ΐΝ©h)φs,΄[BaŽθ ο;:P‘pˆ€§?qΏ‰j'†*άόξ2βΏW–²Hωκ˜Φ†°―V†Š Q&~Cb’χΡ+=,˜|¬ Ω; ό”5T†•ϊ!#T3QΏ€%XRlŽ‘Άœ–_ξ¨ή–b£|všΙ Y4ƒ„›±ΐ¨]'–±jΐ%#Ή»Ν‚sΤι€β€₯1 g“λ¨ψ™σzYν[έ‰^Γdœ ¨­ίf½TώΏλσMSΑ#mνϊ‡€{θ:Vε‹'νqχ΄Δ—NεψsΆ^έ€ŠpΖuad…{L·ˆτhζpͺϜHn𐹲qY»ΗΌ¬q:ΞΩSΥ£Uχvλ¨8‚ζŸκωrƒI|U_’ΰΩέ#:mˆ‘Σ€Ψδw>€»,Άω•›«†ΘηέƒλhΩ+όΑ³ˆ’e—2ۚ›υt6@r$•Ÿσ>δ$8ΑζΚwMσ?ΖΨ_ΰάΆ Ϗθ™ρœΥ‰›kg°Ή-bΟ΄αΓZOΰU’eο>Ώ`vΛή΄F/±D 8F)PA·‘β™ΰδTh½’ύ  ·+UKβόΓΰ΅;Oύ7‹¬±^*Ÿ "{:‚H’ wvšησ˜ς¦ΐ]!πtί]ƒ ΙΏœ³Ψφ0£·mˆΪƒέε˜Uάc2Υ+jοΤ’›εΔEsχωΦPtYY«ΐWQ4†Ι9Φg*ΧKKltΕpT}m“~v}χ §ΰΎ€½†yΏ΄r D:γx±τύ p•Aγ½WCιά%‘ VΚsκθKŒώUμΦπpφb ₯»°£r˟ #L‡ͺKU…΅”³Χά–ΚΎ‚ω·/‘=uύ Ξ6aΫ¨ω{ρo#|xβ‘AΔSUG/nƒUΡ­{«Ώ 7ε„ӝ7ƒGoR§/hΖΕHϋ2w_\qέν~Θβ9jΞj+’vfκΐ₯/eŠ>韠ΤΤ*xwb@­#)­P΅ϊM„dΤY+ώΏk˜½Sγ ―·*ώ[αFgAQΒΖπdή:ΡΈGG)yŽŒUˆ£Χ“‘Ξ’K10ͺvLϊH†Υ[ΦίΊίΚ¨mιžΛ¨ΔΥ.6Υ }Qνεͺi:`±TθŠc…Ή­|}σκΏϋτ»ηΤJSϊŸϊM„₯θŠλζ? ΎOŸ³5Lrώ—*ώk~ύOnPξΚΞ„ΐϊvπ'#Fδ3ΟΣΛ0½1Λ:άή6°bΨ₯δ¬VjΏωŸͺm#@oώ―Iδl–ͺώηΘd#°_tΨΌx―{ΐη„ζμ‘>ZVΜQ‘6—†πήS%y•ξ{zŽ·₯7νη”δ™ΙWIμ#ΐψΟ₯ͺ{ 󏌳Σλ֊’+ϋΟυΙρœPrDΡπXΕz7μ  °Ÿ8p‘b©uΩ¬wπf`Χ͜ž]9=Κΐ‹ ς kυ5<6S³6ΔϊmvύΊoE0μrτKιε„0°ΜΏ±ά ώ/kc*ω?ΏόG»ιϊCoθ)ΨwžύL=:8 z|YowΛ ‚ͺ=[Μ—±° qΧiΤΨΏϊΊγΑ7°σ@Ο;ώHΉμΝυΪψ¨οα˜O¬ΟSJ(Βσ‡!$­=΅ΊσΆiωΤ';>ιϋk]FcM™BΤ‡Ήή δ‘£³.ˆΆξΐΛΠeΊ":sΟ‘§gρ=/‡œSΟώνυ1­9쎌Ŋ֭»‹ΒWφd°”ΣΩv0†ΓwƒO^’ϋž‡"C!œcœ”Rˆ7Θ³γ~ΜΙJƒfoV–½uΦD]”'v†πΜυ»‚ZKŽgš&9ωα²dλ9kΜΣ»Ϋύ2PφξPn#οœΦ―aU˜zίJCΫ5Χm}τ}ΆŽŒmŸj•'βL=~iΈm~8Ξυ‘ν»Ξγ j0ΘΪV΄³+{S[«(rd2&žΘΌ]u³ζΔv§6Φg±6.~Λ…Iύ³φ”™£’ίXMύvχͺEy·ω[Κ»­žŠώτπί°Y†δdo)fT3ƒΙτΛ@)–o‹Λώ–išJ“6pӏΠξ&H μ‹5W€ύί²Tό·ϋ…#’]¬P=ΖΫΙ‡ΫΕ!p<λ±Y.ΜL)™kϊhρ% ƒ(Ρ2Β’:9Bz‘}bhΑAK@œhΆγvqφ N%Α‹ξ•WςΏm†ΨMU]κόc₯oώΣά¬‰ωWυ₯Ȋg΅κ·O%λγ‰ŒNμ£ ’έoβlΚ½†β±εγk[Fϋ Υt+« B/I­1 ΪkΨ“YŒtμ†εf`Bƒbύωθœ ²σ0“9V‘(%]gμϊ&MβνV+·ΰ+ °*­μ*κ½Κyό/«ςJ›³ύΊCψ …Mƒ½Ύσ‚έp0Ψ7[²ώγvi)ϋίόώίΊ}Šu?Έx³ΚŸO ΩU‚ƒ†–\όƒv‰/Άη½j·γ36³ό }?ΉΞIƒkTΫ-[€1 LκʞJ‚Ά vU,bί`a0$ώ»΅Τχ/kχαZԁpΆψ$€>ύ³$ωΏ6¦²ΟΏK ΘΏ©dZΞβΑC*OΨUυ8π.8Υ…ΊWτϋ‡Ϊ‰‰κ JKƒθ2Xtϊ‚φ9rp ˜ψ[£μby†%‘v{>eQ9ƒK9Φ‰&=L£žσμeς%ψ«–/3ΝφŽΎ‘Šyc*ΔU_ΰΚΉ%Fώ΅ βQόoW3‡ΛoΏh2ύίΨ _OC7VJ—ΰ9ώρˆζ;•ˆλϋ;hα$+ε~J‘9°‘Vy,“o•d½Η&DŸMT γ‚eX”H‘ώΌΰ—πΩΗσωίώ0ŽέMχ–yπ@1XxΩyn|*fW"ΐKT·½πd£―ζfPΗώ?§ύgk,Υώ5ψ―ͺ€}ςίZ7ν?ζr₯ψdΘ’]wpΖAf A₯@jψ…ω±ΞOJ―WΏ!‘QΡ2$’Ÿέ'ο7Œ.m„ς$@¨ΤΨ+%xqIτΊ»Έή>οwe΅•–«Ϊsκ–ΝrCφ8Dζ WΏš}³Ϊ/Ψ„3‹xm˜”žύ&χ~ΐ/αώo(Ώ΄ωηd»ώ<ρŸ†Eκ«•Κΰ™Œ,trΒ%!.F£†)½Na9₯a½LΝΏPν{=Α§™ΑΆž©¬κοg—XMρΏΘ›Μ g “ׁ3OΖX₯KΠQ6’3E)χ’ΥΣΟπg ―1νO"QΠPΡ6$C’DƒΫψ›1ΉΆP§|A¦’~rκΈ1|RκX¦Ϊ₯νQθˆ$€λӌ%QΛZ©ψoϋ_ϊς±s Χήβ ͺc ’γN(kΪƒρ=<ώ3.GΪ|˜,υΧ/Ÿ+ ζ~E‘^89m1•؁‘R΅ΤOΦώ/hΟj©κ?Ι›Μ†5ΟjE±Z+5δ'ΏqEvάξνφƒvΆ_tΨΌx―{ΐηŒ £%κ( AΔZ_tMe”5ΧV±k_mδ²3qδja¬hΌθ Θ‘ŸΑ™4 ϋ ±ί.nΖΒν1ul΄[ΚήX9΄ω —έrֈΛψ~άΰΊ’9ΰ2mS¨ ΘρΕξί";h0ώbψ%{-˜gλΑ)iΝ@Β۝Вs―:ž ό€=³₯ΐiCzˆ.c’K>&ntΆ£§˜`’ν,GζΈτ€ΛΐMΈ%­jKζΪ4Άβ*ύm]`±(zΈΔΰq ΰΧτ5j?ϋ ’ΤρɎΐΎTVΣ*&Œ‘Ή…t"…6ο^)΅7‚%ςΏYK•-{ώ+όΪ£4ΑΎϊΟ+ƒ°n¬₯ŠΉBύ/₯†}΄c(qp`%@ψnήZ" υ†YC[‹iL_τ‚ψͺτ2€Ί]ε1©βp―A„q [ΟΈρ΅Τ™˜Ά0‘uΐM€‘{rΕ t‡δJ³.F^NM ϋΡ+)ϋ-΅}SθD,•/RHχHۜκ*EkՈ:πohΦ½ κQ4Ά’‰c²Ή*K•έWb _ύ–δΏmό7JΒdοΝ‰J&Θ3·"ΓZ+ώo ψ'€~p ©”Ύxu?2)–rί“ˆͺ1^j?{«3ΥHβΆtA‘bφ—“kιS†y%`τ`‰ 6€5-|‰‘œD±‹λ>8ό\^‚πρ½(±υͺr0“썩$ΆΪηΙSφΏ«š€ϊ 6φρ?.W&Α`Uό―ω_–9,ͺXVK&Φ‹R6B ^ œ M"2h`αCή‚ΩjVvŠθhρίίχΟή›59²dgbΟΊΏVzΙΉ¨φ}‘LfC㌀6Κh3ρΣVνk%XH @Φ2ύw}'@b‰ΐ’ΘΌΝF‘}ˆD„»?η;ϋοΪ ―0ΜΨNteΏΆ<Ο-jwξψχι2εlόΊ§¬9ίvό•’ϋ ;\φ°~³Ρ–£Ÿ‚…o…hŽnWθŽ±ξ†“―5½¦ώ“wύ7Άώ + <_ρΨώ#ξυή5.ͺΎπ°Fx7W”.TΧF…ν^΄'‚τŽͺϊ`Ε›Ε+Ύη]λUΌχœ#χΒ2§ZοϋΓ ^¬γβ~ΪΓ΅υŽ6 V>Ό)μZƒίΏnμu5xύ‡ίϋ?ύ&εŽ*w18+υaώχόο»όΏΛ»όΏ΅όί3MύBŸα—BWΘ!Μέσnςf9ΞΏΏQώ―0¬#—ίσίάsσ˜νk2aο)ŽoΨΌσ,ϊΡδL*°οό₯6ς‚ϋι1¬ ŽΧ9’.ώV;™Ύ—•ζ=ΊqΘH9 ѝμζ vGύnιQ‹IZ΅ΑΒtmYŒΧ°=vϋ£ΗfΛΡj>šΜΐŽ |ι,₯²ΆNΝ2’Χ=ΆI~7«8³τν’u‡νώ―νu?€ϊωofσΥί¬ΓΐΓ’I;ύ ιHρ?>όνί~ψΈOŸ QνΠπή­zo³—ΝΉ,ί½αGθΨ>ΏeωŽωβήαΧΏ,&a:ωσΕ?/X{£™ΌγwˆiέχκgΌm₯΅Τό™zFνΛΌγ…a³/?Έ™ άyΒ_x9Πsϋπώoν=γω’Θπ­τq\SIuψνιqύΏbϋYœΘ?EημπεβTλυΕomηΈΔp!φa+Ž~sΑΛ€ΌQηŽz©KΉCk»Ό@iξΟ»½ϋω―σWΊώkήψ6ψ[Υ±ώβŽοψoό7l‡°ί2ψΩΕ/ϋˆgh4σχkΕ·‡IzhςžΓdΆΫƒl΄z«QX”Ρσ²ΤηizφΫ…·—ΰτr΄f7£πτ΄˜‡Ζc4™>—YY„ιΗΡ*u2›΄]eJ‘δ*Ω`¨_GΛiX>ΰΏŽΚ*>ΟGeQnη%ΩδΨκ$OϋΏΉλο)_2μnήKΪ£ψOΥ½ϋ»ΨΓtϊ΅νΝ©ω›—υ£ςΉγΎΰϊΙΘŒμxh³ηΗu₯‘KŸ.>ΊjνĚΝf:¨BΨn¨ξ Τ[ρƒχ ήΓοk&·ωϊΒxϊ­—{[κDεΒΙφGλΕάϋJλ²ΥίΠΪΊΎω†y”FίίpΝύښœ·+tψί†Œώq“θ‘οwΏ6ΐΝ4€έ‡όeDK½½OGuΟ}GόŸίΆcG―{ύΗ·ΑΘ‘9ό™£t’ΠP^jŽNΛΧZ‰:Kηύ―£Γ:ΚwκΌά•vμMu1Ρλβλz@Pdζ‰ E±±BεΆΝp˜ύ‘(nΝO­τ_ŽζmΏυΣ.3"˜x+ “οΎ»ϋΏχδοέ‘ίε;SΜ­όΖvδΙ»ύχμ‹RΗ),W―oλqaΣ—dέ π€YCvuχΎ‡`.ρωσΈ½Ιž­`χΔ[š₯.Μωή΅lzš½Μν~&ΥΰŠ}ΛUΆ>Ό†s)ήjΉν@ΧΊ…Ι_π:ΙίΥwΟ}7ωΏ Λ/Λα,gγΏ₯=ZΖοςνγ.qœΉwτ=έ +Χ-RΏ_Y*¦£oΞ[Ζ!ϋCnΰλ½§¬g| ]™ή—”΄ΉU Φ°ό1K‹ωlώΌόuτ„AŽ žž[LšmΈκePg}ιmpΞϊζwσύίIω?˜θ5φ«ξυίήoύΙ<Ώσύ'‘ΰωψο#όgΨ=οπίϋwšͺ_ϊόƒ‹‡Υ5x§½exSΠq›ϊKσ χJ?$XώB›ΤρD웨ώπΫμεpΐ$B«^Δ Ό&ώΓΪ;?ωmiy|ΖtΞώ£(ΧοΐώcΜ=ώγνε£ΓΆ‘ˆgΓGυoΕ7TŸ››Ž‰jOΜ’ζuΡβξνJ Lf”Ύ4[]j½½ό½€ό„Y_}1π˜τ$ΣΥάΜϊ6Ίv7ŠvmΐΪ#L:°³½n6Ϋ4jk qSBpϋͺmxΥ†΅ίŒΰφwΣ_ΌόΔτŸχόχ[6΄β$“Ί£ώΓ=ο―ΕώSaYς…α=~ όvEšή CkLFΫ‚Šgn:`g3Ϊ½u˜WcϊΎ†ιsc;qSρQwηή΄mΠ.ΜkšΝvί㜽λΰFέi77"vΤIQΨ›ΔΝέΞΠƒψΘύΕΥ«jΖ›L©—€©—œ¬—ρυAΝ\ΊΙΨ:LGκΦξ¦Ϊ χz‘Ώζ[;ΰέχάIW[oρν[Υηιtpδϊϋ$ЎKt'¬ŸπkΣuΌ―[Œ{;μΊ^ͺwFJo,ύ-B½Ε―λΏφ‰xΪ.ΔΏΏφήϋξ}ύkΗο§ξψο=ΧΆl3³ΖOσωτ'sώ_‘ύΏό^επ͌šοδXœΌQyΟ~Ω0#Ϊ0›LBŒ­ATOΏΏ0©πpλέθ<ηn«»σ>ώs@ΰςίπ{―ίΖϊ―sAΖO‹ωΌΎœυκ£ώΦΪϋϊίύΏ—7•»ή{Λ’£­½κDΆΒ•νιξ.αήΚ['&ωtΑ­aŠξ{άeYw‹4­‰eΗΊwK'ρ.N]3φQΓΨχ’1o8χ„ΚzώεΘWΑWΰ?kε½ώΓ;€ Xκl_iŽς?ŒΌΗύφόΏΏ…βε2αš*•φ­kΞί*<&^ΪίTΕO€•ζωΕέ/?τTmρ»‡υ›9Ίgs”Zθζ°Θα鐎ޠΰηš>Ι‡ς₯,Ϊϊiέ8Ξ Λƒ"‘[ΊΏ΄ΎηnώμΰύŒυLž„=PςΉΦΡσ²)β?:ζ £U\«σΕcX]j”ΫΡIΉcΞ³ςΈ`―ΙΤζχnψoMΞoΥQλŽώϊŽ{ψο7XάkύDŠa9g]±o·ΓΓ§šώ%ZιΦΧ‘ύ ›X ςrρ;fˆμΧEλ(v™Mπΐώ·C―ϋy#CC΄g=ξΗy~ž–ώΪΊΫθŸσ―“Lαv£ϊΏοΊCώ˜άΊ‰B§όΚω΄©ε;(xέ@…Ύ,ίفδΧξC· h}έ ¨v )’‘&Ί‘ΜΉιqؘO^'hΓΣdΌ‹šn*oχžt—² όg ΐkβΏδ=ώϋύ֟”“Š?k:'υ±όΧϊ^χ=δ£σ6’t ±4^=?MΛr›φφ ψΊ­‚ˆ~rΖ„δ//bΪάξΨ p»ςκΌ­ψΠ"‘Άηςz΄ˆeυ­”ΆΣΝΓ|Ήj―ΕzΥ+{ίμsˆ[ΑΓ§ά΅όwα?kxMύ/-ξϊΫœΜ~G%—΄KΎ”oVΩγϊ²»οδ?eb§dΰΦα’:\&γ4μL΄ΏnΌ†?'κ―Ώg%ΗσŸώΛXβU€l¨Ιbτ/ΏηkτΣ°\`Ζε{*<=DΝ~θ*πxqD¨‡Ώ‘(:±ί΅ώ³‘wύοmω»φρy2ΝγXŽΫC?-Ξ­Ώ1φΈλ=η]μΏΰ‹§΅l¦|h‹η?4žΗ¦'έbγrl–?6žσΗQϋΓ[Υ©Ϋ\=>¦ψΫ)ςζυ|o°ί§³Έοχΰu ώwάξPμlΒ{?!ΞΪψqύmορ_Ώόœ8ΩΖςω‰z1wh-­Ο_h{[ίσΗrEεϋnٜΎ4ςθ§””ξ€ώ£{ν˜L^YgΤ-/ΰ: Ÿο1MmjΔδm-‹mdΡρ_ώσ%¦Γ­Ψm—ΌY†›ŠχηΌωπί1= xO‹»ώχ~λΏxJ>€πlŸγϊOZάϋ?Ώ‡ό_—,ίZΜ‡_šΐΧFμsύt3ˆβ• ‚J\‚Η­ΔoσΟιηΛƒp"βωΡBΫο˜ΖtΏ¦BVΧK‘Εϊš+ΰΕ:ΗΊϋΗ}y―A/ΚΫ8υΥόΛdύw¦αƒc#²ŸΐΏBΟς’|ύ§ΙβΛ²ΜpMσύ?ζφ;Ιζ“eπλ?ύΓ 4ω_–£-ρΌά Ψ>ο7m78Οή όύŸλ»όgωίlξ!Ό€ηκΏΛγό£χυMΘ­₯Ά";ΒqχψZΖvn£~vΟ€ηχ—eR4$άpγMgΰ^α½+ΡϊίωΕU6Βη ΒUχΌζHG Ο>β¨(ΰU@{οΎoΊaœΞΣ—ΦxOΕάΟάzοκ+’ΒdvΩšK―mγxζΖCY–2.uΔΙ“ΜUδr9hύψR‡ύμ0ΆυΪ/Ώωͺ5]7»Ό}λξη5Άβq“ΜΧ^ή͈†΄΄mΑkΓ—Fε; dΙ£9ž;ΪƒΊokט‹χׁˆyMώŸ5wόλ΄ΧX=”ηε›Εq£Žϋ?±{όη{ΰ­z\c}φΡϋCΐήa>:ͺ Ϋ„ηοٞg˜η8=ͺ›`>κή†žD‘—&Lζ‡ύΏeW ‡O„/»'Ι/ΎΞύΪ6ΩY₯§£>γκ#ο(K±έGΕjŒsΗ€eύΚ{oΆ†ύorpfΝξ±XρV“ρκdωαΒπΑ±Μžε§ωZβjΎ2Ty`=K#ό]LςΖ8ζeYΖeύ:·ƒ2λ|‘ί4Œ9Αί5ώΣήϋΌ±όίΡrΦ*άPΰΌύΟΛs—ο wŠOοΦyο0 >”οkP°λ"άΤ.zi2w’—α@ΆΎ“f·ΧάΦw£ͺ˜ϋ=i‡<”)δρςCΟƒrΌΒ—ζZ³%a„Ξ›mΟγΣγγ|vΕ­Λχ’žWσEϝ7§―ΈγtςωaΥs»ζάε<―΅Σ¨ΆΎΫζτε7$€p)°»d!Χ·ΌΒ‹Ϋo,όi3a™μY _I*έVΘWΫΏ”‹ΓέΞύΦW\uKr|—Σχl.ΉbΤ=†λβοέψ1?'³S7ή»ξ7š*uF7hc=N‹ϊ‹Κ€ΊΫϊπίP ΐkμLάρ»­ΖΛρ&υ_Ή`Ηω_Jάγί· ?=.²¦@΅%•έ+φXΈξ“”ψ%ΥΟγIν«›ϊ>5Eb/)-2HΓuΊ&βtΔ+žϋΚ¨ˆ¦=Χe&PΥ•n>LΏ‡§0–Υ8†X<ύδΒ‘Bςψtε“ΆΏ»ψq ‘ΣF?ž$¦½=³E’γ•Œ9²"χθΨ?§chΣυzλ/©vσ5»ξ΅11αι ΎIΎ§Ε§Υόu<ΌΛ«£rψ+uΆκο8ϊˆΧ\’ΉΏζΧ¨τεϋͺ,@οM*Πk·wƒ+†W'͏~Œ?/Β,?½jYοq³¦‹ϋ}E ΖΙ«6λdώ ΫΜifό3ΆšΛήυCΉΦμwe=όŸ4ξl€Ο6ορ'žΊ[ΣμbγRYΆEj―κϊ§―6d½β‰ZΈ^]ΦοπqW΅ =ŒbΌώΧ7v5-}Ν'εκ¦ ―yΠΆ€ώmΫ‡ζ)x˜|wμf:φ»†‘ύβϊŽο?„ίδ8œup ώ+ƒZOΖ­žͺj™'KŠήC™ϋL΅$ΧΝΜ€NwpκΓ^·³c,ΉΧl΄už @΄sboe/l£ΦΣ–w#ΪΪΖ»½MΦvdZW_΅Ξ―ύ?vλ)ΎΌΨφ-χμ;Wl[1¬lΫ‘l%ΒΞΕ΄§ο±½ήaΧ/JΆσΑKvšΊ9ΈΥVΏ}Y¬VΉ~‘C΄Φί4ω(‘£)ήO—=hφΘ¦(Ρ‡7p«l‘ɍό*μξWΉ»ΜώŽύ_Δ=ώχύΧ 8°³ύ?«ξυΏή!ώ«†ί$fλ\ίΥ`ώŠLΜWE…υaψAβ΅:£«^`Υ—mωS©–}Y·ŠmΊixΣo‘vWΏϊ֝‹xJu»@<Ό]Χ“ΒψfωΦH Hωω.υουίίύ”μΧ!Α³υΏŽγ­Άχψ―wΐωΤ4Ή#ώ,τΛdφωΣtΎΪζ―ρΒΕc³ύε!έ―«JπͺzƒΛΈ%ΰΊ=|9QRαfeήsSΠ_4ϊΈŽΏ ΌBώ[-ψΏ—ό,σ2ω/Μ‘ύGv_χ·psŽΩ7³.ς΅λh\GΛ]¨¦wε§7}G›~Ύ(κHOοtΰnÏΔΞEα…‡‰σ‹ιι0pRλqƒa%‡N™)ρC“=Ϊd~ ?ΤΆΖ½€Ο_,σΥς_huΟx·υo™χ[ε3cEGώέσς₯γχ85rg-Ϊ &^N‰ΝQα?ός§ηωΛepαΗμ@vΦηιτXvjχV²s΄o%BΗ(4HE>p«‰SϋžωWΚ[/TstpNγμΈώ›Ρwύοψe:ΤΟ©Q[ΪΪ³wk/½’¬λ rψΒfo%9^φαM¬ŒTέη xΧNρ!0ΐkδΏαχψΏ·]γ|ώ·©e_πγψO~χΏƒώfΛΙ§UY<εƒ Ÿn["’unδ'’ŽO‘±>!ιΜͺ<>ΥΙ΄΄­kΦM‡§ν%š*Ζ} Σ/y²h}]’\Μ α}nΊlŸΑ»˜αG$Οργδό²dς–Ζy5Χί€gΡ‘ ϊί7-Žη‹Q3‰”:σ/ίώq'3όξζ†άύκ·ͺsͺοφέŸόγω½ώλ;γΏΕσl6 8³ώΚjyά‹έΧδ…ύŸkΒϞΫ’±λ_ŠB>§Ί ξΧ7:ψαΆόΓι K;tš+Ž/;,0fΟa:^–0=|ΔK"κΞEΞkέ»Ά#ρ!,'ΐ9-Όx˜<υe1\va‹λέώΦ―-”;D₯ΪχXJ9s£ΆΚOTΆ=ώ)₯/°:}el·η»~<+«oσΕ—žŸΟφτοκωΞτ5όj[τn}Αςd₯¦Σζ»Kb,;οpχΊpΙ“±’%΅f΄\Ω&¬ΏξΠΥ}‡ͺγ{ΎβΠΕ……^YϋχlI K+\RβηŠJ>'kφ\Ršη§ΚŸ*~sA›ŸͺH|QyškͺМ¨7sΎ¬Μ`•/)ΦrEM–γΫ5ΪΝ%S΄αEρjΛΙgθ[x6zώL?φχ!yώŸώ_šέϋΏΏ±ώ'³ίΝζΉμ>}x|šώ€ψ\ώ·<Φ Ώη½½ώ·VΡ"Ύ=<Άω=y"벨;]₯κέHΫ»Bα#*?RΊ¦ζΒ©°wύΛαξŸuIσ>ω½©³+ΑΗλZ±ΗΧ–΄~­κvφΦ©Q_rΓ3JuŸVx™bxΎΆmί]{΅©§σ“vRοA¦ƒΣλςΎρΞ‹HθΈA7rxά³PgποΕ?wϋEς§Pΰ+πŸaκυώŸtω1ή)π“N€sύί„6Gψίήϋ?Ό‡ύί¬ίΡΧm΅xN«ωΣjγ!8ξκΦϊ –₯ŒΏ-·9ΐ֌'΅š7re}₯οw²Θp>‹|Qη«rΪxΥuΝ5U‡ΘΈ3^>•ΤέJ~kΆ—]Υ•ξτ=§“ϊΓύl—ΈW ©ŸιΉΦSάgΐrηgξύΪΪζd>:sλ+K{wφH»a§΄χK¬¦τΆς™ϋŸ-|±œΞW=7}ž₯iΩ;—γξ·=B<8Φ1’ν©m½)Wη䒞τžΩRiŸSdηάKΨΣΞΑ­’°s¬­B»s`υt|hόyΎ\ξΣδϊΜοG΄‰Ψ9φTΐxΚήeΰ(σfςi1D€\Lή:Πmιƒ ΆG΅sxΫ“ΰθΠΡ»·JΙώŠ/ΜZ·9x…U™zΡ½ ι›6άcΠο^RξΞξ:œ8wΘRΪK:Π½°Δ,οWY~ O»G7{xσ΅›1νžέr€.Š»_§a–Κξ“_XΦΞχργγ’λΨ!'οπIξžΣ^Ϊ»2Ν!ŸjΓΓ6g4σ«eΧ±-9uίλŠωrM.σ„‹vG΅ƒ¬wŽ–ζeΐS:ŽA_'™hόyΊšŒŸΒ²œΌnӏtηšΉwd³4¦­YW@Η#a>έ;Eœfς>O¦»Oάe3νΌ†½ΪŒΙγx>›’:Ώsl–'ϋ„ή»Ϊ§°50Ω§°Η²ψ‚Χ}€Ε¦α>—sη»ι¨ϋ}hc9Ω₯³Ω$}Ω½MƒuΦ{εΟMœ“˜ψr°°€ίw‡IS8œ•εrόB―γ:έφ’mΐ%Τύό<έ[Ν%Ας ΏX]‡pιΫJΛyš”½5£;Ό¦=‚7ϋyœž{„rpΊξ=ύ9ΟχΎς¦AqFŒq¦'Oώn…ρ./ΈdΠμ_Ήεψ{A ‡zη«»sξ?Ψφ|έεΗΎύ“gH³ηŠΎ7ΨΉš$~ΨΫ5«E Λη=ςZMžv§τy6ωΣσ·₯Vvςu!oΐηεx:YΟνAορ‘CQxpv»H§Ϋ˜ž½’ϋFtΫ“ΤζwυωΟ^oΈέ zεΡ%[^ΆLΌˆ½qΚ]'_°TwΣή³[1}*$Ήχό?wžόΊ¨Η'GO#»`άHΈέγ%>οlΣ^#όΑΙNδΫ|xβˆ`Ά=ÎΏ@ε³™§Ν€_ΗϋςΏχ,ΨοτΉ!Wκά|ζΪnŠάΫ;ǟ€Χψ34=ώΡ†½tϋ»ο„Ξž»ΰΔΞ>ΎΆk{v_Υ„ϊ^q)U(hΟ‡ΏZbRβόϋΡa"«cŽw₯κΎγKυμϋ5ŽNΏΞή Λ/GδΣ οβμžή>ϋ±Τ©γU;5žσλΧ$T:―ΗNްρΏt>A&±Ϊtv'"iNJsTακπθ.QχΆCθ;Ϋ99=‘Q]§Ϊ:/t¦=Ψfέ·^£ρ‹ήΆ6Σ“Š ΩΌϋƒchΌ1Κμ^Πια>Ό¨ ΰάΦLλΌΡ“ΰψA€»ξθά ”Ϊ=υΉ`†hKD8}φw»‘–;—‚V •ΚσξοχrαύεΏός?ώω‘Œ„Œζu΄λ7Ε2ύΝ·‡Iz₯0ÁQœ―Fy.±j|t€©4_vω·£°(£f-—xΐκ!¬š#€OΈΆδΡjN7ϋ‡ϊο ΝΞ– Γ_›ϋm―}†Nτ₯LΠ₯‹ς§gλu8=Juz”Σƒn΄M=τ‘©VΡδΒ$g#/ŒΗ,³wΥe}p5ΕθΈ..•1ΌšR,QΕͺ½ RΧ&«λε±δ«£wS$ˆΛ…ΐ’[kͺVŠλ˜˜‘ΥR‘;Νͺ¬N²¨t’:Υδ˜ΦΖ[Y-λ^βGτ²X„£f먋t‘mg,ΚλRŒρŠΛXcρX hWŽU•‰$‹Ι.Ήμ½ΆΎz[£—Ψ~Rs}Yu3ΥΟcθ‘mα}β,iςτΠX-πριyRί|Ÿ?θγΦΠ&Kœšρητψα°8€xR’^²š•³5„ΰE,TόMΙηΜ΅0«]εB…ˆ<nSa–ζ-ΥΞIi¨φΧ_Ϊe=œ”Uϋχ3ΈζpΝ "M|<½›λoN#ϋTJ°€ΟN#KWceΎdΈuατP°o³¬^bΓΤd‚ͺάFοzΆΒͺυ―Β 6΄MϋS*Σiσm=ͺOΝ«ŒhΕ©™˜S2…”}9šž«˜ͺ%VP‡²9$ΗρAε,ˆC‚HΔΈ],XK̍{Ν•/άVγŠξœ‘Ης˜'†Έ©mz 7Ψΐγ+EωͺIt–!€ €C(ΑrΙ’2Yr₯ §ƒpLFΕ –r‰ΔΞρ΄SqΤΆ/ϋυ£ƒΛί¬±Οc΄%±T!`pσ€,lΜͺ²Hΐχ…Η‰k"‹E•"=H>‹Ÿ叇ω·#,έΠ@ͺζ\m%$θ°r՚9Ζ ]c J!%/U‹%Œψ#ι$ ŽΊΜ9D\Ÿ~’Xƒƒ“!t*Ό½`’9^2j€ ΉI 3ΖeΦΡΫX b8/%²r§ΐΉ!ΉΌ/ τRλοΔς,βΧ,~­ΠΠC4ήE£ƒ7<ψl!t€%"θL [0p€=Ξ@!Η–<2'"h30&+Ψ‰ˆ} DcQκ‡ΓTD34aΧβzEΪT­Άΰ¨©θœD!92›RHށςsΨAΜ°œ¨N½ΧƒτB‚y|hœ—Ή³R₯Bΐ;γ™Τ.‚½»,ΐυrεSm’sΘΞ.€δΩp2±xίMcσΌ˜?’―ΞαιΑQ¬ΐžΕ:ΞEœ@KV&"°kΙLYeBΖjξ±X"8 ,pk\ΌnyμΰΫCQ± P|° $Θ§‚ώMΡV@?v ¬Ψζ…Ž* ΐ―ΐ­ \A)΄}ᅵρOΉ,n|6E¨ ΰX<”V½rIμ m¦eQ "G© ϊaΟW—ͺpG[“μ}eY¬>₯Η|,BΧαχ’vΨ' Κ4}U5;§T €Μj)j‘\ς(%”ŸP°»cΔ&—ήtξ²Ω5/Ο©€Κγ:DŒ6%SHΣ"Ώ|―cmφŽ­ΘΊ`ηc2ΟW'v];kΟη@΅β7^>J• σΉJI™s>Šh9ƒœJtx`ΜC–U Ύ.bͺΚ"ί»φŸV«Ε$>―ŽΖΑη!Δ²I†j–—s€ Ξ!Sε*£Η;[«“qr©‚L|Κό”A‘7=`·i»Φj:?f§–Œ»φΝŒΤ 0O6 |žkPˆ Pm‘’SΑͺΚLαEk”˜‘ψΖ±Ž v‘Ό[πyAZc(ΊΟν ΙλΌjβΛl­nQ-‘ŸœΞΔvήθŠ+ΡY ¨•lTŠAƒεPόŒ_Kq3ΓšΑj­—ŠΕ†…%V Ίw; ψi•ί "§"ι‡{S3¬iζPQ$‹J™…sΣφy:aΪ={βφ/―)ΐGjΐiΡNi φ™•#Jΰ ψO‚]jMΌBρUβ΄1 κΧ‰ΩΫl‰_9’‰—CMΰζΛ#˜Εχζ{fΩ†GuΜ-πρ§ττΌ<šθ“S{μΟ?ΚΑw§ΗΤUW!n€Δ Ož¨+Ψ0¦ (€(1]DϊœΖŽΦ₯@'Έ|wž&Ύι$Άφr*6`RΥN\€’Y³’V4ϊ΄ ­ΖηωtΊωΌK»$ΗΎ”ER~±&ΩL?­θ9ΛΑ™χή@žY)b.*xο\LΠJ„8t¬ΊΚ$΄ ϊs²Φe€JΙ’!λbηqΒ“γl‰ψΦ\OYŸ£ΣΐeBg|¬F0UΘτ ­rˆ;Κρ6Κ2Rw*˞“Κ Ε@›2ΐ@›ε‘pƒ5 Z(ցAQΓΰr‰#ZΤv^XΝ xϋωBJ6<”pΕQ'XԚϋμq›#Λπ AxΌαφ·T[°vό0ŸΉzΏP\κώΤϊΑ§Š%3ΖΥe« Σ -Έ΄ŠΗ †ΦL1ς‰8θ4±†8Y9+~bjwΠί―'DΒ‘Όλ‘ σxωΊ!½f½Ά!ξΛWΌΜηm˜μ‹έšHOˆ)πΧI“LφoΰΔΝ£ ³ΩžΪΔ’‚‚¦!ω.ΕVb ?—Ωxύ–Πx“q~ G 6Έπ«Ζ老΅8τImΛkΙ’ΒTΚ €6!› •σή&Α«ΨΦΠ‡ +9©|‚˜Ϊν-,#ΣΨ©Ε£ιλ˜ΛU3<[ΎLΚ™ lΰa΅š‘ΥW P}ͺ„m²- μK @J†X² 3gƒ„VN.-˜•pœ³ΘN*aν\–jΤC―½R’Σr›\ ^Lη0"r f}ΡR—-δ¬NE₯€œζ6)Ι#‘ΐtύN;μfύQΘσΩόyΩ.»ΉΈ’κΑ+ Υ…Y#k°΄₯k6§T3Τ7-ΙUNΖ{.”Ν=ˆVΫΤ…Ϋ£ξεdφ₯›άwxO/ƒyν€™α'AέΰF¨κ±B›UΊF— ΙI΅(Πn½N©π(€ŽΙpk<σ2aΦL©ψό˜΄&“ϋζΤ•@-L _œpdš“¦Ιύ‹RΖΔ’gEgQ‹!ΏΨ*3/‹ΰ݌βPg;U'‡8nPΝ= Μh` ΅Ψ\m)Š)97,%2r(cPK΄x™ιsr–Εΐ’+9ˆΠΗ W«‡β―ιž40–ŠΗΒ„y¦O™¬ο^οιœe•Ά`ΡΌH‘*,_œBeJιvA?”Εγd5q²3/’ν±;΄Φ••ΟžjJE8ΦI°Z9†tΚΞκ5S˜Θ/™U Εzk‘ΫΔS.ύ–\‡φ―@­ΰ™ΙkX$>ϊΜ†b0iœΛ#Ζ3=a@Œα(²mp§`IœYL/Ef\QΊ˜LΣt­ƒ”―υΪΧ@ΏΚ9Gαš±žψΊΪ°A.γ6γcνόυυ¨†vΗߏΨΨΰήx°JL Ά„΄ΜX°΅ΘΑpc€ξ€JΜ‡„ύ+Y2άΚxπkY Ηύo―]Wkτa}qL(°R0’Κ ½κ‚ΥΥΙB%Α–ΘΩΦ›’q`D"x†Ώή‚ESx(Nžx{£nΣΐŸM‚2$8€ΐ%Ι£IΨͺ)x –£³•δΠΚ€θƒˆΠ΄VΰΈΰC²5©?-‰…Z›Œΐ?\1T><ΟeέΚƒ% εˆA;Α­¨Z`›Y |£!φ•%5Ρ¨Θ±jšSd€€1œλUγƒ―₯T„π«LXη ΰ’ΐo΄MЇ–g2€Α—dŽ bGrά+k½†ωπvTΟφzH>šΐƒp5™ͺmΝ)ηh5…vdΓ₯2ΖB9,…°ΤΰΗ1A†μξΧ/GρΓΓec%y΄…Λ΅‰ϋR.;hΞΩ ,₯ΉΰΑloŠT>ηA ζ Ά}v»Θš:έ'Θͺ©šτ9δΟeΥWήΆ‹`›ŸνeCC™}έΥTFλ.‘Ά¦γέ»†ό&#©‰½kEχ^oΚΝ‘Β Νχ—rc»__Jν]Χ hŽν˜¬ž^@;j„΄gv‹~4GφŠk4GΆfΊΜ›ο/IΙψΊZ<7aš|5^tΏd*1ύOσΙڏOΉ’p~1―5fΎΛΉ©;vνB―ιγΧή•?^ρέΦ°G^κ'Ύί¦έΏzΒ\<Η+¨mΩ~\ΣύΡjΌΜώΙΩZΧyjΒ .Ÿ2ϋ κύόΉ,Fmg΅_tυ}σ·ΡΞΫΚDGcZMf?ΖmφαΉ—Ϋm0tρ»>Ύwι;ε‹_΅).&ψ§΅Q΄o€Κ$,GΟ‘ύΗ™[k0Ύ z¦“JΠλdc„U²Ξšs§Š 5Ga•HL8¦<”`q f9Γz[›ψ‘XρƒC₯e‚ΤƒBΕ" 9 £ΜΥ(V$7ά‘‘Ό—HωZ1Ε²5Ε»Β &₯ν2‰“UΆU \•οOλh{zJcm)ό ŠΎΏΈJiΈύ*|)ŸΎ=L¦εŒš±Ι‘Ϊ(d/ύΣSΙUΫW½5MΕR₯ːΤD¬” σ*@ΕΘR¦T±Ι ’5θ΄ζ•ΈΛΙΙ(Š»^}|²:ŽδώγΠ‘χΞƒΒ4o άΔϋœ‹ X$Dθβ<ͺRΑΈ²©ς(. >E%E·Ήbοh-δI#λτΪΝ΅ ­`ώφγΟ'οxπbψx^†2Œt–Ÿs¨Υk‹Β:bψ™œ@Ν&‚όUdƌӑI†zρΰΝGqΕΰ›’GϊΫΠ ‚³ )\θRu%Uζ°ήUHΫψ« §‚xP ڍ­2ΛH.l(Π δξ菗κδΩlEaž|τΪ‘Χ€(½Τo86ŠmNΐrg-„€ΘZx,±^mπF…œ-‘½pΙ,ΈbΖΤ¬"Ω± 9α Φmγί„φξZU¨Ϊ*ΜVŸHB~*:7όΆ>Ε‘.ΒO­Π) °Φ{΅Βq‘’PA¨*hØ ε*kͺΟP YΈu‚:Υ?:λώl華›ŒεM†Η&ηΑ2©ŠΣQp Ό^oKE)<‡"ls)A…J&ΚΣ‚ΚVLo1ςΘZkχχΦ*―sstΔAR'D²δήN»(΄“ψAAϊθ₯©ΜgY_7 iΧ|KΆ7Ξϊ¦η2¦Σ;‰mυΔZ;bΧ‡Ά²$–ΩZΑΐHCΑ…“<γŒ‰ ‡Κ\zV˜dLIcDB%:ΧξՎΰ μ‰ji4ξςVe*oͺ‚Τ£΄Yq*mφΔ$ δ£8˜+kΝςΐ€&^’ΤVπh§Έ3EQYηYUQ©ΈήuΡ$‰΅‘αΊτα½»G) νpΦη’ή=―JωJ°hYr%Λ~ŽΕλκ<‰ny\ΆΡ9NyμΥΚͺ{u•-UΌb˜Γη Ί „™$EDk–(τ&Γ“ρΡ¦£OPa8γ¦Ρ™μ%·\C&ϋ$RθKiίΙέ:%?ιΒ-ΓjδΒ«UΜbΟr)ΈΔ Ν9U)4@I€Κ.O†Ι”E•RUHς6Δ{ΟΡ}]xwίͺ/<ΓǁBα©dΑd TYS’%©}„6abͺ’E‹νO>W(εšCΒ†k3piξυxPφΛ‘κΑM,*@€€€1CΊ\IΚD# ¨Z ˜;Ο¨&‘ZqhW  )Θ|QɐψŽFσ― °„‹Œ M…Θ‡2}:bΤ|πs*άσXe ΚƒΒΙmπ2*€aJΣ ϋ”²΄­L†μπ‘μuν1\?~mΜhζ€Τ~~| Σύyyƒτ#%θΑ‰%)A/fŽYΐ'*”W*›”Ο3U9ͺ”c/o"&Ό€†lγ„m{ϋ”X°L*0œKZUν\΅6(™-„…ZΑK§-ΐ‡†Β‘=oά=19~j­,9‘C/D‘x»N œ‡€P1eμ3JτTJΧ „κΉσ>‚ίb Α A9ΐDΆ'FΠ‚’C#ΡΠα6Π%ρr.2¬&’ΩGιJπEΟB€Ά•*‡2!™7P.H€X‘OQςφ)½‚ΥŠ—£τρ Χ†q 8u€Ό¬n"±ΛMΤΊ ŒΪ γι³ιdώ΅1EαςκΑΓ,XQ©$γ*£-^ξ…²NZ―g5Pν &5p)P‹‘τ0*•dΐπeAΊ‹WιqAPΡX*JZj•S¦Μp[3cή&ΕA,ΤS•¨8’sV ιTC“3S}Ή©ιIh°δ£ΜΘα.ΐΎ†™|,ΊX ] ρɁ±b†‘μnRΝΙλ$pBΜ²^θΓγd6?ZΑcκ χ#:ρ!`‹ޘvΎͺ†ι`αΑ―J±^bΌŠ’`ΌΰαUά¦Π똚§QΛ¦› }& ΄* Έ$Ώ¦¬Ε ΉŸ³MΪp0`tiΘζ]\ΛPLΪ\˜(’Υ†ΏrˆŸ6-B£ £γφ”— r9–D¦ϊƒŽGˆ±x+58¦ΤyUJŒ²†gο"‡<ν\“`cΨ_²_waίz„›#㦀is‚­M#;.Nϊτ‰ά¦§ζnΉ:BΖƒGE―$ώtΪΣΰ”AVΝG(q޲τ†E”C2@‰AδAͺ”΅ί9a·ηΣζΝ7%ϊ†™Ž6·ά λ#³Π0ZαU–€ΌΠΚ V ’σΑABjU*Δbvš19—Ά'[ςίζ±ν7vbl›νΦa(9jfƒ5Φ -²Φ”ΜrvxwD«K&Kζ|υBθF,’d ;āE»Ύͺ'b·Zγή1Η>χΠiΰAΐEEpPΦdIJΰIT 0‚cUPͺ-Z* Ό©Z%*Pf°η™}αΎ― μ!‘3€ΊτΦpMω‘ΜpΖ„\°R΄ā΅ wμ'`^NΕ–rP¬7΄iSΥϊΈ²Χΰu6 6Œσ9QΑI#AeŠτaͺ‘Η+Ό¬Ά8I5cΈπœA³JDJ3‘DρΣεπΦ₯sOΠαAοƒ)qΓgύ7Jn“‚"Ξ±X&+*?¨` a€ ϋ/GξΈ°Ebώo<0Cqͺ―ΦΩΆήveζe;ΌK'ε°Wιan·kSml΄0φk[½§¬;FSt–G­y}η΅Ϋ\΄#ΞλTœΙjρœVσ§Υ©‘PžΠ±’δδƒ6`€\”lΌ‘* l28V!tq[()pVLΉjœLdu…‹hΐU ‚d ²G‘ή±Kλ~Όΐ­½Ά+ιmρA―•Β‹,K^SMYkŒΠ…  π~°ΈJΕΙM&‹£ΞFΚmλΗ’Œ+ΈvnΫΖή:8 |Κ •[ζZS28§BTΑ@±7²T²€€ˆΡ”Β’ ϊ†ΓYπ8ΣΫχρ0Ϊ²Ά?\4τ#VNhŠ-A5ψxPTŸIΑΑŒ©RWοTI —`]KdPi΄€β˜Ε‰η8ή—W–žž>m …ΌΘ‡’žbͺΗVΒ΄1 ι±JxρD¨dj’Uρ\:‘D&θ₯X˞„υ#Νk-ŸϊΦnG»υΞ3&yόT …°Z¬•ύŠ>CΐZ mΑDΨv‰Κ*kYEΝΠ¨laΙΛK=…Ώϋ‡7ΙγH½ύG7τjΊP"TθȁɜLN‚ ψŒTx%5X‡ Ε›’ϊ8pɍ¦ŒAP¨0²―,μKKͺX±ΟŽŒ…fxυΧckAϊ'‘—sΰQdu­ R1ύ8*`c.£"lΆ8DE)r]nΗΡφ­_½ιΞ άό\"Χƒx+6ω„ΕυΥb­2ΐŊ³$`#>δδ²Λ¬ΖAŽ\:p«.ψΊUΩνWβΠKΘΓ\ŸδΦ@’X&m5!Η¨r°—”œW“’ƒ< -jο@2D~ϋπh9_ cΘcr&œΎbω¨ύ\η5‡$ΆΣ#DlςΜχ³|0‰a:―ν›vTmΕΝ6.|AYZΣςhuΦb^q”χυΚ½)ΗiXyΕ?Κψ•Y ώδ Κω˜…’ΐμ8BΠ$ΏLuΊŒJΠπ5δ€9CΚ/kΈ¦εkxβŠνv\sΈ[ŽϊΌœYΓ/Μ%«)Ϊ‘ΝΠnΏ-U!–5N}3£« 'Κ@Ε•‘mh©²T+P;¨Ξ‰OΌX& [©…‰=³ˆ―ΩI?3C7 sEΎg° )ΐ!ς$¦Θ-Ν)žIIf4}AU]ƒf‰Ώh]OnΜΟΡιΕ3ΤήτφTd¬φŒ‹l2χI₯P΅Ά‘τbΈ,>+N Vε ¬=—C"o°Χw~j@·ΣAGCHœ…°Ž%γƒVΚPηΐ…(ra ΎΌ <)0₯VWKα&ΎΚΕ}°ή·_6 cΘήTΈ*\W-uI0&JbQ6 άΥΰhW#T—"tΐL–\ΓkIξηFyƒ΅΄ΩD\,•©κΤYo¬F™j₯„Ξ3σŠκ`νΧ™²κBCJzϊΉQΦΕΌi‡wϋΥ€€Δ-u:ΣΨa,¨„u/²¨i[8₯ν`€+ bhT”ͺ/dᨩν?ŽW`šΧNΫ-ΆΊδΡ:₯ζ䞨@2²ΘΔ€"· ηΰi&{4hΐr£aiΣg\κ}ΊxΪ¬ϊ‰i»<Με†ί~‚΅ΙΉ,Α ΐ€ΌP©0λ#g–¦^3*•R‘- γei© šΧOΪ«§„Κ$ά~BJ&.sEdšh4™ vα]q&Λ·Π7D–)ΛjΚ;WΩηžΠ‰“r Ζο£έ³T   ΩmCŠΊ‰ς$Ά=ͺC± Q²ξτώ^wΆ>27žQΤ’Š%šΰ©vŽœylοP0χΰΒ)ΕK.j ΄ξj„υZBυΎΔπΥ;HšΰcνπΕ!RC£l%9R,pj©JBΏ¬Tγ"Υ?Ά,**Ÿ–@&ˆ`8d2`vΫΤ·–&llΩ΄&«υΘΖOΣωϊάςλ š:Θk8πWΟηm―Ί64w\m*/ωμ σ0ζ-ΕωN±…O;EDφbβΪκ«ςH±v›Ύ&Σ/y²Έ`ΫqF ^M— QKΘ%Ɓ‹!c|ͺΑQ€‘t”qš‘B›X!oB΄Δf8w‘Ša‰}O ώΝκνŒ?M·›ͺΤ]AnoF5 Kᲁ ‚1KaΘER›i³£S2₯JΓpPΆU%¨ΘB°Ψ­ϊΒΈ žjΫg§!—?=—›GyκIup΄@}0”q―©h<Ε §J}Ιιj₯hh}‰,χ5Y«<θΑ_; εiž~nbΪ[άΊΆœΠNU#}‰^c{Έd=4o#Ή&5Ψ–Sƒ')$"μΝ‚j LMό⨱ήZμYYσZ—eS?jώT>?‡EΎdΖΪRS‡qvƒ§!Κd“•Ad^|δμ€Nΰ%•t‰FIeΐϊ©‘$']\Θ βQ sέwQΥ݌μύ©zΥlΈαΩ*)δz ž+αJ­h]'R{€JΉΔ Et©ZYΒ$ xUωλfc§Όθe“ρ’F—€,œš*yƒΚd1βΒD―L:ZΊ†AΧ€)’*xΉ‘²‡ N…%ΆΘVτTFκ™ͺMε΄a¦*‡Ε΄£„Ν ’ή΅M,—,(Ο8S šOΤβ4`γΣδΜ‘θR-μ8ʏΠAzl΅s“Ιί­Η­ίώΣVˆolΊ\υ§.ω=όΠESν8͈L)€Π.Ω$Y΅Ί@‘©Iη‚ό£Φδ œί{Ή_Ί tΦ1ΑαΥ§΄Ιƒ8Q€½5̝”!ϋ3yσ9¬³ς^Y.Y-ΤΣλOQk&fε±™(BjŠώ₯ 5Χδ9¨D§ty\(?)Ήx\¨ναΦ7ˆΞ”₯ιeRŠκz’ŠL–Ί›«°bSŠŽA1σ’aœ(X)λ>εloγΞeͺ²ΰ)€lM€ž ₯όΑc .&SSΐœhήCLh€Ύ W}ΝΐΆ>rΫ³Œ»Λρλ/ckR’³0½pYu85~π¦QΥQξž‡ζ0!’46ξ,… ^ηΌφ΄²!Rš„Σ%(₯ζ°PοŽ_Ωρ̜¦λΖ:ώιρ˜λy?|ΡDΕSdΕάί’©°PΫ-@c€J'ςΎŠ4TΧ0[ ƒ2cBŠΰΩ₯![«εIνΘ/ƒ ΄nL)ς¦ D‘T²ŠJˆ>–TuΔ$@9ƒšž+P2«ι VΰΜύ/_˜†•y9lΩS‘RΔ>υΠ(…^“&m20M΅p4[p_@|§“Š ;)ξ]ο>ΗΥΊασ %δ«KΞR[hͺMΛe©#ΆVŒ£―Nγ…C•[/ΐBo©Χ£ςZε|•‘θWŒτύO˜ ˜9*έˆm€¨d3”Β΄§π**³ΐ!$-ŽΊ•PŠ'#ω9„y²(€JOϊo―Α7©Έ.V‘Ϋ² +kZtFa« Ϊ¨BMŽt8μ@Έμ&BE£¨χΎZ#ΐrxr~ˆγYωΎΊωφ“ͺ#EšύAMy`κ4α"jRιœͺM=U,+TΤH:50΄±§Φ‘iz3πvL§FΏμH±‘ΓΧZ’m3Kƒq[­\Nԍ“š¬jꨣ$₯hΔhŠ‘:ΓDζΨՍ!Ψ:v:]zQςόϋ§ηεΖ«|YZτώέ:₯C•˜‡βπΔDζΥ’^„E₯f€›S©&Θ2Ψ` 9/Œ:φt ύιXB_˜LΓβζ…3k’˜Ωͺ"™”(QΦΨLΐ ™…κ,• ά0μy0Όβ q‘Ž₯Ιaϋr¬¨an’r{+¦ΚRΖβ••TΡίκͺP𰔁ʔ†Œ’$Γ‘6Ν‘γ•ͺ!Pc5lίπ§ηIϊ²ξΚΖOΧΐΙsj³ςψH-V7―ΌͺG’ Τκ£ζΨR~ F§"ΤώΌˆ ˆ‚<ΉŠΒ-t Iμ[»ω·/Œ·ΟΦφ”ΧqιΙݘ³.NšJ ™sTvC Τ*€sΤJΚK€<@έ;„³qšΞg!₯ψέ VrρLx›Ω ŒH/—5p@Tͺ²¨‘|¨H…Ή±Νjv ’Ε%ΐOl³ξZΙ»#OŸΪϊ³›£§¬JG?ΌυψλŠ"i±·¬¦ϊ25 Ε"•i―ZYκ͚*XmτΠ¦eI†'Λ½$‡π ΚΖv‚n]f3Β„šRΆz3 pέΨϊ€&tά•ΐ”6Ί€EΝ c›DΦ„Μ<”ΠΪOΉ‡α’όMS¦žΙP”‚ήΗ[Α]Ž"3bTցΣkp—&θΓƒ—Π‘’x«ΚΞχ₯Ωη ‡‘GΝ.Ϋ%ϊυ§V·Xέ|κTS–KVΑO s6₯ ΄¦TACνιk΄ΈB%I†D#΄6Ω’ˆzw‰ΑΉ%‚uΜΛcx:ΡIuJ4ω¬θ}ψɘ ΙΑ• ‘ͺΚIr‡B݈“‰ρŠΘJ&φ~€ΐZͺ πΨShxςyΦ$&Ÿ_‡7α&m}­1¨j‘BWΙQ³BŠέχκΆd2JHŒΧA–bM³…άβYϋ”€6z"|"£VO£εέ¬^WI¦—pΛ‡ Fm€ΧEŽ…‚aUΣΎ΄P±.«JeEB‹5qm uξ_©2&α±U$T M"›3C‚W {Zλ5ž R KF+u’I© WhτΛr\{άžϋm >7υE FΗΡΝΛ!ŠΔ!«24"§!ΰ•Τι°Ί4΅Q+,φ―2^ώ’%ήΉξ0v`π JS‘C²ίk£š7RιΜΐΏ=ΠiƒΦ ώε''x‘t°|¨ΎPμΥ)wΦΟmκMΚ›—{TJCŽ‘Ί &^ΑΏΘΛƒύ,Ž†κ¨’>d5'ί5Η0ψIΆœΣiN§%< LσYN|‚„β‡–ϋ”Cκx(DΟ‘μd ρήΛ ͺ‡αΤxl˜ήθz9q‘ϋΐΛ",K·Ψν¨ Ÿ<Μh¬-ή’69˜&Ό M$PSKΙ <«Κ; <^•UΛbΦ>kΩ«k‘Υρƒ ,ŠH¬’FŸBρΘΔG%EβΖ`Ό ’x[­ f€ΥF_-Δ©|J…ς8Ί½ϊ8/Βηω¬Nμτ»Μ2{x‹[WzηŠͺΥ€oCgΧ…Φ4BRa3cVΖΜ΄lΊ3a£CΚ‘λŸ1όŒ™ž‚•)]Pρ«|₯ΪtSŒ ΜŽ ΟκαˆVKN,,σŒ ΚTͺ€\ΐ)nω>YΫNLGD;x ͺ’zVΠd6X2YΉΦ^(£2[XV!3DNδΠ£™s%}g―WŒΉCΨQοžεͺαKw΄dήcR 9HM•)ΤΥ—μΟΕArΘhZ6zη Pδ’Α’T.ΤΘ³”ΎbΨ5L©¨f7}²…Ε ”δΆΙMMάC%p%υΰΝVAƒυ ά²$mκPΕ26ώ>\ΨOο@ΦMΐφeΨMjdT`ymΪRΡΙg%…/Δ8BmӚ‘*n%Ynœ4‚ZT‘>²=hf–j…%π&U]ž™•ˆE(«›ΛiC”@ʍ‰\”SEe&1p¨ΚUΰ¨RTYe *·’b] S½ΒrίΕ±7xΏŽ XDI™Z΅x“)‰›œP‘[H9CΥm΅ζ IΩ‹:rA=Ά•&€ ]𲻩"qXϋΟΫr²“Ωδϟζί'§” Š€Ύ΅νKE–½?)f<Άmτΐ$J¦2*ŒŠ†P~¨ΰ&Q  ΡΦ“ϊϊξQqΌΙηΩxυγ©,o^FΆšJJΡ…œ˜)‹¬σXδœ[ΙF M^§h”+ψŸέb³2ό²§xγή6•½ϊΧͺλκ›wΊ‚*C5B  !c¨NηlM˜ˆA¬«χ,˜¦G™σΡ,4°fR¬ΖPUμ_Ό/`μ₯…Οuο€NΖί?OŸžΣ&6ψ¨[Ϋπ.+])οΕΩJMŽ£ žAζB;-˜TΩSΠΚ2/Lso³ςΤDΓjhRέ€ρVxΖZκΌμl΅ vήΪ{ϊ&`γˆΛ[ΙΈ7ŠfyœΛΧnšl~Ό|~zš/Zφ²>ςzhλ…izκ.ΒtΝvf˜FHσe—ο•ΩΈίŽΧyO:7NΒΣdσq²=Έxžm›|Ό|mCΩkHΫΛU~ω8_`‚™―¦KΛεsφϋY6Α’λΦ3M§•—©Ϋ[‰_;ηψ’zZbXlJΟΎ¬qΘψq]zζ²i₯>2λ3νG"œ7Κχ’ž7/ŠοΤuk’Κ‘ΏsΏΥLωήζ LV“5EυŸ9ZB…Œτ“ΩΕ=jΪy)4—Mι™Εό+€Χb;SƒRqοΡ!{x,›Θ‰ƒΙy!ΝΩΣ|Ή}ωeοΌδ³γoΦθΠS3ψ}‚Ί_Vγΐα†Σ΄ΗH{^†υ"„M,έUSΆ7A³ ΰ_-Οnζ=‹7HΫ΄Ž§ρzΞΝ\gsDn¬μα†J)‚Οs&’ΧΑŠδ,π*ΠyΥΩRΑσ«`F²B΅'€Š”i'9Ώζ]8ί§νΕϋ€q9I΅ŠΑ§]A΄_t0εG|Άo*ωyCoGI±q­r7†Θ―žŸ¦₯S‚μΆm?₯a*¬‚—zμ”1O‹²ZύΨQyFl[Ρ­gR;«Ώg WΠ|ψ²Cθl³g_\²Ϊ»KπZiΦwΓuΛλŸπǞΉσ+™ίэΖ;uΡv’ήšν½»Χn1ˆq‡ΛύΘβV‡)8ύΟλ;··"α*zj›}αζ§Άέε‚χ<τΨΫC»‡hϋ]3»›)ys4rϊ Ϋ{]ώR/E»!ι₯x³ύΞbΘKΐ±³7ϚL`uu6"DΙj¨ΤΆWeΚ·0Uq©‚Φ,P2 Εͺk."wΩHa…Δ?ίΧ†¨>§‡ε$ŒΣΣβΈ,Ιΰv«@ΙZ6ka¨)Γ:%E•™\Υ*‚p5ηMqΔΚ„7”=’¨‘”M&ΛΞ βΟ“Eκ¨ρςέΝΦδΠ{HeyTφ/S6E±΄OΌΦΒ-ωΗ5ζΪQ©•}RΈ,QςvΞXwΥϋ7ΞӁÛȝAuυL ‚2©xO<ΑrKI€,ι¨β¬.TT™ζU'«M!jY]<1³-’Όλοέ‚œΝ=‹δζΰώlΎ.'³/ϋ^γ°ά?@j©]ΉBGΣ:΄ΛK —Ϊπ_£sγΎτTΏ99ΙT ©ςΑ‘(.H κa.+ΑΉNOλα§ηάΰ+Ÿά`δŽ<ΦΒxm«ΙCΨι”₯0‘a?)wU)$ͺ7,;SΕlQˆL>½!^¨εζ;Ce ΣΥAΫθ(΅H$>{~Jρ,e‘Α‘ ₯€ &Ζ©o[‘lKΓΣuKΨGΠMΔ§ττΌ<Ώΐ“ωΆΉˆΐ*5t%Η{LΪΪyμ©οi•ΥμHΑs¬†Q”`’>XΝ¬”φ ΏnμΣ‡2gψΠ㨔γλΗrαY0°!΅.6+]™TeΧ…HΕB,WQRΣ#°x,maΧ¦· :;Ιν֌m[€t»~ž4N+T€S1j΅–Άb—²ΧΩy2θͺvuJΰTšTEloͺG―U.βI«SΔ(ΎXλ½Βf²ΉTL·ƒD―ΦΗxamι‹έCψΉ€ΝяŠo‹αρ΅ \‚u0 hΌBεB1+΅%°#Ȏ⬀/ZRζO¬ |…—œ„—6œ‘­kBZ₯‘ŸΎLΞΏ‘7'jtΙ5„Ÿd‚jg: …Ο2uΜ©f |ŸtΒ±΄I„β(&r©!ώRJ²ί“=~άΑdkxΛI[xϊ?ΠΗρrž–srυ–―“ς_?)bψ δ ˜m$հԐπΆ΅κx‹Σdfg‚ΞZ#£2υΑ†,¬–—ΝΙΏ-·±Ε‡ΣCώωiδ#ޜΪrχOXGά½Ί…φ'¨ο‹4†7IQά Žy³Y60ηΙZΕl²Δ°cœ!rhηΤ-…ηOαOΟeœK|ώάx)ΦAσ鏯§Κς6έΆιcxE”Φ¨>φŽ•†‚U%4`e t λœ΅Τ™8pjt_IC’t>Z‘z4ήΓ|±&ͺ‡žΎ‰Y„ΘΐTx ΤOM¨Ο•S1|±νj4“΅p…ε„*’ žf‚“ΤPKA’ ιkqNRQ2ίΖl˜Ρ‰¬Ξ>β—Ώύπg¬(† λΰ ώgjBQΨΜρBUŽJδTϋΣ“₯VYŠQgPg@OήSϋhπ…\‰γ’ιbhυL.eNM ήDCMD#ε§F|ό;`{,`Νp’Μ +@ΤNA­‘Κ_PAkΧυJƒzaϋ‘Ο‹ιH4 xύs2Η#t:xP"eΤ{)ƒτ6ZŸ€₯²@Π£AζDΠ Τ θίΜνjΕΔ%Ή(ZxŸW’ήύ8σG ξN‡>'Έρ₯ς’‡²g©‘Ι’ZO₯DjI zΑshšdEu" |KΕ ~…ζ€α@4­U‹m€MλͺG`2ζ­Ξ»Όy¦²m€{W/Xΰ%h9ΟLR§Μj™Ξ’7LšZo`@ϊZˆ±ϊzη̎¨?ݍι΄τ!Lλwψ +F„DˆAd#’ ?{ίΆέFŽdϋ~ΎΒ«^O«™ε6Η’¨&)»\_v$/β-IJNVUwŸι©*+EK‰±7±#vi’ΥmΤFδT€ό"ΖL>τβΤ²(€ sCߍn{χ]ώ! σ“γ Η Ξ_Jυ؜$aΰQΌ™z[ΆH]ξŒb€,`«IS)’ŒΎ*M[-’”Ι²Ζ‹ψdc6ε~{ίττβ „UΦU@@$²p« Ψ΅rL>šκ+Ψ³—γ]“|χ*q @Ν Ÿ<…„ΩŒΟΘΥέ»‚1ΕZ€j;(λC‰ €Θ#ξk_<Ά‰U ›&ε1EžΑT ¬S9XmJ:SœΨλσL–όeΠ Z]¬ΐ{š­¨ΜNΟ Τ‡­Ζ`Α1‚€‡ΧM|π7ΥϊLͺkmΧR‘Ρb.l²ψΕ,@½@*«οΝ^c7`.N2~$K s•˜_Όu²ξ:HB r€Ο$MnVŒ½±†β˜^σ~qΠΙ9ψΤGWΰ‘‡Ϋc‘=K6Λ9M(ΰe5 8U&+cλΠ5Ε&JA:‡””ti|ŸϋΣκξ(»(ιa%ς]`’wΡuβ`‹·>² ~«u¦β@% C³ŽŠbtΰ r†9ΐTιΩVΊg/z“#αgΫ φΣZ'αLw»ΉyΠΣwFΡFGΰ_ q5%—=,5Δ[ˆκEHΤκLψΞΙUEl#έ%ΙWםŽ}±ΛΌ ϊ‘-Κ—»k)Τΐ$Αk‡ΥͺU>ι‚ΩD€Ξi[‚eΚ‚9Θ\ΐ,’L¨ZΚMS,#­CŽϊŽvώΊ]ϊύƘ~ίκ(χξΰ•ΑY’‰\55ΙTH)`§φ‚=ΝpMNf[ƒ}bŒJ}ΩΫΞ„£}…Ώn—Κ%c̟Ώ|ι―όqͺΡ9υύA1²±‰ άkwŸeΝ&J/Žb=βΏιAšΚi.χVrUX:ΊάE.Κl΅ ΕΟ±ξρλγ€ΡΡ/Wςη» !―ZΦΚ+wΐΰΎvΔPZ³Œ_T¨:!Œ²…shέ…B Τ‹—SΥ‡‚ΙΟ΅yG⺌εώ·"°Ϋ’s"• XGE„Εώ§²,*>Iႍ.υ&}*s*p*Ί8*8³άΏ|ήΆf\w”Ύ0ή‡2o?OπΤ¨H»"2ΊrZ*ιcΜ-³Ÿ₯ys3%Τ`J– ‘s–kτ”oτ0}/½/ΨAš΄œ(•MίŒR,AΛq?g[Ž‹FtφΩ•Α·βΕ€€cW@gΫ €asα…­ψξΑ³$ 5Cuf销[ΑK^ΐ 0‹%NQ‰ΜfκΗ*·ΞΉQΨ»•P=ΐτΡ§ ή‘'Ρƒ3'yi˜.n;R‘τ:|―ΒτΨ²!ΥHξx€%φΝmqΏΤά!₯?“%_dyωl5X&@oυ(L_7b`,]rμΩEιn”ΑH΅Œ7i8zπσετ€FMΏ¬H/­9°t2€qͺβ=΄ΈI₯@ ‹mIΓrύLΊxιQ`(!"ξρό]j‘%Pχ^ έΖ_Κη/―νΓjwσ0² ’δ΄)|ΫΛώτΫnΈŽ™q:λ―a©‘οΞ?6Ώό“|λφΆBNd/\矡΅›ΎK¦‚Gͺέkr©=°ά_ƒ-•€<”s•LΖΖ†ω‹‰‘{iή"=ƒ­‚Ι‹Φ·E€χδ>νw.ύ-TΜΫΞϋνΌ‹‰OΛyύΖ+3œΠαβjώm“G³šŒ==–} Œ!‡ωΙk5wΠ;Ήί,zl s$=l‹²’΅ζ UD¨ΑΦΘ3 "Κ\ͺκΝƒŸηS+{\ŽL†ŒοΣv ž»΄yKƒ]ρα™DAε‘ςb#Β°oiόια™³kσžΪΦO%‚NΆIΛ° Ξ~’]”`u†9ms •ΑΠΰAmDΰ³^K·—dΰN³ς·‘•knŒ΅΅Η±©Ύ=b£½VάχΖiΚ&Ραπ!p–dP―b½ΡMνG=Η₯πJ9Ϋ¨ƒρ(IϊmlΟ'R›“χF°©Λι–(gφβ}o’A¨•\Κ«Ζ$¦“ΚΖP^;Δl}*’–οψͺVΨφ@ΆΜΪμΰΑ³δσ=ΞώΈrD{Ζ fϊ£θŒXIΎIš˜–Hβ8ŠT­Uά 4€ΙΥrO‚kfM‚q΄k.U£οo…ώ@­\ρ†ΙΧƒ«η@IέJ!«h½pˆ Ϋ’‹χΠ&ƒSΤtl ŠzbKΰ§η„7o&]λ&6zπχο}-Ρ8Κic‹IΉ~βΉx’ΓˆT\9W’±Λψ<έP:χΦ.χK#έ#oWΗ0ȚΉϋ1œΘn{“UŽν¨˜"θΓ†sΟ₯k₯5†cͺ ½6›DΥΉξ€~FΊ,>Χ£\νs»CIΥ?φVΕϊ‹—g>= ©7.ΡpZKDΗΖɏqƒζ"2,Œe‹7₯=Ίn₯Τ<ƒ\—ήΘM«VΑ/lθVGω+΅˜ώ²δ0Φ‘Ζ“η(Ζ ώgJώ©*’—ΤUŒ¨w‘KΥ1ΥT‚4™qƒ nφ΅T0_ ‡Π?WβΌΧ½s\PN-ZU/½r²i.².zε)cγ³Ώƒ]o β·–RR‘ΧRΒ.§RΪeΌ7n›<ώ'9₯ “)G¦Ν~ψe°tΰ$.ΒJ5iΖΣB'©%ξφΖBέ­ω§υU bq[ρωc”§v‰ZΗΜ₯`Tΐ>΅nŒ§Φ£(ΝΌjΡdT(:im/Ω|S³οΡ!ψ‹P­-VwΗ{©RzώΤβ(KΑO”“ά­Μ5*Ei‡—οk…δξPN%CiΎKÊxώξι@ύΒ(ίuNˆότI©ΑuZaD%uΉjρn;1Ρ)ψcŽΈ1&Έ+²X~PIjdΊ‰7Άέ8֌7Νψ1ΜΏŸ₯ι;HS¦ΠzXGο’ΕTv˜KzεqΒKJrΥGε5>[5«θωY³—Οˆέ?ζ‹owŸX•Kt,³™ξHW2pBEš;a©Εˆl½τ pr8κ?Ψ Δ²†cZ/uώάg_ξΞ3ΰI€ qεUVτRN&ŒTαΚ©jπp4Ξd ―‰u‰ΊΦΰPy§vώΖγν 3o°RcΌκξ°ζ: 0šKSϊ|”_kξpνbsΈb’?΅JR„\΄d€ΙA&œ•©ΊL"'ιΞΧ)ΗΝ{Y?6›p4§Šχh§f’Γlvp~―;kΝ D― FΰL-*&k|Ν9pqnX₯±£Λ©»nή•Λm*ώη}ΓΣκ­š&‹XŒWR’ 8Žd@»’=ΙQ(Fξͺ +LRX½I+Η*½Ν?8Ύ98’©+_[3^Ω ]/U“φE 0VΥ’ω&―CQ™Fl7ΐACk’«Aώ_IL_|?Σ!fςj_₯ŸZοΛδ Ξ=7Σ*β{pΓ!]χ‘‘ r!9§‡ž­€lq$qσ²£ίσάOΎ­°S€G,'ΰΛbO.pχEMW[t5Ή‡}ξ`β4ƈ‰iΩ2ξ<»­βKŒE§p£S>θNK}κα¨uΊƒ‚3v‘TώEΟΔυβ|ˆvYي †ψmcθ)5Ξ5ΰ“ͺΫ‘₯‹l]³ηΟΦ֟ŸŽφAΜιιλΫρς:υ~c’·\όυƒ—Χ²|-η¨ϊHΪφώAξώ₯Οpཎb7ΜΜ±jΠ]&C»{ ΰ6FS ΙζδLΔΊ“ž±ΆvΫτ s2›ͺ67΄.μIΔ©ή‹ ϊNν˜w/ώ–4ω}Kn₯JοnP„σ&M…ΐ5J£΅ξ†œ+-μI'VΆΕ·ρ-Κ·š‰0–ΊΥ γψͺ=ΞH#ίΕ^+ΕΤ)μ\8±ΘAΐ₯±ΌRώA vΠ2P3ΦβΫPZšΉrΒ°’^“Η_P§ΩšeΈo<Υξbι™$IpΡ`½d8wΙ¦‹o‘ΐΉαϊ9ŸƒtjΆΕμ;1άc«@ύ½ίΊLNή¨›[}OβΈ#oD Fš~m/ΌΝ?Γ₯S€ν―›ν~εύ­-}‹’ŽΖŠHR“’Ό‡ΖηL)4@%z8€ eμQk±l₯«(Ή”œχ¦|―m7§‘λ[?X撝ο«―Ψy½ξncνžbΨΚ€ΩΖ|U¦*—="I@θp*•TuM@˜ Ў”6ΎΘAό‡m|’Ϋ{bΪ -κβ&-δΚιάΩyΌ»I‡ΎFL τ.ω"50π§NςTJ`’λΆKˆρCΊV4ΈsκnT±ιη>’₯±oβmέιGΜ}|… 0=ν=Ψϋwϊ‹Λ?Ν]τ” ΐ   ²r%VTΉ;³΄1  ΎΪh“€ΊQΥlΨsημŸε.~,/­πΛ’=λ_΅d~x ›Λ»§‚w³q¬aCο› AϘJ₯€‹α?ΐCQΤ ³υΎ,•EοώZώΞ m3 έ«γΔ›ΙΞwΎ›>'%FγDδΌϊΜpœ t½φΤkυZΓ†‘"|Wέ+–δδΌBwΡζΡ2]ί^n…$ϋΥl­ΫσFΡrΦ³š )6X_gΛ!ƒς‹cχŸAπχ°zb“¬+cχ±2Σ†›k²4=’U35<”σ€\‡T„ŸΠ€οNηΫ¬ΎMΦu o«μάφKtV΅Ώ5냳s1‡λΨ«_—dψΖ΅·““£Ι/Gb5A³€Η‚ΙbvzΥ 1 ΪΏ=Fœ(%zΜaN₯kΛ"NΏξ6ͺp½~ϋΡΊεΙk΄^η]8„‹d#Ζα₯|ΨΜΤ…™\ΐUXsζΈlϊ;Q² Ζ“6¨ΥU‰A2rɐ*…*f€ί»k­©]V>¨*Κι|ΩώξΖΐό3ν]!<\ιMσν»$MžQ|½GW9Έ-VY#iJRk†ΏχΉ sDpQ*‘‘¨4ͺ^Eσ΅a­ƒΏϋu½‚ΡQžŠ LΆœ'Ϋ=h ™λΠ¨ƒŒ¨J€ώdΘ ξΫΈ™ς²cε€ž@1LκpΘ—Kš’τ»0lωKσΕΟ?cόΥ9οuέξ½Κi<¦NNAB“–* j ‘€:^·ŽJœ‘³γ¦nΌ;ΫΐxΙΐKί–§ΆpwшΌ”Ίρ6`#cy΄ˆ‘ζŠiή+ΈpΡwΔθGU`#n tώlxΫ•ζϋv9mwώ–ΰ?ρ,ζYlΡΝ&|Σ°ΑŸ6&{ΟΒ;,GΈ·?₯¬[’lή€H)Z[α2 ›Ι…Φ²,S֞#Ό(‹NΎ œ­ΞyLάcŸWM~Š&:4"@Xͺ3ΕFΡ"ι&ζδ\«ΙΚύ€)†E”¦˜Φ³θί{_A@-ƒ †0t=ΌwmR²ͺ©$ ΤuΛ’r7ί5)#rViΫ’υ•ν ©Σ«QΙψΉρcÏ\@LOΠΤ)ΦΗ έ—M!%GΈZ…ή€4,4©ΥΙrά“Θj‰₯:Aδ§½Uj°L3£ HξζŽί=OSnπ―Rž]RCΟO’ϋ"§I ΈθΓxΥbΉcoΘ@ΖV‘b½Ρ‹Ρ}Α²½Ucώο=ZΉ€,j5Uλ(‰«’MC7ΔƐ΄©aw₯•τ㩦ͺ¦»Φ­³ΈIn‰½!‘χ¨ΓύΛ·/›L’qgΆλšu’ :yΆ‰)ήJπK]7₯ά۝jh.Ά—jž“’ιRΌ‘ΐΰ28Ε6ͺΒωžΔνΡΑ†ΙΡ υš,†Ψί#'#5/ž4[ΙΕ₯-εDΤ]„&’ “hΤ¦t£δθ/;NΟζzr gΞ¦*A©…j»ͺ%ΙV„dSr pšΖrΡ°u“ΆώΫM<μ§»ηηΚ€-„/h©UpMύΐ$Ν€ͺ ΐκ5XΚ|ΞθξU™‚ΉŽκ’w}1Η%οvz=ͺ,U·DJ:4u[œ€WFΎΠN΅Ήΰά£AIΖQω#yv;’i»š?mŽo8Ζ>ΣΠCί;Ι^έΈ?nk ·ž—ϋ_φΗωΌνRΦΟΎΜ—ΛΩΛΡΓ‘kΦξ?ϋFmΛ§£ŸύτςΈAŒ›ΟσΩςΰe^ΆΩmΫ―IrL_<ά«*―όH?όλuhέΙΛ—ωσαo:^<<Ψoί»yΎͺ/ϋ_ΎΆƒ‘ ™'Gπ°{ψ“ž^Χc~z}\Ν€8β¨>άu¦;τπλΆ—φξnmαισζ€@ΣQi,ΉŽ"˜I"v›ΐk{kI…ΨˆjϊυΉφ“χ:?4zδ΅ήζ.μβqγaj―έ€φžέξΗ߁vHοξŽD=¨‡ΪU Αυp―tͺ9ipl[spπΡΘyEμVΊL zΡ%P#“Χ}υkΘLπς‘Q§?2ρŠεP9εš$!Α`'OŠŠuΎHU ƒD#ltIΖ3rΣ„(!Όf`¬zhPžϋ>μ£m—πΛ›μhέΨξηοœΩσκV(τŽ:…w˜r@oπŸ’9_’‹ΊBκπΞΠB.* MuΕd +9BΦ ΦέbsΖι~-x£=ΰΫσΆEΓ՚Qt°+…aκΝ„¦ŽB‹SœΝ„]™‘€ή©Ym[f’Ύθ!5Q‚”ͺM₯Œγ)7Ϋ{T(³½φθξ•ΞIΡΕΙˆs7œ"\ΖoΟσα2}οζόΖ„ΓΫΣεΉYŸάƒΨΎΎy4έ:Sΐb…݁K[έcΰΜ^jhΡo¬ΪΰΔJ>Ωμε›rλλβ;ορΨ=>ϊ‘σw:ΒέΎ9r„ΟσΫV,ψUŸi‰ύ,*&λÏߏyχ­$πετΨΤή#-7™ f'}Δ#!Q·pvΦ€ΰΉnb’¦d€₯!%98AMO-‚4yGΞζ{Α‡£νπ‘ΈρvvwΟ€mq1Yφ" m/₯UΞ !’-5„–Š)Ή0—nα€RK@=±ϋ+<ΣψzΏΎ―Ψύω€'™>^+Ρ ΄©D”.N΅Ζ]. ρ °¬ΆΤΰŠX‰N‡ΦMG_"Μ_t«5GwσΒ½)·ξΘyΣγ’ŒΪz {ΥdλγΨ{§.*m­0…Ηάͺuh 8 +iSƒaΙWt]ΙT πΐΉQγ{†θ.«tτ€ρ½8φΧNίE?βNΨO'ŸξP±s%$#=)΅±Τ³ΖΕ$!ΉfSΗΆ ”lW‘ƒΟ]5 U·ͺ άQ<Ω{qΗχmυ#uγρ—F?ύj°Κ&VΥϋš"'Ρg)Ά5ˆP ΐβΡΉ46L υΙRJnUΎyτφ]sΏρ7wŸόIšͺΊl³—ŽΊJ-Tαb₯Α/|€•ΣzIΛΏš•n²°ƒτΑΥΏ>ω燇Ωo%΅PΘΐ+f¦αž8pά—²ΥΙ©‘™‘R³.‚w˜Φ°θEΕ±Η:ΩμqB£€kϊfwΠWgΜmΒΘ»EΨΕϊ’o3η ͺ1/―a†¬“Iι5’Bxπώ¦¬ƒͺ«OΏ}―xpiμΟίx]p,­.ΰίMήΎίΚUƒ48”ζ9)ˆŠ~Pδ.‚%I Π’ΜšΪ\ΜΎβ`η”Ίύν0>Λ0>/yuw]iη„:ΉE#„¬+Φ§.ή¬c,Ύ»J¬ρΙv*u‡ύŒ ?"Ίr<—& cXπryχ~ΦϋοήDΓ·’+’•.ma"υ.Β2xζ­λ­2V±‡FΌΞ$΅ψnG:?Σγ. ΪεK,. ­ψa 9žΤ©ΗͺD4+'Ή½'ιμγZ.I0«Θ₯ki―γbήε˜ΗβUτF=(θ¨ύΘ€βυwΩ]—ΖΈωΠ‰TξΤ£¬^©l0«¬ͺthμFiOZY¬ΝΖΚ+#rι%IJΩ·ŠZ$„bι7;"€°άˆ,κta˜σϊν3½ΜNβΚΤΫ³:0U'͚l}—‚iΨ’Ρ°€>g`) B«ZdΊ°=%!έK•²τ=/,^η/όε•νέ#œΎoj šή@έΰ[,9Z’vTΝLωΖ½pΚΙΆDž¨Y.m•\€!™_αi+θ<Ήμeζ$aή‘eΕRφ‡pΙ*¨Žo_1 rΜ9Λqx0ˆUΊ>,er:Έασ -τ‡ψcσΊK£c#"vp;Υ9ν I:ΖfMΦSNͺΩ`ΰw΅Ί­Fυ;=ΎςC‘K±ρzrx4u»ΞΘ„gΐΊ—ΆIHmοx[0ΊcЉ=[B4™ζAœ¬ΰΕ…²&Ϊ6NΡϊ"²]Ό>TΒ έέ­ZΝΖuM ~S¦PVT΅•v²%Μ‡ξ]s{ _»C·$]όαŽΠ«™ΎQ5Š[Θ#Cά$ςfŒ½ΑoΪ”£Š@μ!J…F˜ΌΦ½X§z"»!ώΓmnϋΖΗx₯ηι]k₯˜‰ωh˜Α*΅Τœ=7Ιΰ+²ΜΪ&Σ-λ]w0Kl­ΔοxφD'έΞ¦ŸE@ΛΙΧRΗ;g`·jr+ ΔR³u΅‰«ΙFwΉώθ4¨> ”₯ „s’€5ωd¬G ,K‘$―ΕE¬B_]ME‹ …N“JΗ܍—VΒ₯AΊ¨eipΠ~{ϋmΓψ{kΡuDmNΑ:‘eυΝψβγ\bxQ*Vz~˜QˆΦ θ΄“€UMI.f΄5σΊσβI·Δι;v•sL^Ξ6=Έ|q^z0GWΩͺ&ΩΒ™{Ά6λήαZΛοΑΨ,}έUεσΞ~(ΪzξY]Zdλώ’Η“”&g°½{X›\ȘΛb3!wJLΦkCrOŠ―€[Ν΄2ά€U™›"•Ζ'i1ϋ}({~yόyχvžŸ|‰1΄ά: Ρv nBΏ₯ƒgΞ΅΅ή½ Dϋ„…ˆHζ"œœΧΔ‘¬ΐύx™­.MΣΟΒ―Ο³ηΩqKι“+‚² ϋ’KΪ<ͺͺj‰ˆ_Y4αΝΑγ”΄)κ¨R= hξS›±$ΗΪ?ρSύΊ8i45PTΜ ‘ˆŒ¨jQAp‘ΖΔˆn ›[ μExα1΄fPΡw5~όνOOzξ Ε‚eΣAΊ8εjˆΗV{¦^πΒ…4(%ΆQ―QΊθv­N2νΛe΄p›Λz¨ζξΗΈ0?bͺ—ͺΛ< qhkHڈͺ$mΕ*Έ 0 Φ©ΡhΌΰ@ίK­α#1•Ÿζ½Ÿžu…ι{zΌ±Qˆ4%P°rζ₯ζ˜5ΠΌΉΖΞB<•fGΉ ΗT ή½΅oκ†xa”‹Ÿ'’‚fϊυΪXŽ™Unʁ“)Mƒj’Ž’ΟB {Ρ&B|³1€€°i‚ΨZ­ώ& Υ#ΦrN5π’%>Γqξ―)uˁm·U•` p­ 6Υ6 &tΒμ—PeΫλk)χΉ†I$χqd 0š―?υ‚…k ΊvՁ߫3”†\$Ÿ“²Dή”ŠψWK.ΰΑj{ΣΨb©‘½UΆο$oΧџ7Χ ~“8p΅Έλiφtzη<5χ.L(rώΕ«>–=Ύƒ$k=ΰ/p€“³―\ ψ0*Xρ™²•/£\φΊΫŒύΓ¦ι…AΤ*baΙέ9ΟΘ+Σ’‘Ά(U‘Ι57μλN±J+O—4#޲2Xί₯Ώ<άΎύ›°Ρ•ažOlŸΎ+­ΖXu*r<-‘ ”“8]ΜKΓΆ`#π5βJ«–ΊK"& ?1·YžMيWΖώΗηωﳓfΛnrD°&qNU\`T5ˆ’‚'‚ί%W³!o[cO:c±'`€¨­[r4ΒEπ濏©Ιμ?ΩτžΈl™•Σ΅8΅GuM–_Θ©€6Φ²TΚδp ΚYέ{"γ:\«jr3ΨVΊΛπ'•ΞΓΈςHίΨ”ΟΛΩΣΊ€nύ`yτ`$©ό ?ΊΧ‡aE―Χ₯;\¬ϋκ¦Η‚λŠώs+Ρ_]{ηL>}%lτ†ΐ„[ΚX{˜9­ADX‡,οƒ σͺ)H—μŠ§s;Ο¦΅β;ΥlN~δ1Dœ|Υb=μWl}lWK‹]sφΡ…’=ΙU―h/½[ :₯ )GcbC75{ŠΑ†oΉ›ϊ‘ Εp_«” ]±αι pšž°/Νx΄Ν₯Έt( ³DξΡΊ’tHΙaΗK‘hN<€š°cς’t)~JÞt_™Ό«P˚εDΑΑ}SοΎ#ήKI’Υ{š—>5‘΄νQNZšoδJ€[ϋhΕ›Τ-~]$j—wrΚ:ωΩ\0½wvJ™ξ:Βaoou¨πzU¬±²%Γ†²ΣΝ²κΎU£Νω3)zQ6RΡ‡ΧhΨΛ6άv/ά4ryΐ[οT΅εkΌ6FN{²gςxΉXž«9NώšXd= ³§B·ΥΏ½/–•ξ"ξ›΄ΛΨ†ρDŽͺf«I›^ΐ+‰H9–^(Xβ3G£'=:’.ο/{’₯Uι*SιAΌ άsͺpΥ‘ZιύPuε ’YS{!%“3Ž€,€Ρρ ντV§%Mο ε£ΞˆΨͺƒ{[‹­—λLς½ψή’bΡΩΕΜc§a_%BΟ”-f„€žΡK;{œ1Ηί\.χ,Ύ©πΑ“-Σ]ξ7Œ\r}=ϊFϋ1_|yΌϋλ+~zι³Η QνΉHΦϋσq4/i'/ΪP6θΦu©ΖζΜpb’ <Ύ3Ζ'ι«VŠjδsZ v–ή6Jk}Dάxgζn<6`9;8^avς>"YΊ°6PΔ ‹Ro<§ž£“&DKE*΅¨%#ψ>₯ΠKΚZUπMxΎρDςχΊΟ³c}=}o i&ZˆV“ bš†©!έ[RE€ωAe²mΓwƒΘQ²σ΄ ϋu›­ϊ£τνΪ+z?ΙέΌ|σϋ‹ΜΫΜΖjKd7W£:ΤΧηΦ0ca"―«―σΕςλμeϋ|έφa{βΊ΄«ž—T%δ?ΌΜηcΟίώΞhWTΡvx^ΒίmΓ-χΔπηΩσW^ΰ·οΎΉ?j|)vc €_gΟ»‡ς|γιeχ`Auk™αΛΩφtDόeu«Ÿ3ΓkGt|ΖΧΞϊδεsέ0κ# ρΥλεψ΄Ά~ϊΫ·ΰΒW›ω:―ϋύ Υ :{0,}·8ψwˆmηαΙμyω²m 1ΎΘ^κωχΨΜ«‡ΩΣΓόωqkϋΝΓƒe@?Ÿψyu ;Sι‘Χ:wλǏ΄κσΕΣςŠμψvm {Ά¬sLΒΟ«‹χ+χΛHχ–σψΚή<Ωv¬Η«sο~ε&^<ε—yύzζΣΛΗωκΜγΧηϊȻ糄―;<ϊ£Œχ‹˜ε…ΆΟΏ1Ζn›ΤΔ³7$Pw³Ά\χ9ŸU>ϊrπ»gλ%)iο/ΐŸxυfα 7ύ‰ΰ 6εθάΎœΜκYŸq:+‡žδΌ)ΟxΨv±η,M}β€ϋšsV;|.?_zRΞϋ'΅|-x s5θ0b3-f/«½>φoX»νrίσnβηv ›\ςx»Uy»ΫΓ[Α/ΝΆ€'~nίΗ½ΎΌΜ«›½ήGβΰš »ΤΝίΪ<ΓΪ‘I[-―;ΆƒΙήy;¦ελf΅ŽΈΈΣ­-ߟ=χωnΏΌ<Ξκΐ’κβηΛj~ϋαΕ°ΊgΌΌqݞœΫ5χƒVWΦΔ6z|E›κ’‡>v‘ξε‘HΩΰτΟYκΐ{ϋκHχ–Ϊ™”Ϋs2VΗ‹xt€οYηqι΅Ε•ίΎ_Ε7γoΌύžs»μxΏμΒΕζOO‹γGg ΐ~9Cς•€+O~ζH(‹₯ΗΟχΦαχίj$hŽΖΒ—ύ?‹tνΐ7w~#+χ¦(wq§EΕne^Y>›ΉΈu՟“ |[TΫ6ΆΆφ½D/Ύγf ·/σ‹h8fn1>Γ̜ Mkο³½Ή%€ν=€λΆAy»XΦΨ Χ7ρ½+tδ0Ѝαƒoο°Χ.Œ>όϊΛo΄Υ‰΅e.Γ8φ'ƒεΏσΥ¨όζznpM'Ζά|¨ρΣΌβSγ<όαόαε+-ωάρ _Ϊž6|›ο~™=Ψ`ίΧl‘ΕΠΧhυσ*ژ=·Ω‘ωΐ!VG>_ψd‚ΰŠΎ}fPhή;OΟφΩιJέ|@ξ ~½ŒoώτΜΛεή<>τΗΓΧYπιΚZΦ―ά^ωΰE—ψA[Τxψhτ•–slπCsΒ/Ÿ|jύoςƒνahƒqπύΧ6Ώυf/Λۈξ₯ΰ7Ά.ΟP‚ 8sxφϊ<IτƒG`G«λϋιΑΠ-Xdv5;Ι#Φ5›Π―η—ωςmΟmŸbDΚcp»·ŠΦXχΫޏܞΎ\`g›€r!…ζ-°ErwΈ!`= ·ώ‡“ΣΜ“πu6tώ³€ηVD+Tπ€9¦½‚gGbΧΩΓ«σhrϋkϝ#]Α‰Ž&oŽ§Θ^τ«g.°αα™Λ')£Η·αίvFrωΜγΧΞ'nF€'Λg‚ΥϋgΓΉcΰΆY Ί†œΞ ‰ΫbοIdΫξώλE·χGœ+aelύž„•χΖ‰χ†„€ν™Τ{9ΛώΌrύtŽ œ_;AϋΨYΎψκΣΉϋΨIϋ•“žI<βG ΙeoΈ[2Σϋ¬χ¦λ₯Εόε$‘erhΈ;ς!%WΙϋΔ^š1xMsd]zΛR“š{γͺΡQ9LΡ4Β·Λoc―Ώί§οψv}rzQύ7Ζϊ(YΏ΅Υ.9*ΥUΘ½‡dœν©Ϊ`»δMQΞ΅+₯(”\)Τ‘A<+ΒO~9žEA—¬’%[ƒQB$CΑϊ¦+Η& b9Jžd Ε€ή3ωF9(Q£0v9ΎnŒͺσ&΅­c1Η¦ζ~6Zνσπ>C.ι u™Ν½«$0?Ζα‘X€Λ+[+kE‘ υŒ-§ΦΉ[‚O93YͺΩzG͝/άΊ1βUϊ[|™=―ξ^Pͺ²ͺ±η,o%£Ψω•tΎάc1’Έ»ξΕ36₯Ά&ΧκZ0VT€”»©|="Q‘ψ²q„Yx¬°Mθ;.Hœ|Ϋ†%;Ώΰ"vAΚƒbΥԚ5΅u#9M]œ·V§ήJήΩͺ½J#šˆ7Rn™iuχ1κμtΜјjRv&aΞc€ά•s]™€΅(χ₯ENu9•œͺ!K πΧZ#΄o­ζtyΔΫ₯p’ι9uLi¦οlρ.ST₯*‡m›Ι+™ |΄±(r$Š‚J”ΉES4’ZyΗςΎe¦·ω¨'ΫzrAΊŠ˜’­+Ύ•ξΰΰΫKŒΖ₯Π¬υ&γ_:8W0Jμj*œzτ‘·Γάί1ϊ•]>b–ι·@ΓϊW¦HΞW5­{oT± ;΅&Ψ‹;Bu/ΥΥ\ v 6yQ‘ ρΏ;{»ΝgNŠΰ¦^’”Y4cM42‘Ν$― ‹#)¬’{l₯X ©^”Λ+ιΪTΞ&«Νπ8+OόΉΎΌžH4ί‘;&Ά~ξ6z8x ’΄VΛ ^Ξ…μCοέvΐ²TŒ%kφ1ΔΦuφΖ‘œ—c˜Qy 2»!Ώo^ώχτVΪL>S±6(Άkc²ΠKs‘Š#Υ±ό›IΎ\“QΑ₯Ίmά΅SƎTvΦE΅¦Σζeψ­… Οvϊi%ψs‚ƒ .i‡θ6l`Qφγ†V šΩvΔ·B˜l«RkB΄Γ7ۘ΄Ϊωןήi-Ϋ|ˆt²Qc݁ν`§™ά΅r؟άμ zΩ‰QSM"»Υ4sυ\ωσPΒ}Έ §―Ί’.p’(ΌΊwΡͺ”€z(Xφ˜#QQς IpΔΰEA‚ pL{²#Εgϊn uΎ>˜:©Ύ‡θ4Υ‚›”΄Κ!‰tΑ₯΅NΛ½Β ΓΓ[ID[Θ„βγ˜ΘΧό…ώυʍΛλ—Σ,ρΙ[%Ϊ,‹2`5ΌW2˜«nDͺΓƒ΅j ’¨€ώΐw5fg}Ψ°π’Ύ Σ;ˆ`€ι,¬MUιτ†@ RœOAΞ2–‘Oπλ‹±AdUJNZΪ6>λ*‰“ 5;u›2Ό³*{P΄Ll‡>ͺJtJ$ΪYκκtΛr SМΑΪ€Qelxύ4ΒJΣՏσΤΑExφεωAꝎDAή|Εi5Θ\4Υ¦ˆδήz½ΰ2γBξΨ\ΦieΚ–ψ%ΏŸ»/¦dŒ.rδ’K…Νb0ˆ•Fdo.βX¨VN)ΒΤS)fΐM[:Α[–δ΅HΝ` ƒ6—mZ˜hUKˆ#!’½ϋͺ“·­ΊέΝ~­ΓΔόuυςΊϊό}₯EOρΞ³κm{Α΄ας©z’Κ‘)i΄D~ UT  2+χ¬[7½4X*Β9ΜόΗ³DF8‘ŸΪWa}!iu]L Έ 2Τθ,PRΈ,W5Φ& ΄H‡Faoμ€Υ’©η‹r–+*όΉ1FπyΫΩ{d¬‡™8ϋΓuΟ]ΊxiuώVιΖ[™ƒ3ςωh6i»>ΰΥόiV₯ŸυΛ»Gύο0ΌΧ£ΰ©Ζu|77A.ιΥ{΄_3ΔiΆΘ=μr˜*τΛVΉδ2±i††I-2{zy\ŸiΘηΓκυερ½ϋΰ\ΕD£’€&ςs·δh^4Υ±(ΐε,ΗΣkψsYsη’ΦޟvΗ}~˜†΅}ϊ}Ρί7Χ7dU][ Ϋ4ΡΏχrΈ{(Ή-Ιωψmώ ¬pή οΞΈ[˜-Μύ=ρdψόq²Γ]ƒΜ[ΥΫΝΓ~FF%IΎο΅Δ/Ύ=JF9―Gν³­k>IEίk Έ§+6²Ο†ΙΌΆό΄Iτώ»ΞΛ6½ύ―Ϋͺη‚Φm%jwΫ³{ ώ‰]ώόρnKnξ¦N|ۈγΗηG7Η•j7Ω"·―¦Ϋ‹0ήTnޟΆx6%ρ0Ήύ|5ω‚W«Ÿ{ιڟΦfΓχ†D½·\ΤγZsΡ$z©_φΊ˜;‘Sέ¨›—~MΩH.ν!y·ΩΓwzœ΅Ν]/ΔΌ4οˆ ϋΛμ}ι―l–ύΥrϋΫPHιl)γνΏυ$Α}¬Τmϋ|OΔo’R¦σσtAgγ8_rΌHφ­οj©ιΥ—}ΗL^΅Λϋσˆ?°ίͺΓώΊ£Ή³υQχ9ΧMrΉ6ξߟʝ½ά<£s²ΠπΣΎ>ρVΈgΤδηk˜n!†£ΥG«Ελ“„©β―<ψΌVΔ[?Χ7Oλς?ρ8φL™ζώ(ύ_‰ΙΙο[L‡Ωθ[δsΕtΏ“δ‚ώ}8̟ΎvΦΨU<ˆΆ/¦έ&o­Ή§η,W΅?n·ήD<ΎΏ`岏ΈΧ™-Ώ]_αC•φίώζνΦπςΩέ“½ΓηJQύδ]F…ͺn¬GϊυcϊBΑνΛC${i~ρ΄βοήτώΊ x~‘O|λy―ƒΠ­vΕΏizΓ•vƒΆJχ3ΐϊΙ›’ίίt+νι“όWώΎοR¦~+Ϋ+™'Ή;΄ ·ΏQώΰηο ₯_Ύπb―eΔt'Α—nYώ³}μψς#'ΰ·­‘ύ³”½3₯_<ο܊€έ¦^0ΑAγ;¦w’ΣÏ w’D=pΟ³ϊν?ς°eΨ$Pύ±ΎΌ˜–+ΥN}G%ξ;¬ΟεŸq·}^μοrϊ;*Lw“’ΚYύ΅ΏΌΧΜEέώβλŽvοΈΑ/άIOμ―ϏŒ:ΰμχ»“ο˜ϋ‘·ϋ²žρΑγϋ₯όŠΆV-ϊOœζώ“¨Gς!οιΐo/œρ­ζϊ›ν3·ί^ ½zΟϋ±i»a)o”K'XΚS iPΰwψ½^δχά›‰ύχ¬ΈQωx|Aϊκ½>[‡gο; ΎρΖω‚Ζκ[6Γ‡Ϊ93}$CμBΓΠ“δ±£ސKvτšύ=!κhΕ_ώ]ωΕ"πψ§ ΤϋΉ€)%iœ‘]ΟnλώΫ€ΡqύΓ Χν{κšA^ώ²β?˜_·ωγVΣϋŠ©ΞΫό]€όθ ρ/€CίβFδ‘Ԍέ_Ό½o ξ-oχξdάχΦ}$ίήώζΫ=ςgxŠ‘λ°IΟ_?δT/΄»fɍGϋ3Μw©θψΟ<ΘΎξ=Ά]ώ{nšΆ‡©=#ώ~FWϋΏ%iuΫκυXζijιγtΟΥ7γU°*©nͺ2ΙctΧ–uSμY§NJUkͺ±Ž¨y‘“qŽΩ¨$=76‹Ύιη{ «Φ7ωdΫjΣ±~ڏΈ­Πρ½˜²ϊ·}θ—ΟτrΥΆϋΣxΨ λΚ‚9z•=RΆ”jTΝμ1PhͺΐζI΅kH-γ­.ŠͺIœ(_έVδξτ’Ϊœ”ŸΰεΛGiZwΒvοP–Ψ‡L[G~³]·ωήζuͺ•ΉΗDΣΘV_T`ΥΔ²&&6ΎQU₯jκ°Χ€z)Ρv9RSyΒ#†Λg kα7=όXΠΛΛ ίΙe)Ηρo]΅άš'"ε(—PjQ¦Ζ—μM―δ)e]σ,υκkθΏ]ΚjώM~νh_§5M,Ίš“f8‘=+‘Χ.u/ρΎ¦Ϋl“U,2ĘqΆ΅f[°γb0:5gJΈ΅½έ˜3::OώŽώμΗΝΊOΤοΤδJh-tM•₯9{φ+ίzxνaΨŒεzν^ΓΣpr٘κsο*γ /΅©Ϋ ,ζ?žΧΞΨάζ^ΆV8€cgϋ.ΗiORο -ύΠ$œσNχΨ‚έϋ(‘34©X³Ρ.κ 3"mφέs§fIq ΝυIωͺ²&―›Φͺ˜›Jd׎gψοΊwΟλβΊ«–κδc€1½wΦ€Αˆ–kΦYks±₯†5‚.MŒ‘Έ‘*#©φd½ςΡD₯”Χ†κy„Έ6_\lΝ2>Hg&ΧΩ+‚’l5!xe€0 gΒyKn|Σܝ/I™Ψ=aϊ« Š΄\ιΔΩ\φ³?Ž΅υτΛ΄αuΉ cΜ₯)crp•Ψ—Sξ”kΞ˜–Β"2ΫΘhγΉ*‹ΕŠΨAW§iύΥr_λ^ή–›^ŒGχi&ΝΔΓ?έ~ω0tΘ9[εΏόJz@€›νπHλ4―‹ΗOfSω?ΎNNnͺ6-Q§E)n eΣ3Ηd[Φb&™„½’Θg6*TrήΔ¨ΈrJCdΉ5@Βί.ΎΎxΞ»GαžKuN†K¨¦³uΚ@ΨΈZΣΙ“νΎb;w’ΪzΔ²'ψ0γΝΘ=IύφyλΎέq4ψ,dj½Φ7­Ÿ·γ\‹χ^›Ϊ3ΆΡjr•γb³"κ­j‹b‹ χ0HHŒh€GDρ0^χΙΪή`εωŒ/5|Ή`=½g‹ †$‘­ucZKŽαη8Αdέΐhΐ3=(P¨9šR[lΐm&’φ|ΎeΔ 16§”{q4cI7ŠασGV Σ‡CΡϋžj`-Τ/4Π6Ύ:Γ:b«D §rθa―©₯ψ@LΉΖ†fRk4Vη―νHR_ήΏΝΌό)Όμqψ8ΠέψNΪΓWbŠ3Ύ`]2μτ²θΝ§kc^kΤ³e!Ο^'ͺΪ‚χε†oScγt °`Ω)1uΓ“κ[€£jΩg J o HΨ˜Έ#―πW™Ά—―MEΏε΅β\‚εm]υo^~=θ»Οޝb+F©’#w@JΐŠV)—τΘͺυΌ’\€’±ΓŽUυšΣΘρΑνΣTΎ!ή]±_!’* o!3Fœ1)tζ1DΛ)N^λ&4¬Χτk˜’w¦εό:΅H½;u|ϘοΠzL&ς)`˜ͺ+ŠΨ@ΨZFΙ\Α[T—Άk›²*†“«`1΅‚p&…₯;do”ιβ(™½’oόωΗΧΩγύuϊu. ­8εj{*5Ι*Ž…Šη¨£u©fΟd*(΅.]%{™kΛ!η±έΘxΕηΥ 1oΗth-}?q‡@­΄j π‡ͺ΅ΝΦeolΖΎLαΰΉƒO$ς rέ1Ύ  Ψ΅ώΘ8ΜŽwšλΝ§›5u cΕ:›lΰ'»+ήS―UψPΚΡγ€υD”6JΦπθ8ŽuΝz­hΥ]І8» x γKοΉχζ βψp%‰Λ, #sΙJ?φηρΣkmט1ΆΟgο¦Ÿ¬¦‰½OXJs¦€5œΡ:ƒ–΅μJUZž_aB”;/,?@ŸbΪHΌή¦δ#ΩtqŸ/ŒψνsχžΧœKj%˜ΐV³/IGψ‡εL (/‡€‹u‘VŸ]Τ‚WhΟ0©ΪG.υύΔ+ϊ₯ːέΉ·1ΌNc§\χΨu*f X¬ž»717Ά˜χ”|ΐnΚ­:Ik˜†'€Gš‚<ΡΛγμΝg‘FΗ½ϊ² —―GqΒOξ_]ˆMašμƒΫ59€@k=a…ΗΒTΑ”6 xΝ"":–σΤυVβˆbΜοάΚl΅δ[{d½Μ†œν3]Α@ίγΤh w„Cx³FCΆ™– a s’![[τ αΫϋ³lc†m0ϋ …#λώmC_ΒΕ3=~ΪΌώ»‡-‘tκ79€YπΠn7κκ\Œ];7ν’œ8‡Tΰz‰©8“@Ϋΐν2Ё •:ž½}Τλ·ΏeΠ»ΏsIž¦Ψ‡„ypŸρ]{ζ |‘J­dŠΑςa1TSϊΠΫH©ζH§μ'• ½f{Μό ™Ψ"ΘΥΠ£+°‡ΖlλεήΫ{μlΖζΞΐ‰1‹ETΉ—$ο”ΪM‡ΡJpY{R D.iψx›C¬%·NΦΘ}†l¬νl+΅ΫΨθBŒΏ}h Σχ’n 'ΊŸε~0ΖjΉš›–Ύ³[Sd=Ά2†λƒ\κ7¬©=u²‘³ςΖ±.ΙΈχ=g* Α%Uν5Π―簜°Ε¬vAƒ–)/ύΧ@GδX½λ€ψˆz¬Έy¬£δ^s­“\¨<5'―pήΉ\Ή80–ε―HUˆ–st"έͺ©o΄‘–Œn¬oŸTAH›κ“n­Σ§I€ n˜ΞF:Ξ:RˆπΔΟΐΦY‘Q±gα‚•ώBqΆs6MӚΡE΄V>ZήύCNΧΐBΰΎC Χ‘b• Σ\5ΒΉ•#(αX@nΤ±€ΪZnλάξU€λΔίσ€Ψπ Ÿ=|Έόώe§άύPπŠ@νλ\.·λ;ωΉχ6VΑLφ^[«ΊΔ½ΖΡK/LΗΠΥ–˜³1¨±ΚV£Zui-rj€ΎΞK#βΛγSά} 6a²±₯ε \I`ΐηπmΔΥq—†Σ=W 7ο½š/+;"€Γ]§3<6gσΗΗswΏ“χo5K ň2ό6;οΌΩιdMR˜ΌTαI½ZQ1ŒβΐΣj«τΖξΖ‹Š±μ₯,έ,ί›Τη?΅•ΐrt‹35SΙ½φNhEPlλ‘£’ήΉTγ·p W)f ^Œcώ­;nY_^α†όMΗΝ·ή©ŸΦ+yΘxžΙθθρAr™.γϋ šυΣ/”P(Sž{°ήͺjΡX!FiWŒ‘T݈ψΪδp8Μ ήξk"–•tcήΦΤΖyω>`€N»―OžΠX£«ΑΈ†ΝΠ°~τΖƒ?κ”lπ-–Τ»¦(\“μ5§x*ωQΈ·ΰ&υ³Ό<λSσ°°V.4ω(©ŠήcΛ(ΈSΕU+ζ?²ΣΥϋ&}ΗmKŽIr†ŒI΄i3l–…HΫlfl†³MFŸkγ~8ΉqΤwp„—υd­‘žάμ2QςέŽ0p#‹V©"ή3{ψŸ`’“Δ’-<ΧW§oέιήΓΠxif&v*γΥΈ$ΟψFΛ”‚"Ι±,ΐ‘‹Ρ€-ΡK(λήfέΗrϊŽ'νΣo2š†Ρψ φF9Ig˜όδΎ'Ν:8ΗΊΖ{ `Ρ‘ “‰ΕQa'R:°ΐ™ΈφΦι€NΝyEΟΛΩgν§O›μΆΑO­UO–χA έ[fϊ|]©(bfcΐœsΆΦ³*@g䭏Ρ†ΡΌ‚οbέίH…”t[[fΫΓζΐ2ο²ΙaBνIVΤΤ‹‘ΜEcjΛFIh \7 f…&95Φr›G‘Γπη€χγǐ۠΄Ι8~+ΘΎά«:;¬Οy=_jΏs”υš§>ΌΡ-ˆλχ%lΥ6; šΨ@C©;Tγt”}Wsx@Ν:]RΝq€KωjώτψΑ1κ{d>κήYΰΰ C/rιΰ»‹Α`Ϊ}p-6e“άɈq@ƒZ…Ψ%³"ζσήrυu†9^lΆΑΝ#^•“†Τ“{‚Τ­U&*ΈΚJZ" »¦ FHΆ ΎU„7ƒ‘b.«i€uΐΑ-Ιώδx-α`Ζ­V‹ύ|Ϊk‡vŸ~یϋσπƒ­ω Ωξ‘iQ#+ΜyΚ†¨ΘZˆΥ†.¨@Ξ·[³ L”{φZ.1¨•%_Ω¦ϊ«­_O0ΪπλξΏΰ’\ž—±ΣΔ‡0x’ΡΡΆp“–”z32ΐJ%DS“ΰΧ‰:Β4θxψοΓΣ¬έΓLχX`€ @ΆNнa@οD’Ζ₯“ΛΦΠF\ΖΚŠιΨΩL@7;λ{ ωVϊ¨E†t’“ Β©O;[ιͺΊTͺnYΫΤν«­M ­±›P¨Rυ~9(ππΰ`c;<Γ‚Ώ]Η3/WάNbθԌͺT ¨bB’Ϋ(bŠ]$8§Έ'9g‰σ­1ΧV7@Χ$χbͺ‚p„«1§„bκΙ(Ήƒ’zΙ&γ3 °±"δP ΐ%ΐ )δIΕ8<­ΦΖQ Qλfμω[jxEΏΟΪΕuχΔ«―όϊ'™ΤΎξ­8qc°ϊl­Qξ/@θ]‘B!K¦‚ζ*mb`xwίH΅\RνΆγώό}} FόόΌnΆu±z˜ΏlJ‘χ1ΕΈ΅–«“ΔάΙ“ŠΨ³°ΥšJˆ‚6`aX8₯cHb‚\θ‡Λ†ΏκV…ξ| Υ79,Mε[~ZηrmίrυV„wiΐεuφΨξ>lλ}*nγˆΖ1Ηδb½”ΔH™ sŒDt]c°#φBI½eoΆόΎ5O©ZΝηR’€Υω¦Ζƒ’ω:Αa/wcg½=;Ύ(ŠξU—Tΐα¬υλ¬~½fέ³•ˆΣ›7`ΰRG€4&Χ}v Q΄Ύvεk–ͺυn€žx©"νbΙtέ#HEμ(R‘Σ`•ŽΔ#Ηeώi ό΄,}zMΒ, p”lGεdB,N1Θ ―°€Ÿα=…€ΈυT£ΣRθΔ’(ζΞσρΣΐτΞqΊΙΧuΦΚέ/‚―ς]@RΈ)Dΐ›¬“ίaΡπ!δ`ΜθxCΙ­ώφΎL_c”UiμMAK€o ~FQ3΄ 3&2A•c1Τ»wΐώΤ3°}Óe†¦σ­±ξ35=.΄Œ‚ά–ΩΦuυIN¦›(mB–‰Φœκ=θ(Ÿ"gο$Ωaδ:w el†q6Γι=βδιΊHρ­ μLΙ΅)Β5IΏ…―Q„…Y=([ r‰Œ\‘琡3·$`ίΒO7ψξE ±8"")6VΖD ‚”εŽƒωf dΑMφcJ–ΊŠ₯D,&Xƒ"\u5ΧƒθΙ(§—`«d5πg—A:j©ωΛ„*υB˜Xκ’€γm @\R=¦ΓIκ…ΐκΥQϊχrϊhiuV’19:πOw’Z΄”Θ8£ͺdhi.9;‰œYΓ4k$‰ΰκ(―‡Η5₯Ή7lάrΖϋ7ί΅•Ϊ 61ε2¨ †eΠ;Ÿ»~ΑGα›Ω0v*³J,Ϊ Y;ιΤ„@λ ΗyY7ΰΎ’RӍε~0ωRε Tθ ΠQoͺˆ6±Fh4 Ρ³ΒΫ\n!‡\υv&)υxόvrχ}1fε1*@`lΦR\L6΅ gG ΛA΅κ"ͺ,ε1ͺ1•ζU<_q gΤ_λΧεŒκΛb#–}Ρ<‹6ΑwZ όςξηŒTz.@K€ΎYΥ.Κƒ tk²θaΨjswΝ΄¦€©§›ΙΪi'eΞ}€ ]‡‘§7“{hHd(N>Ν΅X½ͺͺ$ ¦¨šκΙDbwδd2 ²κ Œ)εm:8“'pξ»³˜{{ΎŠ Œ1">{ŒI1ΰ`ΈΒ.9ΖHSκ͈fΆ”}›ΰ­vf0ΨΕΧ_υ|?^ζCYοέ'5HΉgŒΩf―‚ΧΥ1ζΡb= €φΆ˜žTΖnΐ$ Ξήd|IΪ²«‘Β!ŒRƒŸGm5¦wϊJP£’Ζ++¬9&©ΥΣJhΊ J±₯ ·ΞXŠMDˆΰ«~@«xy+Ύέ¨ΦΕ|Ή,L’δϋ―Χυ=γew‡ˆ?₯ΪΕς‡½Οε ΦT¬ T}6Zf—›Ÿ”K€­\Ζj]['Ι¬~Πd)¬%±DάΘέλΞυ+=?σγ¨aޞ ·±;ΔΣ, υΟυευB₯γ&ά[Ϋ)ΔΜΖ%F“BρΪ'‰q6ŠΛZΓα+¬—„?ƒWvs ‘dŸd%·mζ7ϋΎ@έixœ1/’0a€•ύΊΚͺ³“λ>~ͺ—^|†³FΐΔ-]»Oύή ΘNcT\V«₯p«TΤF8OEάG‚'ΰψ¨~ξŸ?„€ΘZΨίΰ§θŽΖ»x²ΛJ%œ —₯όΣl"“…ΓΣ”‚‚ΠqF.g·s+kλφrO~ ΌΒhfXjΏκJgόΊ*ˆςΗ;έίγ4{Gƒ»λΌσ{Χfˆ¦:$?½ΏlΓσky›$%œI v\υΓΜΔΆύ*?ςjϋ£μ–―κ‘!eNwPZ α­ ―ΐγΑΟεκtɈκͺ’˜…±jδϊ>%"]›ί̐έfύ«Τ«έXάΉI―²`ΞdΖ™Φ<ΒΣ#ΰζU¨"ΉO΄,QΊb}UγQ ¨{`Γjς²Ωνi1G‡.‘ό‹ίΈυ)ϋ°zϋρϊ±xš±ψkσM#δ²πΔΒd¦°«Τ"i^ƒχΟLh!Ήβž#,3ΒYο²)z΄μ©;ZΟΣΌxޟi™ͺ¦TΏ!² «LΙ* 㛀@y€J_§L„h*.*¬7b<9·ΙΥ4^Υά2k›·T~€²^•υΘρ ¦§,Ή3#hΆto°ŒΝ· „2’€ iCDrΒpŽγ•<–μ+βeνιZ6ΦX|Υ<•U h\E$c§3ιψβΈ’ιIΫχ°Ϋύ†§ΏZ°~ΐxαZ“—pΡ.Ψ KΪU&YΝΓOhUΜp&ΈΚIΜK£$―ž& είτzgntsyΕΣ†Ωτ¦ΘCŒΔ8NE6S‘­0ΘT΄%9_’ȁ³ΤLQ’^Έ,™₯Ϊώ$δΓL ―?z~styCu<”ςPžͺ R.@‘ή ¦ljX•―=Μ²ΐ©5ΛBα"™Tn¬ 4»ςϊ«ώuBεςόΤν_o₯Ψ c”Σ`ΉΈ¨m1Ν¬<'ˆέHrAΈ8kΑ ρ²@ΰ΄.ez‘Η1&+νwΕψε§΅αμhΪx‘žςUN*΅κ¦½Χ™¬½βv#HeΘ6ΒgδaΓΓEk”Γ}sΫυξ.νOρύηκΦv<½…f8I*Ϋύ‡j‡{°Ρ&π†Ζ?&A9ygYδpΚP§³ΣΒNK ΄@JΩκ ΨΘ\Š ^ΩνΦyΔrΞw¬ά…ν4ύ€&hȈαNoϐV<„ο#κLL΅&SΉ~vauλς>‰*˜$¬RΤΝθ¨PD‰^&Δ[F! ‹gcΥ†&Ω#¨Ÿφ ςΚ=ρΛ±Qšΐ]XοIu§„ιƒ*)f’”Ύf›BԎ©ΠpieB΄ ˜Γ΅’Άΰυ €°ΐ)z!γ°Ϊ₯ΥϋΛΥηŽΘάk—}ε·^ΦΔs’±e¬ˆtaΘrˆ‘Fˆ@£"ƒ€JŒYΛwž1=RŠ~ˆ&š‹Ω‰5¦§ζ G ‘ώ9•λψεN*ͺiΟm*j8ΞV›1εc²9pΤ―viƒΗωΌ'kvŸoιPz˜bΦ4ΐxν΄σ΅νμ©ΓfΫΏδ?O η«χoeτžMˆφ.ή'šu»Y»naΑ9W“ΞγΊ”£ι˜?|Βٝ^i? ΆχόΞϋΰ†ߊΔi`°Μώ,Ÿ»}λϋNΞ{˜ΞXλ#BΌ!½O—™OΨϊ¦h₯σ ˆψώτ».‰Πρteq\Εξeυ~Οiίqš3Οlx=&νεα — ƒη„ύyί@̟°KΫU:3μΚΊΠKŸηpκ»Π$Ÿή7›υΨλWG}ωrθhίvˆ»ΑΜπΫ M9άοϋ‘§{΅mwνX*ΌΏιύ}Ή>¦[z0½7οOΈ ₯ϊ_γ2Ώ³ΝC<νήKΊΓήδ=Ϊ€σj“‘w IO.g^4\vhΞR‡¦L―Έ;H°5‚η‹έΉΉGΣΛvσvΈP©yMΓ-ΗΘΛqΘΟΈ‡ §˜<±Ž Έ Ίδ5GMΞ΅ο0NςΧ*•)Ct±σι8Rγ–0άτ,—0½οhήΓۊ~oy}ΡΡ‰«οόζ}ί‚Σ™ΥΈzϋ|Š«wιηάt]oζ|α< ’„°{yΚq‡Sώ Š? ct W‡φ/‘Γ>Pζτύυέι<Ψ0`-ιΕΝ›†d5ΟcwΔ±ϊžCΊfOΎA2uςνγύω«υΌ=ζgϋ•ΣύΛΑ0Όύ<Ž•}:|γά',89h$Ηrόυ$$ψ/ΨΪciζM•ξŠΖœSΏ²,ƒΗ;μ>―t|βΟ’όψΰ9Œ(q νλw”vΦI )άM%›©I§‡†ί†ΗjCυŒ²οB{α;όέLw|όΆ9’Ÿ|ή½Ώ―iv;™ύ}μέP·'η„Bω7±sΝΓ 30ΆΜΚ/ŒΕ|=ώŽ(먣»3πύxKλϋš †―1:Άψύ y­sΦπž΄VωΣΜνΪ†υ`ίξzw%½ m~ςfX ϋΎzΏ‡έ1­―:οΦ"πk^_O°©υ2].―_½ˆBΊXΠvΠp Š[›ί²ΑΌη‰Ώ†ΟHK|}‡†νJ&юχ$·OOv}?>*½aχs GځτƒWξSiΦNΏ~’§ν*ό²ΝΏΓ~–ԝμ ΏΌύZm7o―Ѝ£8Ž Vkψρt/e ‡:yjΠ¬Ξϋί—#»Qΐp؝ώ²ωέ€Η[*C{^ΊΉΉΪΗϋwψθΫ7۞wφfLΙ6οΨ™ύz*ΣΨہ½Ίs͍Xήs9Χeζ#¨·JύωκχμӐu™Ϊ»^kΦμ]=Srη=<8nɟˆXΧ›£κύρY±‡ Η«)pίJbΝΜJ=ov»Kό4'WΥ½Έ?;πE|uΘΑ»?§ϋΈξœ(§»ˆog˜₯xΩύτ;6γ#ή³Οδα³mςS߼ٟ)5χδ•ΖO—˜5·―αm—%"5ύΆι!}₯Kή™zΣe\_ΛM5q~₯Β-~*\ ΑLӘ=-,œ•4\―ž_φw,¬}Ώ@ZαΊΤβfΞιF p#"ί…“-α·wϋ<θΕ›ο›Κ¦έa·ώ:4ΐό―nί}—f(Ι{€ύ2λ\σUΏΘ‰Ϋ‘RŠζ΅τڏ]l»_o?Ύ€Ά:0½ί¬λύ*y/ˆ²Ώ§F«;ρ䱨‘ Ζ |ΎΎ$·xˆη7Ρ/lΗΫΎ•Ρψ΅9Κ8βΐ ‚Α9ΪzBw§οNΊHΚIΎϋ₯@Βρeλ~Ϋi„Ϋ;Υ βΚ΅›[τwν,§΄Su˜ ]οΝBγwkΟψInj=<ς|Wέu#Υ“·ΌΒΛηϋ‘ύgΘ/―<΅Ϊ {©ΛNξeα7λ's₯α<€ψzΟIΫ}>Ό― ΟuŠœ&Hέq!urawΤΩTЌjsxFCμ&ΟΘΨτw;9-—±\έΆ¨/ίuCΩ[PΏoΤ'Ζ°νΐtZ*΅»τD̍ -z%μίΤ¨©„Μ½m7£Υ;=e|OcρCΩ΅³όΓu<χςΣ~―Χκ?’™μz‚4§Δ`ΊΡeτX&Κ«ζέΤΡβ ”νχlβθ!P/κι/΄__]ώπΘAœ^ϊ½k°kΩ:w»œψ¦ΈΚ©π€]€Ξœ€Άƒˆ›?— <\―—ΠΈˆ‹™β¨ϋ2ϊο₯hV[D››ν)ŸPώPΧWsκwΓ¦{ύ=7'W ±»ΒηΉ@j†WθA«ο6Ρ\RŠ#)ώC&jΨλ\ΫμV:υJ™gφY-ΰ€Ύ]]ψ₯j™[ΧδwRuάΫ¬φ‘n_ΙΠN^Ώ~ό $Ž›zσ.ύ?–š8™Θαλω£’Ο1Hχ˜ΠΫݍΧΥ!S»ΕέΊ=₯Ίέ&Θ‡4YκÜz/ ύͺ,-Š7ύσΉ‰lρ…―~­ η'χίoπ4Πͺώ˜–vηυαwποœΦνΙ¦YΈχ³ρΤ…Υ\Έ{ρ‡σΡn»ϋždΐ·πΘΨ>τ«f$NZ{G ?tφϋΟ9ωυ,Ρ±LΦ₯ΉΌ3/}HΝΡ]:ροΪΎ7ΐκxΙ߈/e»y>ν΅ό‡§τΠΜ·r@ΨΘ ΨLΜ.hκŽ~ΑJœ‚½Ω-ΛίΎάnv7H^°Αvϊ|,‚Ό«U`žuΪΠω’7£I`({°€9ϋ·2)£wH£{9Σ©'"­ p³79lρa“IλhiΌΈ'–X)²‘eaœωL΄Έ††[-πU€Ρ£ήσΰ%4…tl―¦6@œv‘WrΩ=τQDsΪ‰«ζ»γωίάΎ‘α1ΨΕˆ΄Σ1γ™tL{QL‡ JQήq]ρ~H!»$ͺφΕδ,˜εΚ%YyMωoσΗ9Ÿ½™ΟKΣqΈΚt †y’Ώ,†ΕRXΦΚΦβUPΙŸƒ•2σδHΥlJΕΩ'“!lι¨ΌqΧ­ζήξ%Μβ4Ε‚GΕd¨ % /%‡΅ξeςΪΉ’³–&x•ˆžƒU‹­!“ΓΆΫπΉ-‡ΔCσΝ―cέΝQ΅>€― Ίά?eΘύΟΏDCcωΏ†9«―:ΗΫΊΫμŠΨ½— šzXqrϋuΑŸPGIœQμpl~΄b»ƒžluͺΨ[Η•.ΥΦ μšƒ Ζͺ‘nFsΖmΡΞδdkΦ9(¨βθŒJZΑσGθŒ‡Δ ρLŒ ,™,kb₯ΐŽC”ήήWΛX ‘Ϋΰ²ΆΠž%μΆƒΉ©Q°`Ggά΄γ.Νβ›/™D₯ξk °kJγωBΒ΄”λ@δqΎHb)2šˆC.z—ΗȜOX©Mh0&h%mKϊ|83VfŒRD#‚£§P•P5{idΑ.Θ Ό–LΘ’•֐GX•φ6 §Ρn«Q*σu‚nyβκ(€Ϊ5&¬=MJMD`j«΄‚‰ͺ‚ Ύ,Ÿ Š9Z©H·ΩyšLGέ|Όε&Λ<τΪ™Έβά£Ρί‰ir‡‘Ο?zχlQ₯Φθα’‹¦Fk₯(Ζ²hR)ά0ΰ…Z]1Ϋͺ‘Jf¨χΩBγέ0!ՍΝ݁Χ_½ω‰ζ\’;"™*†HžiΉVRE^uŒ‚LUVΕ.YΥΐ³j˜”ψΒ+©₯[xΈkΚwμΤπϊΑ….Ο™Κ³-xE$¬ΧpΟDJ ξDBbΔγ„’―Sl7η¨ΡΧBZNΣ.{ό3η‘…ρ ™ϋE ΏΖ΅‘ŽœE 9{jΟmΘΫ&kΉΔ. 㑟czΎ@'ε9Œš§&-π¨τθ«;¬Κlξ—±¦IrŒΨuhzΖά‘ύίφΎ3cλΫζτβΏς ˜Βƞ5Ÿxͺ›νΣώγ}]vwΐΤ―?Z6ί‹A`Ήš3 hδXg’C΅QΨ„ a2£!7Fε\hζozΧΏMώ~ϋρzθ8g·ž’Ο„°<­αmpύͺε)Ββ)™ί–a‚«ωGυο[δν}³{*λ’ιͺoη%ξH€υαm{μi·Y4Ά”Μ­θβ:)y2wF“qOaύώώ©g$εΎΆ;½γΡ¨΄ίΌοοYΡυξ}ϋΏv•1#ΎZώηΫόώf™Ο‰Ηΰυ$Έy ,β‘užώΝχŠξN}Ί= wβ/Χ=―·θBF"§qDρDΊΙΉ¦g)v± œ;\ϊ—―Oϊˆbώqέ οΓΗξΰ]t›½ΗΈόν¦Ω$Β=sχzzήβΉζΐΞLΫ3Ή€ω‡σΏίκΊ™όΈKγ፝{ƒΨ9Θ¦81·y Ο8ρ‰`K’ »%O\|"O=Χ2#­‡"ƒό΅Φ³χθΑ'?Mτώ[ΦΧV6φc‚υwηUΒj0qQSα0gω±7΄Σ•?[υV°qϊψžχΞΔΙ΅aΈ‡W»%žž’<;‹;œ±-ϋύgΛ5ι‹aښAZ°…†η^κajnηͺœφ¦ωz»ΩάP‘}†ρ9Έτ;αΞE·ΖB³RŸR8Ρ»Ξ+ψ_؁€ΰŽ”ΚWLΦ½kφΓwn‰η9Š;{'g:'Q:'»\)~;ϊυλϊ»«2ζζEο;άιωbή³;¦@ζτΆ—4³ξœηϋώιΉΧη1K†F Ύ.S_»WΈ·ς£k©§ΦΈ*_.Ί›r€ΠοΝφσ‰λτ:ΗT„άIΔc½Lzšγw0o9lσaΘρψFœβΧ₯}Ι(ύx2tό8ΟΦ η^0ϋΧ <;uΉ7βΠΊ~`£΅£'ό>ϊXμαa’ηΒmMΕΘT«,‘΄υLλc°)) 2'eΈtNΗjδΚ•bcυ!ΰ£b΄uzO46§Τσsέ\&–o{p•sa…Χ\TWΞρκupΑζ\E΄ΙDx0U3ΌvFq%’d)D‘εψJ:i˜Gψ ’D/•F)₯0ΊΒ+‘'š'™΄\«l|±ΥiN ΝθŠj%λΔBΆ½ϋr½|―³Ž9F@±Npυ γίY–$Ή“\)šηɘ·Ρ Η‰q©ΨT¦o΅ w―ό€:ŸKά†‘@ηͺΙdLΝ°+«Χ‡χΊ4η>ε¨h ΆΦYIbΤ\(’—N9λΧ9ΓR²Ην}.’LψΗOΟ—±`₯²2±Œ¦ΦŽΓVδZD`FΡ Sε•―Μω"X)ΙC„΅fF{ƒ7Š2b\»NWHέfB±tγ¬Φ†”mΑσΐθ͍ ŽaaΙWSŠγ‘Kca,œ΅"ˆl –(‚΄Lgα†ΫΨΣϊD^Π½ˆ>-μιζ¨Έξ'»Νv‹·Iλ< ™ ΚsXe‹&ά‰δ1{!jRΜj'˜ΕYΌη+—Φ[SύH'ΐ‰Ί•'n@AλZδ«ybΊΉοl‹x„ˆs—ΰ"φGΫʝ–;a˜­›ΑtVjY<Λ*…ΏW }!kμΫ°€4Οώ£YσξP|ΐο\θL¨ΞĘjζ5x8kPUƒ2€i4"I5γ6Šw΅X^k‚Ϊη"f-”ί\θρΓύƒ]Zσ‘Ϋ‘|Ώ% ,B‘)ΩU_mΘQ΅˜ ήiƘΙUralU©F·«ό\yΏ_¨GΆ`ω @™™€…c'˜Ο1ΑŠG₯΅;ΞΠv›«±9T°\€σωjΨ#Τ.θ’³ρgωœΩ/x j™]wΠ)Ό|xsΙΖ(Χ>z/αΰ3SΨ` ;· ϋΊ aήi Ud_Δτf­Μ±_0½ώ•λδοz]φ&Λγχν―ϋŒFxδΊ"pM ϋΝJύAΫ2Ρ<ΧτBφ^½°yΞΈΎ¦υΘ_ξω:x-χσ‹oζ‘6ηΫ Ν·˜o3ΰuκEΪωώ»f̌±Ή½γζj.γqΧd΅LΤbό…ƒ¦{’πΎ]œΌ€ίΟεψwM,L3~Ϋγ·jΜΏΥ·5^  ΐΪ΄β7«'~Χ= ’Λ#=ΨAŠιΥތήΡ’Δ[;wΊ²?νgΠχΣόΒΌ—²~?υͺ†νσζ Y ^Α“H7z πyΏΧXλŸyΥβ-~>κρΥν׏§\ΩΨ@1˜ΒxŠ‚{AΣr½*Eε,bτ€4ΟZΧ"ˆΠDJ8H˜ŒNJμ?½xΐψ7^ΟD+Γq8ΌΚβ3νL–©TuŽ™ΚͺΟΖWΚηε*ͺTFE° ;NUχΩ's°fιA©¦rfsTL$ό‡i-”Θ±ͺ,BeΕxУSκΝkΛc,ΚVxaΆΧ돷μ§?«)ΓσωφτΊΚ½ UΉ8Ρ'd‡H,7ͺδȍΰ”9ζ4ε^ϋ€]πYV• ΑF'83<Σ΅D°ΐ@~ΡfΩΟ·Cήγ£ίΝ&§nˆNͺ ₯3•ξT’σ–sY$Δ΅B8yˆΚrŸ ž¦Q‹v™Ζϋ΄;]Άδ͟Β‡ΧM[ιq-"kiΈϋxγŽI’„Efέ‘‹β\^~6;οαh"“UB8]‚–…€ΣwΑzεφ°KΖhΓkb!W­Š0PΚ€λ°σ9,ς”ς]γ΅Ώ 3 ήH•ΞNNΧvS@v«ΤBΦM“Ο ‡²νW_ΓΫG  ΄°Λ€ gR“ΩβηΟ ²·²oK/iΩv†–uI«όm9ΫΡLΛcr*c&e,}2ΤΥ?Ά΄Λ4fάtP„¦ͺςυq'ίΘӟδΈω¦3B¬y­½;§l_{‘ασ΅\„οο”ό+α“’ΞΩ·WΣ61Ηπg{ΫA<aΜRί€MD‘Α–J¬ x; œΈ“<ΪRb`±Do•SIόŒI/~Ύl~SE*'b½ΆΌ·JVNέΩ5YΧ³ΪΫϋNn፠γzυο !όΝJ—φT΅ξ…Αβα9:λ₯bΔ―V½VI Xf{l²5p’ͺΐpX[dM%F.μ /²G8Ξ\~zωœ^!…¦λnͺš*νωβΕN*›¨+‡%΄Ζ(ΔWTΠ-OKŸ’ζ šH4,j]Տω΅Ο^βcZ γ˜ΦΫgΫYΎnNr ©ΡVVœO2Q,―ΫΟxͺN)ΐdΈδΥžTγΘ ‘Zi\„·σΠΜtLp‘Β%AθΓv˜>ΥηΛE—υβμ^Λkz9XͺΧΥζPΆ'OϊΙ?φμγHΗυͺi“ϊ―’φMS[“€1SL~Ηm~:‹ΤlOΤόΨαΎ³+`‹›F8]]€:Y–ၝΚEΓ6FͺBfAB­ό¬>—` w‰ŠUα½`7‡G9]Τ?y—Ι‘·φf2rm>qŽβz„œ‹SΣG‘ytUiε2”§πjwšk“²9ÌuUΐδ0–2ε²B²ψμ7vŒRc³ΫΕ^ ŽμΙδ6¬6ύ Xlk[N?„Βΰ+-ZK^dζPX/#O$œΑ’ΚδYI,η ‡‘©[£Ύ, WΩ³Ιm0»ΰ†ΤJY‰ ’ΐ³–š™O%!Π™Xš5Ο‹q/ΰ_³Υ*‹¬6Ο‘σE§«ώ–Φ»^W{:,3,BΡVκ‚I ΊVN&!‰Ρ ₯ΐK91DΨΡQf΄ά›„ΦσΟIZ5kF–5i#(‹‰&’SόΧ- ΪPωΜ5Λ)ΰ›Tƒ(Μ"ΰ*‚ϊN’2 R[σfBwŠηοeώ)ΌΧ΅Ώ:Q 7δ›;{• k™ήΣ7T’yσ8°™=ρΛί²Δqƒ ²D4—hcZEι"―@q"Δ œΖ Feh"γŽΎΜ ft^GφΰŽK|ΉΊ΅n,§Ψ“B»t«SUVγΠ²2Κn…Dx"ύŒ D6μπ CpΏγ,Τ6GI+l*$Ί$Α'`Μ,l₯»‹/η 0Λ΅ˆΙqκ€JJ›`c`&©¬3gg€½…h]£ oδϊο\ςeJ[χ-Ν=’ρ0ψ+OpUž"Βd₯)΄ΠJcm†„²f‡+}-©1Ή(7Ώ,?½l7o›ΑΠό0Jv»λ"MαϋόtŽΘr^ݩϐw¬w-}S'ΆΪo"iψΓο- Ν±p"i#«oLE0£eΆ1S₯<^ͺ1ΠXCΈŸ„ΦVpΞ"ε˜Fλn·₯¬F²>€―»BΚ"βΚanœ’ΥGW’ZXτNΰω5P·@ Zi,Β3ΕGŸ<§£,Λ_2«’3B°$ Γ†[›X₯έHς)$[bΙή#δj<΄ ˆŒΊVVvη°ΏΓUn{¨¬qKŒκ;ύŽ^fjρš#*6’”ΈT4š‘ &lŒW@J 9eŠΤœ5w˜S58B)ŒJξ¦4tUjtετΌωmGψmΏyόμ—΅-‚^Ζ`dLΥ 6ψ‚ύΐΑc¨Ν&i„–\…J₯π&:ΉH³¦τ’4j‡{lςΙ1*³;<βΫΡδœ/―­§rηI «όΦ&iZ½Ώ•ύœœ|§:Π«wYO颏νϊ/ρO1­°§SΕΣnΦΏϊψjωƒ8$jz’Αδ yH‰― \‚Μ::r œΧΚL_ΦN ‘s΄kiB™9o wοiσVWΟsv}½ύx‚σz)“l\͎Q%oy6š8•Ο'*DοaέΕοb©Ž%¦byφΪ£TJ¬x 3Q> ‹Eψ£±υal’ Ѝ-’ΰdαΔ1ώό­ζ{Ϊ{=»Rž~οΪ]δσF½P“ΚΎ ΰ§§¦Šώiχ~5νcΦ‡Ή jύ‘χLαθ+Έ=Έθάuέ­ VKKJb").αq₯π5yÁA½@δojf)@›^bΐ/μΌ‰άΙdΉ4HLgςj·[½Φα°οΟ§nγήHΕ±¨η[ΤκKΫ«3‘κυf-MBΊFrLˆθŒŒ’{`bƒ}³)ια  |zFΡ‘Αe#€,4,j?eΰŽ5)C ¬Ac[ρω^^βGηΈβ¬ͺ<ΗXy@±D}ΐΙ€p«g>§*’υ,ΰDΨ”p0Υ9g1ώόoy‰ό­„Κδ‚`¬ϊbl`Ιλb((Σ’ΖκτΘ¨$ΰՁ[§΄Ζ9;`pΟG96ϋτ#εώόsφ€Βvmr)4Ξ’f[2˜ΗZΘ’Χb2“Ζ)Qda(5ΐWθΆChΙ“Ξ*ρ±ΒΎ‘RΛχ@Ε/•ΓΣ₯Κγ;€ “P^3' 7 kBΔ_#Beͺ§¨< ˜8zχΤfμ>Χ^†Cέ‘FT—άeYζ1h«²FW*"–Ρ*jš‡ΊΨ=όs Υ7ΕέΤV£2ΒD¨ΧΈŒΰ+‡3’ΗgώΡό‘Ζ¬θϋV*`95«RE”΅@„L„c)…Ε’ͺΠΝε«u‚Κθ’ΡEΊj½€ΛΗ„σ7³Vκ >±Rͺ5«Όκ]œ-}%―|ήΣ(H,$+SΒ΅ΒFdΛLG2ΥZmιT„V Wlz?—·²₯^ρν6|&8ͺΣΰ’ύΊό%Ž;£jEεθ%?ύB Φϊ' $“c@Z½Z$άu¨Y$%Π…*P* E, Ό%<‚ƒ‘7©ρ•e,ο߀֎øSγEΓ©fΉ@@]5iNOŠΰ‹ΌJICxζ’Οi57I»C,όμZ˜ΞS}ι΄νς0€n7μf₯ ,,?Ι*p–©PŽΟςŒ0ΤHΖ³ DhΑ, *πœΕ4R€8ΈMfΩmj2<%χ6hiuX?կž•`³AΨdh~}*8¦ΐΓέ$•α[«E„’ρΆƒί *Α–¨1J‰νΊη—³9SΘ²¦Yλ†:© ‘Ν`+@Χl•‹YZ¦θΒ.ζΒaν*―4SI°υΎέ8fWω±ž ΝΓω^πμoϋsNχ|Ț·β~Ι§Dw`œK#Drv*Ώχ%rΖ`ΊΙΐG!Β‘B7ΓΐΘέζb°#Wλ4XγžΎYθ‘}Ά“užάΡ\pŽξΛ―°ώ,ΟύιmGJϊ₯οΑL4Φ0N%e:yΟ€δΔBB6€ ŠΙ’GŒ˜²IΚγC!ω”$ 'Gκε'«K₯χŸΟ}X²|f*ΞL@#«DŒγ‘₯žW΄'h BβΰΖκUΛγ,ΰʈϊߗ·ππ{%ΤΔ£"W€­…G` „˜†z9•£ΦQŠœ,0ˆv>‘Ao89z6Ύ€ύK5·|i 9W<At€ξ\o ΡⱉXIHS²„ΕDψ…/<>nt‘BiΟGΏhφπωβυY\EŒ΅ώδ…†.kvπ€* ˆΞ*&ΔΞQ=΅³:‘ͺe9ί~a~yφ`Pm€f€=>,'ͺ•₯ΖS\d.?1š΄ΐ’‘β ΗtJt4ΊˆΝͺŸ_œ@-0ΔnΞ!r1Abrρ¬§ φ=“BωΒ$u ‡Œ°°jμ±XŒ{φίΔ(G›}Ο-­ΘΎRr“fΦ iκΒ*ΩΐxBpΝΜ2…Έ‘(š cλ ΰΑυ‘LMNψΧΨϊ~–νS}{8›šΟšΒ&γ"H` (@°…Y›9|ΝctDv$‹”πΘΪE‹ƒ`•)ŒžΟaθι5H‹‹—c.Ua%όΎŠΖH>6ψΘzžLΘI[΄΄1 !2΅RΖ(ΰ$©5=|4;šͺtδΪiž9μμwxΫ?Ό=§β‚7Πyž2t'†uΉθ€5<"lά"χPΧ·–ͺRη,•q„χΝ!8>_³N,u·κ'ΊΗ¦€,|γ‘Μ΄ΖΑ‰'‹PQAΥυ–FyDε ±*qGd> "`ΛͺΝhξ1{IS“M>Υΐ ζΨl²ΦΛR«υ*S7„@Hl=_™”㄃•PΐFˆό)aD’ΌŽ―ιυ)βο=—·žΙ΄rω| eμh– uΗΑΠL«†>ΕZ*ƒ*:xbeYpΘ< Γ %s³ŸWΏΠ^Σ™qυ_·Χˆž~β·?~B‹aL’’KΑu’ζH“eΠγΕs]Y…έ’4UˆΘ9…#"$Ό›l©γˆ―οa½™S€q{@μΥΎP…lΙ37qΈΘ^ύS,žΚEI π©},Ρ¬4$l=M‹QπΕpY‘$€ ˜ΔAδ¬!W―ζ Σνh”^oONν©Η7ηlLŸΎχ!²%‹• φ])Y)΄¨9*ξ‹ΌΠ2nΌδI&™£Μ’»8Mš‘ΙήΥ g€._R‹™dφ6 rD=d;2ό½•?ϋŽ_!PύτN^ΆdD“‰žhoLšZrΡa9swk`ώ}ΰ—Ώy ƒYΔ‡J4ΤC›Ν³9J˜ο„³n&ES(±λ…ΠŒKΔB²(άΜN#ZΥK#žAεΐ{­γΐ»ΏOω/«ίEΧnF.ργωο8ˆ,ΌΒΈš ‰WεΔ1AΘΤΨ¦1X1Ÿ”“ΜȌΰ‡Q'Š7T², ·΄γœŸUcωΩK$tϊΘψξφκ"{}ϊδΓw»•YΩ9N ”ΑέIγuaBd‹ΨΐχUIΦ(€DYF·Ί%$Οζ•F, gIοί΅μL[οžνThΡ=Ή[‡ΤM~=δ€œ΄˜€"(!’%ZκŁVΨl0² €·)Λ= +¦₯Υ6d;’69oM_ϋ«§tπΰ-yΔN²Φ=ΰœ3ΏuΜ}Ύ€ψ‡Νe4ΌIΪ2·1ϋΡ‡ώΔΓ…ΦNω@§δ“y/Zάf¨ˆ‚ύ(YΈδ½(‹ρVΈYQDρ– –Ιžw*·φρr2ίΝ"”„™¦M)X!¦₯Α:ζš4‚μd4 Ο=b?ΔΊYΓK–ΎΉ›}Ϊκ±0bŽΎLKψEromπι“ΰΰE[oMqΤΘΚihvA(š e£ρœ‘V4PΊBL\ΣψmΫΜ;£»λ€ΩeΟΏΗΡ`£YΉ΅.ύψΩφ­[μζ˜ko(έz’X‰Iψ\•Τ O,^•dšξ)ƒ ΪD§KΕΡ©}0LVf…R•Gζ%ŸoF—ΦOι«Ε“Z™Κ…’°Τaν2υTX”6 4ρΪM—²ΙZ₯ŽΌfW–ƒͺαψ£9”ρuK₯z8μβ“ΜY¦qD°XŽ1Ybpάόr`.‰”Θ;eθ(δΒG‰Kšρ­cQŽ 1+·_.QΔtμΙς Ρι3ΔE ’’)MΑ –αr˜W©T[p²)Ψ „I&V0wt‹Y†˜3cυ₯ωΖB›‘»ώrχυ‚q‘‰ΡՉe’ίVNWι"1Ν₯ͺ7 r\:Ί‘Ί$!νˆΰή σΑϋ»MϊYz|ωl³’6&λ­ ₯b©xN³ΖJnςΛ<—¬ 1έ*E&˜)‰§€S֎gφeJ——Οχervͺšμ°˜­Ί9 xoq ήd~i“β΄Ύ;ώζγ(’Ώƒ–Nc.ω™φκΌύO”kšqL‡Ο=ό¬44³Κ2cIε”"Uo3(U)ŽλBγZ₯pάc‹ld¬axΣΤκ₯DrŒφξœN;³Tφužwη©—€9;}Œ»—ΐηžηΠιΕϋf½ξΩ{ωΟεg²šˆh₯/½―•ZrCΤ<Ϊh¦W4ΐ]Άό|ΛJ2©8β²ΪΡΐ=ES_‘6WΌE$ƒΣ€hrAC8¨ιN lπdέ„¬ή 8§DφΡG‡8₯A€™8{x)|œDΔ ¨μ©Š₯ΒωΥ$§Νψ1:Ό(”‰D2Suv€ό€­(ΊΊu#Υ{Ϋ_₯΅ŠΏdƒOΨϋλ0P―Ή›.ΫΝκίQΝgxύψσψΡΌ6{&\ΜeΐΜfƒ’Q:1KΒ!S’$Yr%-UΧML£ΪΰŸΔG.~Zρ:)Ε·MΓ[Ρ"›Μί!M˜?χ΄Αέ‘Ύ‹S&ZxΜ)ΓΈΠ+ψž[e₯α1[WͺŽΥ Rw₯3£ρΝ&@ˆαΖ‡γΓ8wΎM/ςΗH“Ηβƒ,ΰ[Οh3Dͺ ”UςbUΠθΌ ΐWΣΕΉ`47aw37_l^Ζ&θLŒ5Υ]§Ζ'½LΌΛ#hX M‘€υ€?°Ϊ h«Τk€mˆΐP…ΥŠm*Ά" e<9‡ˆΪH†στ΄O»Po¬σπ‘^ˆύΈΕr —"|΄tœT,λΉ*cψF’ΈηjPYHžc"Ύ+αLui:,=,iͺŸφό‰ή„nφΈEΓ«y¨Μ6U"ΓUΆP{y8ν|TH&ft"ˆ˜ΰ₯€€FoWΖS ­ΙJγΏωοώϋŸώηγώ/Β cargo-0.86.0/benches/workspaces/tikv.tgz000064400000000000000000001266741046102023000163250ustar 00000000000000‹tikv.tarμ½Y“γZr&¨ηόaΡ/’)™yvm£™nυØl^ΪΚτ’ΊC;k+Ή‰KfΖλ>ξHb'H‚ΑΘ{‘*U±ηχΟ·Οw³oίΏ~±zσ²š~·ΫιlV_ώΎ]-aΈώ)!·γ?Fό1 %˜„Ώ) ΆύΓ;όΫowzσττί§§§η—ΩξωΏ>αŸπcϋͺ)όz6$α±eŽΖŒI*BB½2ά'DDqσΐL,ΧαωszήΣσΖ/V;§ΎξvλνύϊϋΊ7_μjρu‡σ λŽώίxΚσZο^aΎα΄Γ“ž?ύοO0ώ{ηιΈΐ­WKΏάmΏΪωjοΎκΫ―eΒ—έj1ΏσϊgŠDΥυΟ%ΖυώΓω΅_:Ώ΄3Ώύν“ήΎ-νd·Ρ³έΣΏ<=“/τω“yΫω-ώ’_Θσ§ gσl—€ϋέ~“ν$_ψσ'\ψΩ†ΗΎΎ­ύ&ΏŽΘNvσόxωόi³ίv«©]m|~M…η6o<<Ψn¦η ;·Όiγn[άΊί€g¦Ος©τ¦_yώΫ'ηƒήΟw“ΰυαM‚žoύ'Nxξ—/_kηζo=ΩοfσŽK6όΗσlυόΫ§ο~³­–ΗΟUΉξΛfmg«ΎW\Α™Ϋν|ς.ίΟU―ŸΤνϋz_©γ/Ω°7Θουlωbυϊk~/¨2ͺΧΟαΫ&RιQ·~ƒ8ϋέΓmφv·­>k6\•Λmη«—Κ…ϊηtξΏϋω¦¨υϟQλΜ½ήϊιi—σfRΎkψΪxωΙΛ|e4 bϋ‹›χΫ³νλΧΒ Ωλoόw<ΙΙ„…8φΒ£₯7‚'I‚Ί‘H¨"˜@#γQzgZ{"”ΕΣ3“ͺ0/α?Η3κΧZ}Γ©Tϊz»ΩΒ—Ώ ΕEˆg~Ÿ”ε@uaηC»XΩoε;άΰψΘι9bφabWΞ[Έ'JυjΆάeO‚?ΏžΆΑpΖv—ž‘Ο³―…ν8Ϊ™zͺl<~…Žτš…§¨^Άψ€Ε+WΆ—.^~©O±Φφ›~ρΏ}ςnΆ;Μ5BγηOK½HEhηOλ½™Γ :bi€3ακνΖ~ΟΜ—ΝφήψώΥτΏ|Τ3zΏόHFΌ6ώ$ΗψΟn¬AoOθ―ρόΟ#ό›λίί@₯λέΜfΪφƒwώˆΣ_ ‘7³ο§»Χlί¬6Η-UpΆšΟ½E TΠx…ν η,ν~³_o€– •7ύΤhΓ‰΅‹ϋεΛlι§PΫ~W-žΡvΉf_v½μ”ϊρkNQ/υΌΪρψϊ₯~ξόf©η0« |Œ©Ή^mv=―[9ωkvrAΟζ€ίΆ;ΏθwαΒ 8ξίz>ωξhΠξτΗF―Αf+―ΒβŽΪY«εη),ͺ0{)VΪS;oν¦v>Το‹―_h³Zψέ«ίoϋŽάrφςΊ›ΏUŒ²Ί£CΧσ•N|<Ρσυ«nΌ žkυxxέ‚ρ Έf»·~Χ9=ΪY»™3ΣάϋΝΜΖΕb΅μχk§5p½m·fσOΟη+ϋ[ωΆ‡Ν·ŒΦβΟεtχΆφ=εΡρπΪ…ήτnύΫ'³ΡK›Ό(ϊ΄}άSЧ„PΥ…«Ήl,Α° °Fm€xΥM­— X/ι,nQe_G=Ξx±λgΐQΗ3ς&ξ l€η–Ž―]UΝΑß;-n4\=˜ΒlΨNRβΜΡΠMίώψ#{±ŠžLΙF»_€σπ΄ϋ°v.όbCΊεtDi36«^γ° vxUm±ΝwΆ4xp[Υ1Pa-ϋ2@UΫyΔG΅=-T9,ΓΥ­¨ΗkۚGW݁κ i[ͺ"ͺ;2Ώξ1©ˆ²&—J?7 ξ8ˆƒκŽj;οšiΟΚ¬iσξΣ¨Vχ—ΆΊ³}l+Gž†·²γ0ΒΥΝ­n§8Wφ†Ίaσq΄+ϋŠ^sd5Œyƒ³λXuπ+ϋ*γ_φžm—UIpΨ‚;·!?`ΣΞV?lΑEa·ΦΛYρ°ΪΎκ Ήtl9ε ;ϋ9ό2Κ‡φωυπ ηό»Gύ?}δkv /ΰΉψ/U’:ώ‚γίj»5^/Žx»ΥΗWυκ ΰΓΛ8]€Άρj₯±ίέf_ Ir_Ÿ=½ιΧ«άΩ›WƒscL΄dχΆqοa-WR 0 ­δ>l†¦`b³_.ΑFΔWBUΓ¦g_§»0['.+λΞ›ŽΝ“έονΡ6δTςΌυ.½λYYwA]5΅ΓšΛηRqτQ΅Ώό\£•’£όΔψγβ|gύOiΣψω?ˆ€D_mœΟ1{ώb Ι°A–usšj0 7yΤζΌ½ι™zΦUT΅m™φ’„džΛ% ΧϊεTΰ-ΙιͺΊ=ίΉ§ώMυοŸLώύΟGω˜ρ?FΓCgωί„¬ηπ=@‡Ÿ―:•σ)…½N—φQ+…œ‹Nε2& >nύ₯Ι#ΡΈώ3ώυψΧ­zΰœύ_‰ΗγώςΏθb\λΝ·Ωςe:_œΑu…pΜœlΏΝΦ ΗwΕςoœ]‰"όLψρ2™5Χ ©ͺ¨έ W*ΚBγ‰i¬σmi?N&JXνdH’ͺΉ•[zΕBΪA«*ΎΔΌ „ήόν‡%GsσCΙ[qΐϊ_Κhδ}ΜψΓ2Ά~»]m¦λωώeΆœκυμ6pnό©ΩŠώχΡf?›»*α |;ν¦ΗjŽk˜"…ώ‚p~ Ϊp}ΠE•ρ„Κ/»@Xmž,άv΅x*LΑ§l nΣݝύΫΏyξR%MSw΄/‡X7©€+δΏβlΜxΔψΓβήΌ₯«tΈ ΰ™ρηRπΊύOGωϋ―½,‡ΖμΖrvΰ MχΧ‹ΖΪrˆ:ΙδL£i²‘†¬GΎQ1N75ιG¦ξ|8«ζv—Φ|τ!ΧΌwζΥΥUa…bkωώΜ οM\ΨFs_xΧ“μ~5οΑCλ$ƒπΖ¨ ¨φύ V ΠΏ’αξ’όΐKY)ꩃ71Ά]‘wxŽώ’Σκ’~y_Uώ, ΰώ―cΒ#ώ{δψημ‡·›ηπ?!¬ζγ#ΧGΑ-Ψύ<ψθjύ£ 0WιΎΚdΙΗΆ$·4r:^§Υfύ•-‘.Eρω3Xώή`{μΤti§¦ο ΧΙl9;4KK Τ΄W¬‹F†±2Υu™υΉϊηVθ*ŽΔf@}Ϊ0TΗ­`³ SήZ§’ΏJΟΦOε—v`ΟΫ«eN<=4ήC©γΏΫπίνfΐ5ρ_¦Fώ·ΗŒjާ… οΔK•Puώ_1βwΗΓ{·οήrt~¬_΄σΚ΅υC]~Α@ΦDπ2Λ9ο_;jαDΉ’§€=Qα/Λ'S/ΦsŸ& <ε½!ž²'Ϊ½κέ“[Αh-W»W$ύ1ϋέSF@ΤNRφ±­Sώ?’5b£όœώΟϊ«Όώ,ͺΧ°hΤπ•ς΅{κ–XξS»ήgρ~<ΕΚΩ>Aψ³l}m΄ύ¨YΫω^/υAχN4Ί?φž6ζ?OkFBVyŠΒ$Γr†¬,ΛςΧθ­;SX‘:σλΦj+€g£?χWm½Ψέ*±œ΄0TžA‰3ŸBEΜεjƒωφ[ζ….ΡYο`΄μp#w.ύ{λ `Μ ‘χΠε\>g]ΪfnHkιlc·my¬3fΗ~ώλ"‡ξθΊ~4ώ ύΗؘϋΐρΗ΅χβ`¬Ιώ§£ύχϋ―‘»r“U“Ί‡.2jrWWσεn’YΏ§ΝυΎΈπFζς?oζΚͺ3ςαχκύ‡νδΫ*/|ŸΙ·ο'¦θڞ%tyΒ₯Άσ}mg–x©£2|…uU7>vγ΅y¬«.ν§-Ψΰσ²{‘·ΨX;,ΛƒΜηO+°‰7ωAΫΟi ή)μΟb8,ύ²„w†GI%Oζrz=8ͺςWyγ7ΑlO΅šΙ±Ρu₯όίΘώ ρ?‘κχβ’i­G΅ώŸϊϊΏ‰e©Ζ}ςj9?ΫχŠί%3εκNse₯G澍πβ.Ά= ή‚ŸoTΘXώ?”EE£ύˆρO™©κ$ _σ¨ΓΟ‹°Αωώ/Υψ£#στ—fφΧίͺ$*-D»½€iδΌΏθϊΏH7\.aύ‹?DάωΝRΟ§yλVΰYώ_δϊ­ΨtμωϋO/ί^W?ŽΆJ™θ·“­χΐλz»ίei€₯Ox“•Yͺ\ikJd²ϋέkΈ£Sx³ΙvΏΖb“ίjc%M“^©+λΰŽ¬Ή}θroΆ³;ίώύνnΠσ•vpδ™G‹†΅X―Χοƒ ωΐv]ο·―= ϊ¦mηγάΏ’ϋχ|“'<3_£₯ΣQκέΉε’ϊχcu«‘ Χiήredό‹υlοΔC£†ϊo*Ζϊοψ:zΉ¦x(Ηκqή²vͺXŒς‚Ί;j5ΩΉjJšZGιΝ7@‘ΣωjwR`g™e;š»v‘Δφδ‚}dQΠ[‹ωΔπeΙ/‘«›ƒs@$>S–φέ¬Χ£μ)cνdΆΪ.W«Μz‚ίΟfH_@gtcož’_ξ|Φ[ πdOWψEΖΝrσoΟUoʁ9[Λ§λ’εσίO‡ύοΏWξsρψ3Uγ'‚γψψΕ91u¦ήι£SΊ1ΛΏdύΪ)Κν¦ήu=d$ΜΓ±(δAλ°r!δ?αJŒλ]Η?Ϋ;θsφ¨ϋκψ32φψςΎ+°«6y³šαΰΜY#ί¦¨#§'ήBΝAύ2t\-έΰR–Υ&K‘φ7p£Ά\mΨv Έ¬'ω²Υκψ―Ÿό\‘αr”ο:ώψ_~3Ρa>487ώRΥυΏ€γψΏ»ώRΤ=υr΅b-ήσΌβ¬έͺ‹J0›ΦΗpυ|ώΛΥβ~ϋ1[ΊΥνߞισSΎGoμkΊοg¬¦JΐŠs€U˜γ©~ύ¬‘BŽωΏΧΥςεeX‡ΰYω/Dgδε€ς8­/Φ] &揷Ƀ”_Dτ±νͺŽυPώ—hδ{ΜψÈg½ŸόυώΏ Ηρ€ο8ϊ“νΫ‘ΆΏ!1ύ«'ŽΰOβ0λX•lΜz·ρ/ΈΚ₯N:Ξυ‘5ώ/ΚΕ(!±ώι~Ež?½Ύ­ύζP‹“œμY€²‰‘%κ¬-Χw^XBy§Κΐ{ΧΤύω8ApRΌΨjώ£ήΎ-νd_xΆΦ›]-’ τ»cnb΅Tνj ΣRΤXΟsAH±½&§­΄ζΖπbZ;F¨ϊ8'π5ψOŒόίΩr·š¦?ߏH^ΗjΔοοΌ#Λ‡εoΏRwwφFnQμ΅&j½\Ϊϊ·«χ¦^gύ4ψi±Š|”Uω`ϘρˆρζίΆοœCi½ώƒΙΡσO9α 7Οφωύ˜ύtί³ ²NΣ«έ°ξƒA<7zPxŒ”ώΏΎόω_r¬{Θψ…κP8ΰάψsVγœŽώŸGΔόΟ#§ΓAd€X€ΙqŒB wŽΌ:Χhΰσ:₯¬εG+υ=Χ@zΰšϊ0Ζυ€ρOγ\S€έ˜λέ@=@―‘2νΘμϋ4Yh»Y±Όδσ?χ«o.άΎ-+Υ°Οθ"ύΟέFOrŸ0r4ζ•fŸ΄Ÿτ/OΗQώΏχϊD\#Ηώ_ΏXmή²΄”i*n7ΞςΏHQο-Fωω»΄ΏJΚΧ'έσθ6ϊ0λV%pMEΖυˆρ/qδ:[AkωBŒύή_ώ—9/§εdΑ{σ΅i]Q gφΚc0©šk™^ Ώϊρ@œ„Η΄γ>J₯Β9F%XΓ8€Α#ΧG¦υ~ΉR8λ‘Q΅3‘Ρ˜χλωj~΄±šΝ(Γ?ΒϊΏX)\ѝH>GŒ)EεύκΏiέΟ#:ΖίEώŸ—ΕΕ¬₯ΡώηYΝUjτ’A`ΐ9ώGψZώG4φ~„―ζβ¨–ϋΕΤχΫά2/φsωΝ2 ήδ‹ψε8‡m }5WQν*“μ\αΕ(œ=zΑnρiέƒ?ͺFΥξβΉ€να°ι+r{€XόΥT‘T§ηFڈŠΞ£ΜH―ΙT#ώ{Ψψow«·ψ/₯„7ΔΗόŸGΰ?3Ϋ…Ή~ΩζΘ Em*U$§αΛYψq܏EC[γυ"Ψ ιS8 2ƒ„pH9ΞΌe­1η šΤ­r 17…‘σˆλι τ‰½›„ωJο2H’Rδš‡'Ω&πs“]'-,¨q^ΐrωkdαξ³X7Ϋψc–αŠ/΅]θωό»·Η X_‹f6nΰ-1ρΘl°H;tΐuϊa—βƒΔΦγΪύfΏή .AΑoϊ=IΓ‰ &έΌ₯ή©ΎφΐαψVλ"υx]b[ [ςξ¦Κ€ 8¦—L‰Β χ’Ϊo˜Ί'~Ι~OY€(­Ϊyώ­η dΌdcΚΕ—†κΞɍ…Έ™ΏΗΘbΏ1+„h‡ΟI¦3ŽϊθžόΉ©ΧχZ~»Ϊop¬<θI˜”₯ρ¨νMώνv7Ψέμϊ  β „ZχΎΎ„ž-ο?X’Ξ†]ΦΓc²{έxνZϊgά#sgΏŸΉκC!ΨJCŠ’Ίμγ†αΏ9χ§NυyΒS§Ι₯εkvZS)μp€IΩατŒKnVφΫe&=£ρ’½ΨNkg!š^Ύk§•½qiЉώ‘OΒq_»ž‡½ΨuΫaΨά€Σ·‡n/x”ά™Ί€ŸΗ™kΎίxΑ"J―΅‡©γζκ!θΪΆ«Ρο؞vV`―ϊ%‘'τJώϋΟ…¬ZξZq(jNϚм1Ε KO0ψ_juΘͺ­wšG­rTeΰZφΆΉk;SςΚ#XυθζƒxS«κhVό*Zs7Žι©€υΑ­>vy4ϋTZΠ©ψ*9νqxκ‡TΟΛAχ™'i›3 €g”ζΨVm΅Ι€Θ__ύΣ_gφοOΙ6>7ψΣη3λ—ΫΤkπΈΘ«Ÿ€Ι&E7{κΪμγΏσώίηŽό°ηί½›ξ†kqfόeDλρ*FόuΧ}gEX‘.ΊΙ-Ÿͺ£;₯ζ\?Ϋ[βz¦φ ΛπC~(bΏOίίΉ8œ›0UΔύ^΅ξΖΉΑ²ƒzχ}_W\Υ—ZH­­lsΕUyΪjQ̏μnΊaU69.\žεsΪ/{ΑŒ9ή|1œO8«sμΫχλ S¬Xςdύέ/ROτiχa μ\ψΕ€\!’Qڌ‡ΝͺΧ8lA ΨΕΪ€S,ίyΨΰG»¨H²ΥΥδ:YE ώ¦ή¦.Ό›ςϊ(Ώμςά΄8{Jί’ΑOs‘‹¦Ÿ‡¬#Γp»¬ΞŸΓάΉ-Lψ[=ώ°₯έ”v‘λ§~ΚΙηΣ+)ςdˆέΣ_Σe εΈ&’Ρώ”ύ_Šΰ8W‘r=WψŸ9νo7Ωό 1μ‘ΕeνώsλΡT?’l0*Qύ=ί–ZύgΣςz€έ ΰ9I^Ί2ŽΆΩ yωW¦΄‰Us¬ͺzO’’<έΎ/l>Ϊ _ϋ£₯JͺΣ™šπμοι _ϋoΟ0χ?φ\-šF:άΩ2¬~;—!r8p‚Ξ|6HΚd°T«D$ΚDά0eΈ%±Q>ΦΑr«”ΤRω‡ΫΞλΫQΰ5ύX4βΏGŒ‘ηω?8‰κόjμτόΧ»ΎαοΫJ‡[Ήϊ†KωΏ7Œ»Ν΅ΫΓ‰zumι1₯°{ΨΎ¦ς₯ϋ²~έXz EŒι*ο/Μ!Ψ(3ώ›οΓ²­${}WƟŽυŸρΌnVΛΥΡ`ηz[͍u]•›₯ܐ’Oh9ΛwЌKd±ήΝίc€»³~Τ«)‹½’Ύη]Λ‘ΝQ4”RΪoϋuί"J<Άw\Οά|8πOV{9diΔΐAε?cYηέœcEζΕ$Ψ¨*rΈΔ₯ƒHτ₯Μ½²‘ ρΝήΙ=ΝαΡα‹1ΗD­»'j}τ"ΛΗWJ‹n¬ΜVΫεj΅>%C6>W υjP‘£Z―νΨ¬dορ9KKx$ϋκν·b PŠ<Ύw]šΪ”AΟZB‘³W• VΏ_s±`φΘΓΆUΩ΅SΫχ―/&“«J|u§ώ=xφ›* S šA•Ν‚++ζBsύαq: YžΨ] ΧžΠviαβΐyn “ε²ΎΓ΅;ψƒ₯Ώ©aΜάSC€ΓΗ™½dάg¬.δί€ήίλόΏDύί2ώΕr큼ΐηκ­σ?s9ς?>$―JζΧάτνŠ&owηxϋ3ΈύOX— ΅¦ˆL@ƒ^ζX­œάζ^½•\ΕΞΝΜΫΙz΅šΧXγξΕF7ΊC‡ξΪΧΟU8&t~87SZ-Ψΐευύ>)λί‡gυΊ¦qHΚ©AλχΪψ«ZΔ}—s¬σŒΜE–ύ0qoτ{œ[:Ύv”₯\?Λ―uzΛγμϊg>έΑ•Υφ‚C»΅ξLeΥ™uO—OΗχ»›ϋηόQ=sΨJRγφšμ΄ς\SΗΙh=bόS΅”»šί‰‡³HΥλ?٘υϋ_‰ƒύŸΩjZΧΑσ?½έοV›γŽR–V#kH»κ‘]5T‚ΤmL?ύύ_ΥBυΜλ;ΫΗUž3tΝ΄Πp³ΊΈšΉŸ³½–zζο}-šμˆζ({Oΐίβ" άώ폧»ƒ­Χbδžχο‡— πc,ϋx4ώ{$‘Ρˆ5ώv…υΜ~»] <‡E½»dtΰ*Ϊ―΄zύEθ9‡ŠΎ ΒΜΥζ%θμŒ>°σΒ^$­xτΞmN>؝­ΝMhεA`τU­(ͺ·‰Fy›§Ί0);z6d“λΚ¦ύ!5 Γ y—΅phσ˜wΈ¦+―½?Βιϋ]έCαR؟Λώوm „Ε—Ό0‘°υΤΛψτͺΐf4/ϊαΏŒ€kψ_¨δ#ώ{Τψ―έ ΰηψXCώ'ω‚»ΨώFнαΚ5ΗbΏ›™ρ.ΖϋWςκ C+έU@Τ“…g`~η3%*70χδJd„XΏώ²δšϊFΗό‡©τmxfό wΝ―FώΏGΰ?Œό€°αϊ`„ξ&τi`οω6[M0Eysδ ϊuXsώdT7₯L”‘†ζŽuCY¬=U‰₯Β—Ζ΄2OWO7΅ϊ5{cέ΅₯5Λi0:“+Β>—d<=”.δƒ0΄Zζ‡ι8ΏCβρa™8ΊœΕρ»+GKΤλτά—…ΌZΞ»"ή5ΆόέdβΊ&O±1ώχ°ρ˜δ\Yο γπΤω?~1Δ·ύ―*vΏΊΔ•ΈΌ/o©+Ύ h^†'KPΘω­έΜΦ8„’μιΥΟΡ›ςV›§r-n7pϊπu»ο'Σ‰‹±ΣγΖ?O·{ώ/&H#γψ? gψ”Ÿ_&%g0—φP ⨑ƒ€²·Έ[½|­ΎΒŠΕϋNΎΎvY—·«ΛyVGψΌ*OqEχpή―cΜθϋΊN?…ΙΡώΨψ§`Έ πsψO2QΛR|δύω?₯lŸRβώ˜ΞΆZΫγΑυ\žΩΒ·E£ok:pžΝ―ž˜>¦D<2Ÿό1Ρ+ψ/#+l†Ψd²χ‰X_‘ν~ηŒφlάX`²]—~Mώ·T#Γ»?ϊv؞―ύǟJ*jωίDFcόχ1ρΏ ί…ωί €C½έϊΝn{Μή^c/±c#€tπσ ²ΤΫ΅Ζ*Έ³―“Kxρ ’―xς =^OΌ¬έλι΄^πχβ§ικŸpa‚βU{v.m>ϋ‘IβΩυ'―^Οw―}󑓏“,^ψŒyγ«εv΅ ³—‹Η·tφ­χΒu?Xzz±Γg«ώOhyEτΛΛζβOY9(Ύ’ζ; M]Τ|—£γ1fάν-7:^€ϋNλΝm7Yon5έjL—κΓσ2ŸφήΝ,4¨Υω²„ωΰ+ΈΚζ˜•eΑΜυ›"ωξqΛΔχ“dJu?a.½ΞΒξxBΦΆιοΫCeDsˌͺζ ˆ¦₯€r―ΛsΛJψ¦šfΦ|υKRΝκ—/fU― ρsρN]Π•{^ƒ±*—x…yΌι ³6ϋeΪ:¦ΪK\4^Ί.^αyOiy•«₯ΡΓιλjυ­νUOG4_ mΰ[£?žοo<Ή»Ήw₯CxCŸοΚε.sΧ–ϊ3=·Υ«^άΪ¦₯σC{ƒ›qϋ₯³ΘλΫvννΤu7(Ρ{΅έeν»8ςY΄]σzΈΩ”χ1LΧ’€ΎŽϋ\ΒFΩ7’=R“K²ωΊχx΅{­Ν4K)½βΗs›―}e-γγˆΦ ]Υστ“\Sa’Κν₯Š•Fξψσkε–οίΫύ\ΣφΒΕκδkρβuΖω“Σ©GwχŽFW­ύͺ†‘/Ί¬’²˜?ά”nU$Ό,«“j΄)U«d‚ή‡΄n΄u³ή܁Μτ8ΠΉGλΊσεΙΨ«Ο|w±F`ΣY]S!˜ΦΤ’·CφŒφbJΕqre1τΰ–^_+ΡφΊzΏ –wO»·ΨΫUΐSΨ/³t”§UxJoυ”Αέ§έκi³_>ύuφ―ύi½ίΎzχδV?–O…ΰe;„­‡Η"¨‡…ΧΤDlδ}πψηŠϊvxnόΉδuώ—±Γ#ς?ήδμ<υΰΥΫoΕnpv²Πv³biβωΣξWyfg=ŸιmY g„ύ|žw έθIJ/Η4žϋΉ?Πδ¨>ξ΅ώoVΧπŒόO`όSdzώ/Εhe¬|„όΧΛ·Χ,σ,Ms~3ϋԟ'@'$ο Ώ{υϋν$Ϋ3Ÿ›™=ζκ7δ›ν^gΫ4DtΪQ/zišzGnϊ₯ψ>~Šβ\Ξ^^wσ·ZΪΨsPυσΧσ―'#kO_R6ΨNΌΚΞύ©Œ{ΒΣf»74pυ]LάƒkκΓ‘”σς1ό_,νΏΡλt+8Χ;’uώOρŸθ3Ϋ…™Ÿηεx”£ΜΗmsύ²Ν•4 )³Z™¨w™ζf_κn³έΆ`UŸ}έ¬–«c‘`φs²ϋ=x™WσΈΏ S,χ‹IAŽ&(nΚ,Ηcuaͺ‘Ό›„ωJ ±6ζ%»Ε§Xδxh/dR+δΥ7 ΅Π μtt}όiΉZτMbίξ*™”ςKΣΓLλ[‡ΖΗZ±lεN³ΚίlRŸ‡°MŸύŽa@ΐ‡i‚Πo5œε ύ½ε―ΰι_ύ³FΫZ½Ÿ£υMeμέ#ξKR ;Ϊ­χŠΌ]–ΘΦe`ό+€¨'DQχ³-N±ι+¬‹>ψοV ΰό―ΖώΖ§lΠ €3γ/hT‹(2ςΏ<—Έ=0ΙsH{ ΥΈ;Ά˜sϋέη˜]| œόG·#σΐ…pHΊ1Αμ!Υωoz·ών“Ωθeš’~›.Ά_2UexΪιz΅Ίϊrx£»œπ˜Ηxρ,)$8~Œμ·FπβΏKΙΤ-εP7Ϊ½Μ„χ-ΐ€²¦Λ ωΛΣχ,·ο¦Hαπ1㏃o4―°ϋΏ=~όΧοR!šμBΗόGΔΐ€Pβύ©Εtκ ΕNCl¦…)3=^”)ρ@ώXύΠo‡g»C€¦Δ­Ση2]l†ν:Φ7Bρ;Ϋ²Ωφ/iΰ>>ΜrKP$'i¬f±ΤΗn«ƒ_ψ[Β/w‰Fό©Κš>ΌΨ@΅vΓZw°z°j§FΞ©N’©d!cλ΅sq9€M7€]ΦnuUώΒ²*DV~»½gMUζφ9o„Γ«QcώΟ»α»1Ώχ¦€ͺŽ?‰σŸ­·oK;Uyδg‡)Π?’ρzί ΞJBX­Υτεδσ[V%’Ÿδdώ Υ43Dιψ™/'9(=ς{g[w‡ —l ƒ5%«”΄Ηo?ζ+νŽ₯TΡ3ςŠωγC΅1ε/φψ/δΘ-W»YHνœ& +₯ή„­S Ί"― *½Q΄Σ›oπ$Σωκπei“ΆD΄Ώƒ~:m[ϊ]ͺη³e^Ζϊ$ϊ§ΚόψΪlQΕL}Ÿ"γψιύΠΤ―:UbΟβKn.ΎϋΝι]2[ρ”)X0 g/Kδƒ?Ξ¨³Τψlς‰IUS‚ξ:…”Ί―<‘Τa+Έ9o©yΑ~3ΟΝβzώΝΝ6ω―ۚτξhΠΣ>.ρψφΠφμgp»pjαMŽ ^Συ|(kͺΧ³–gm:t.d­ΪΊ‘εlΓ©qqι΅OgΆ]Ά/Αr'»r³²ίξΊ*žΨzΡΎtΝέ\ΝmNο}Λε§9Χ-™ΊWτӸ䚝~©}n,–μθŒnt²₯—™Z ΈlΥ΄ζm›œρ”n5[α2H‘ΐ­έ¦!=ΰι ’SkΧk [θ³ §Ξ–»ΥtZφByx:―žӏ»‘Šϋ}skJu! ιHΝώΎ½TΪό¦…σΟψO`ί[φ"Σ΄’Ύω1Ž{‡”χJ―˜†ηL―f0kt•υ}Ι0Χ cχZd .ΏχΫ4)¨»kΝg`¦b.ϋŠ•“oj‰Σ«N%ώy>όλΈπ[‰πK—Ϋ Φ- dfœwχωΚ6.£•οlPŠΏl0Ptv ΐ("$έΉηΠ;4zŸnCχo5taŸ‘j=N΅#PG]N―&EΥλ}ϋ~S€λΡ ‹ZΤρ$mhŒxI«£{φ9Ίw~ηο³uκhR_Ϊς;ύO ΠΜηΦ}σΜ«Π~ηΗ~-ŸΪ;HΨΏAΝ5>λςqΕ|οnΒΡ03sԊϊ²Ζ"­-ό™vΖΪΙl΅]VY{ŠbΘ­°οω’ξΫUΞχλϊr7_%λZ‘ύΎOάΫ|–ρ…7œP:¨v*Ϊ ηΞΔcΞv ΏC㍙y½!G1-o/zΞ4μΘDώ©mGυμ³ύ<ς œνκq8₯·Gι¦εύx4ΕΤ<–ν]>ZΪ΅|-ϋςoά‡3’mWκΤκά™yΌnν?rrTΤύΫφ]»•T §Ύνξ;›œό"mGΊ‹d0©JώεέH:r?Rγͺb/ή£“IKξHΛΪlνxRXž΅cΚ+΄yχq‘6ο>¬Σ–½Η₯Ϊ΅΄ZiΝR^ΆΥrŠ|ε>ͺKΓB6|)¬ε {ΑόšYš»œΦψ%…&ΧφjιN—j[ςΥ©R^γ ύ_r…ήΠ¦΄Ϊςn0ΆωμΓφφ†1Ε΅yY˘Φ3/k“•CžR²™ήο^aͺ€§ώυΥ?ύuφoώτ—lγsC!›mw›™ΩοΌ{i±άκ4L«ηO°’'ίυ|οŸpšbRψΣzυYvžΜΫΣΪowOΕ_π| ιh―«…_Γν8όΖ_V›—ηOpν«Λσίώ·π ΉΠ>ΒLxξωΜϊe:”ρw}υ“4ίϋ”τ†V}5Σ lϊŸωΧη~Y8τž­WΫ|Π·.3ύ―η²·œŸ|Άπ½AΉ|± γVΘ—ΓΤ,Z³ίΣT‡σΆώ>εδθͺώΤ~ρΙ1ύψ7ΙΌΧΫβxΪ$s5]q’нξ~ Χ‹nμΣ…_^©ˆΩdΛ'ΪΉ ΨGostZœ»Oz±Ϋΐ„ν4Cwνέoφm±}‡»,@ΦΌΓmΆό=n²π‹•:e5vΙJ[a•ΓF‡~;w‹ΓιœΞ=ψ’2,Υ*‰27LnIl”u°ά*%΅T©λΔε·-HΎ‚#Μ[γsQo.½Οdλ7 ΄R {ΨdwσΜR>φΏžͺdψί―ψ_~3Ρa^έ4Ÿ™μ―κŽΧΥςεεp‘,ω‘xΓ–gψ\w&εέ€φœBN ;=f?wϊμΟ,ΊΖ>·x·Ά―]uλΙ5ύΉ+ψϋΉ!{κsG8υs›³°zϋSΒηφΰυηυη³Ρ†ΟgBϋ³˜Ο€Ο›ΟηΓŸ[’ΗενΥvΆgv=υδ+ϊŚΆ}=8ΞͺΫsa) ―a’§ΉŸΫ#jŸ[ρŸkΑΥωw僚mν¦…άΏΚsΊκ4l[p…l’Ο-l­;šΏg!ΏισΩDΎΚη9I–ζά¦Ο­i‡Ÿϋ$ω}Ύ&πωL¬ϋ·Oω’;?dώέ:][A"Ζόχ«.¨κ;ƒt?₯€VAi4ΦΏOύ‡ΩΟζFν`α­VΖ1Χλ<ί…5lΤk4Žω£/ϊεx›p±”b9ΛwΠ$+>Xοζo‡άPY`Λ šsw›½έ­Φ»γ3Υ“‹9ϋ΅ά|Tνύκ4ΣBσ*(¨εͺ;{ΝΥP₯χ%N«œ9xv~Γ-Ξηθ_“Q_»QοΌϊΎ π wθ‘ί7c½νκmyλ’?W=TbyνΚ]ιεχNΤξ™Σ\{ζ?MfsνΝ»\Ώ[»rGο―›_[{Λ!³l/ޜk{AŽlνͺ]™²ί+ΤΥ3S“k€£œυΚ6ΜΎ__βρς§ކΌαΊΝyŠ 9[—dj]`XΖbša{Xjͺܐω•AλsΎJηwg{•ν™ηΥxΞ»dx₯Ά;-λ|ήΥωŒ«bΥΎΝ{KV΄Η]Υ”¬Μ—ή•Š•~ΐjΎ•»g VgšUs.Υ…‰RΏJ:Τ!q[ΦЍ€0§)PΝμqο’οs.‘§5eηͺdœ_:ίζ0_Κ@ι$δ©εŠ4e‰dΫ›³Czδ…d‡]”R?ε” Υ·GBDtλASŠzξ—³Ÿ• '|žΩ f„X FΖΤ?Ίwψ`ΐόOTώŒfπ 8Χ7ͺ?bμρAύ%‡—wόΰ_ΈΖeΡθxΈΨo7&σ™ήeN懴ۋ₯2ΛκΎ†Z~ΓvS-? ΣXˏι4ΧΗ΄lωώVS-ίίa¬Ž8‡ρOΗU έΆt§ά–ο9ά^„έšN½ζύIτεΐΰ ύΟϋΎŸώoςC‡Ξι₯jύΏx4κGπ?†Ÿͺ½œ|ο,ΣaSk΅Ξλώεi·Ωϋs‘«ƒš9s"ύΒ0FnΘO0κΥyzύYͺ‘β7ϋ₯›§ΡΗΞλρFΊp’ν‹ΦΤΉoqφΫ·jΠ cϋ|λ…±wsεΒϋεzγΓμ§wΣμ˜ιj9έξΧiF’›bNkXm²ŒΛ’Z¦_Λ±("΅šοΉτΜQι+Χ7ΒgkυT—χυ„ΰ"0{«ξ’Β{n­Άωο›™^>ύήpƒΩ%‡Nژφ²¬†αͺσω·.ήζSπ§Sε§9+ο%CWθ‘Q?LL }‹¨ηqωΠu猢iŠlΕyN‚›K<Μg)1B_ΰηΝΈpΟ³μ~‡Σ‚OάJ’ϊεΛ δ¨§Λ – 6lώWߌ―Ύl†d ½ˆή¬‹ΦςCφz(ει‚L’Žά‘?cΊΞ0Νk.Λj)δ±Τ)’ϊ§*ž’―iAΣ«K›/ς,ωOέ‘w+Ν…IνΌ1­ f!4Ί!‡ασΈ*όίIΉΡžΏ*”ήκ%-sτw”ΆœΧθ+½Œΐ8hμθ”<ΉΩΖ[¬Ψo3ΖΌΠσϋ«‰EΰΞΖΧΖCΊ€―±ϋζf±€μΨΟ'kzΦ]]ͺ&;Ϋ8§΅{)ό81‘δ£ZΪ–¦x7ύ°Gn:tΪ²σ›EΆE4΅₯ιΣ…¦άώˆ6·‘9užΊij[ΡYW™Ω†m£‘zηώg―{χ*¨?fαR§έͺN;Σ’ΰvΓ|$˜ΏΤ―Ώt•»τ¨K9[rvιͺ:8u.#ηκ†χ'QΝξlΫ_cΓ_Z“ΠPΠ3CΚLχζ”φάμ΄/›Υ~]£Γλ6χ2‡Οyƒοb^(Ώ?έΞ~χEΉ Ϋ‚όώ¨dSΝωΰΥ…pͺΫOa˜EύG΄†σ\cK%Gϋο!γ$Μp.‹ΰXWϊ?SJΗρoϋvϋοΊξ7) μΣυfΐΞ*=±T*5rϊχ’k―p­7β₯Mν;y£λtΟ}Ρ‰Rπ’ŽΗΏ„ό \‘‘£!γ Ύ›ŸF ωίJŽυΘšνΒ\Ώ\ψ(μλNώ 7‹Cš8X€‡―£Sͺξ¨ώƒΉ™?fΞΡΆ›eͺ^RxδΞ.^°¬έ­ΥB Ρœ)rRλτo΅33΄ζjτΔo§Μ£ SΪεcνEGύnϊ?Sυ !Ύέεγ/—‘ͺρ 6ΪοροΏ<ύ΄υSΉ€Υ{|=…ρφτί^όcΧ…4‰*›%ŸώΛΣ½ΓC—+ψŸεε»{  μzΉΧσ§TH-_ΰΐ‚μα Ǝrμ·£άΒF lžςθ•εTKOΙ΄qΛΖΏ`‹˜·nP¨iw“Ή^Ύ|ΝD|™­&3x¨Ÿ˜ΰν·ν>©s―h`& wΜFŽ3Ε΅ΥZhΈαžE*&ΚͺXEΉ°BΙΈ Tkλ05α€ΜP|zz~™-ζ³ηϟ~k{½9Τε˜ "¨Aί,0Ϊ@aγΘPO¨qά%qˆt‰Žƒ5&¦ΗΦ;#hΦo„ 2αšΛΒ›Ά‡ΗΚ㋁_:ζ#.Έ‚Mœcξ¨!\ΐ›Κ“ˆ„H K%”qK:ηtΠΤj΅emζΟ5^Θ‘=aD1EB;ŠSΘjΑ‚aIπRRg¬ΣΤ nCD4‚(e˜†V0*πW8§,όŸΉ^§ΰ³ΨιαM0Ο…§ΫΊ—Ž™‡ψΌφώ|ΰχ%α­"Ξ‰ΤJ9Κ’˜οM΄S‰ °βˆ0±₯„IXDZ$~D^Ξβ(j^S{QΉΥ’π«₯υSληστWώVӌ€|I`Iu|‰@©ήΞμ·Κ‰ΠhΨ γ*}"] “!f1–6iœŽœ0 411lt,ζπ§’πm$‡₯“˜˜ΧdαφuΣρ†ΛνlŠ©CU!JŸπή‹Δ€t΄πμ>»Φ±K@D Fœa<ζA‘§BΔΜjnqπ |%¦ρύ~Μ–z={ΚrΚ:ήςνuυ£.L‡Β(f2¨˜eή0AI€ŠE°πڊKγmΰή&xΓ6*œQΑ8Ιm›8Ϊ€i½Ρ›·η†ΩA_€ͺ$‚uˆυJZiΣT e­DX‰'υLI£:œΠ}T€΄h};Ωώ™T}ώxΰηwΪx©iLCΜ£8‰xbi",n„_ΞyšHΕA[Γΐ8’0FƒιΘθΈυω7ϊν;ϊ*ΟOιΐ/`bρο@&Jί8Φ&ρ"DB0ㄏœ‡LΖπ‡”†ΑŸ^2ΟΰE 1Ίq‘,Wn³Zw,°;TE%±±R:EHωΘDήSE”1αΰN$‘€"α Ακτ8‹e,œj|·,i4 – ψ4c3% $έpΚͺμψΥΤΥηj½ώΠmcΞ‚°VR-,X,ΔΖ>ή%2’>X @‚(ΔΙJCΔΰh&6–aD?Ζ! Ρ¦νx f«Ο4£3έ²ž-±ΚύοήΒCΟ°οΤ™O΄Ϋx]Ulxp'1ŽΊρ€-@E 1 ―UD‰—οLˆAΌκp G¨ZvCΏNρ &³Εz^ϊ&ω7λρφΩΉχώ<α\*˜‰ΡΡVΔ DGΕΉ`ˆ&…‹-#‰“& ΤΑΜαu›?&ψLΪnVΩbωΟύj—ΝxΏsoŸ– =Χx5Ψΰ+ΓΑ|1¬‡(R°`ςS‘=±°‘πDΕιπf™d@Y} @€G"=*Ρ_,ΪYUμΛΑΗΪ‚ΕB$KΕsά’(V‰‰x€²AlΒ#ιajό Rκ8’I°! X?aaπΨ  ωωαVΨΊ·“‡ώΰΐ’„°5ΡαKŒh/O-”χ2Ε΅€©ˆ΄*Ρ6ρ6H0šš]€₯a΅Y—αΜ‡Ύ|9Ž}M|Γο£Oyνύ·ΩςeΊΣίότΗλA\ΆΫ§Ω‘iΤΤαž.΅ΧyΊ£m’ΜvΣ0σsWwΦ Kœ5`lRΛx€σ  UΖ…Žˆ§‘O,4'„ε[/Ψ!Φ£ύιΓΆzρc7½<²3$€uœ€ O &΄‹±¦Jlu&fAH ›Hb‰χŽΓla.‘Φ$ΜG4ιxtΆ”m6Όƒ₯|±€,(5]΄bPCqœ%‰T’–BK ΛΪ©„ͺ„·=?Fκ'fͺkS„dxyf₯*8姝a Ր¬₯ήr RΗ) Λ’)‰β„a„k8bIδEKŒg JΚNR§lΗZY­P₯΄εΚΗα½ζ6hP9"1η;^`[ρ ­™‰biζBd§R rBYλ`πΓΓ¦α,V0HF*+cnb* ˜˜ΪΦ8Θ ΞV­jŸh΅Νσu‡eE„2A}[G4Aβ0ϊpœ$2ά λƒψdJ&‚(zπΝΆΡΉ%τϋl͚ΐτJ_rh©q₯)`F°fPژ@–Gή Ι˜Π^œΓ8$!4VF‘UβlWGΝͺX{™-_ΐ²‰}Υ;˜VκΠσσ`œΐœππ5@l‹HΒΒ‹sπΈ2ž“8€yκΉΘE5Ψ[΄ΕuU³WΧίΣΐT¬:^ŒΡΠ•2₯‡Οa@«(Oΰ=5$Ϊ2ΔI‚uμ+ΐP‚ žYIβHD"[=WύœΩίuφ:ӍϽO^­oΎyYMΑ ΧXΪUΓstpLν9θC OtΐΕIŒ3XŽPLγH γN c βΨFXˊ^ΐc?eψσœO’G,Χ’‹πήs?a ²yM`’3Ι<ΘmmΐΊB+Sž&‘$’Δ ΎV’¦0©ˆ(K(u‚΅©ΠŠŸ–Jχ8ƒΔ‚‚³ΖUœ(3°TaΆœb0c-w‰ζžCiy˜δ€χh’xΣ<ˆ_™ΌοHϋΈ8ΫΣ#\ΆΘ{»‡Ϋd=œΕ}β §°yΑχ{«“χTΑpΦηΫF•|ΨΉ=ž•Vtϊ‰ύv5ξέτ?);ŠσI‘‚žώaUΣς}M'·oŁ\tŸΒ¦Αε`MΡ]ά6»RΗΝ½σ£`q{gbXΐΜ':3hƒκg°D˜–¬tœF"‰-•ΦrbΑšŠZsO2UVνo—Ζnκ˜fpƒ=Š₯A·O‚Ω¦θ#dΖEΦζ²ξL ΒG^rͺ.H&―Ɗ ’-ŸΆαροv5}&‚σ$RTΖ±±DQP»ώ Œx/c捉Hs#|0![$ƒa#­όŒ‰ξώΉ_1 cψ’$ eΐ6•‰R`j‚ΐyψΦp2θΠ₯€ν˜5 šGΆζε~1ΑLϋƒ˜Δί±w΅ω²ϋ­λLvΏΧr!ˆ8δ$hGx,Όp XΉ³ΚPΖ0Ή;G:6!ϋ"&>³"β±€^Σf3=ΒLΰnΆ~ςϋjι‘ι¦γώί*¨ϊaΉ°11<ŽΑž₯`1 šπΰ1ٍζƒΖ€:0«₯dl €ΩΊY‡’Œn6"`Γ|₯]Ϊ΅€γεΧ·>β&‰Š‚4†9Η Š Φ!€€₯€1θωΤ °‰|Α;2ΒΠoεšSΰOΝψ²iŽK-xΟ½-8)ΙΥΤΟ*κ,54ςΚωɏ™Ϋ½ζIγ°ΖΊλ{a>ΕuΉΥ^%l]&“ά‘Σώ5hJβE]ŸτngFDζΐ«κtŠ »ψb”Ε#QŒXΑΌŒ #nS'«’ΪIE9HBΑΔΰ”Σΐ‰₯l·¦Ϋή++ξKK.–jJMeΨκΆ{θ•AZ9jŸ‚»©ήΒX€oΓΨ‚°­/W¨hξyΞZx]pƒ:ο™τьΦ'Ϋo³υ|–Ω.Lb<ΉΝW»¦OXQ_%WΉσΫ-ŒηzΎKaͺΧ³ž_°ΊΊσ Β¦bž>kλClό$¬φK0μρ3έΫ΄':N]xΑ”Χ1γ¬ `kΠ(xχA9¬ΒzO z΅σΑ^A@F·$2”^βM-/Ž~Ÿ Α«nΧ{Ν5θΜ"ς‚Ξi(Έ Kΰ„Soϋž \―Α††έ΄-BnΧϋ™›`Hͺž?;4ŠΤ”&Ek„ pr–vŠ0ω%‚ƒΊ΅BσΘSLΐ„§’$N,ΌSΌ-p{δ_>‡Gρ”Is1€δθR‘‰‘γ³₯%Β$‘| v˜§A]ζL‹ΌΙ’ίr£©}ΚsΜVϋΠλ #,ΞY휀0Vq4r:"Ϊk@€„Κ($€/9?τ[&•β4n¦ƒ\­Ζ ‡ŽΑ`ΜͺˆK!˜ˆ ˆXZμ, “Δ1f* LcΆΖΓ΄’η”qΝγΝσΧμ!ΟοXΚx|³Ιϊ σν6σΰŽ¬­mΡeQυΕT ŸΥ*+Μ” \qwπΡlτ[–NiU—€5ΉξφP’ZΎ‘dσԏzώΝΝΊάdΗχ‘‘Ίœξ>ΧZ”w22`dXΓ#°8$˜Ÿs˜™ε4ςΖ%Κj½K§ƒΑΤ‰ΐu ίSβŸΖΨoΒΔGZ‰Ϊ띑ξXQ± Ω Φ “Θ%:‰Ή#%>EΚ.q6"jζؚ‰"ʁ‚§ΗλγλΨεΧ›γμϊe*`[φEC sD‚Y \ƊΗTƒ€εŒnάD›Θ’§46D: ;iN€:ΩβzL:έZG/mU―Ÿ9F¨Vήp‡S]cέ΅ ¦1fŠqΕ’ΑΘDKάsΐ8.ΖΤΈ`’Θ΅TΣΤ2ͺO8ΦΎκεΟ+[Ζs*Ϋόze_Σşώρͺ7ύ§Κα΅» •·Νπρ w97ŒΗΧΎ·“ˆ(¨ΛΣ( ˜F# Δ2¦ε°ΡͺDi Φ‘S +“1 ΊΨcα/gΔ₯ΓωNŸ/›Υ΅0τΗSBJK#&€°zA%5 ‰΄°ƒi OΈŒIτuKa„Šb°‚Φ_ϊρ†Ÿαο4ιƒΧ,―‘e1LO@y“HΙ±@λ€=A₯aYpΑ$¦°r„$δ’œs`z³ΗΜεΖΤ§U[Ÿι€-XΡώe―7n / φΟmΌεΗ !#Ϊ•1χKΪY~!ΕOP›+ZNΔ‚Ζ± υqp”fc€47}Θ«oψ™Ι{0drΰΈ1–cZŽ‘˜Ϊ mœq”j’ ˜@Eπβ†Η"V‘TTPU?ωΨ“±$doœŒχ™β—MβτΞ5Ξ•Αka[œ΄Žϊ$XΗJ0^ΉObo”ΰB½Š$4a ¦π“Y@u|¦πΆξw¨τ«ΎC<Ό=ωΔ%IΠ ΐ%0…‚O+ΑΨ  °σFsΜh r™ΐhΜΗQ€OHfEχ;Š Z“CΌεΫz·ΒJ‘ϋsp Vp±ΤΔrβ›Ĉ#i"Y V‘'Κΐπ0ή‹R] ί$>@k­zeδΓZί›]W(znͺaΥ‘ΙxƒGΦΚY!15sς½€»,’°5Š|ŒDcV“€š€¨cS+Ήj1λΣLυάχt’٘νVY‚χζmί'ΡϋxrΥ΅1τ7ΰh5&3i£HΓŽ‰Ρ‘e0ΥΑ\ Bγ„OιEΌ§Τ(©`nhJΨ«8₯œήΜ1Ί|χ%Όb‰–œω ”°|%¦uˆ+'1Ώ=¬g0<ς‚S›/―‡‘n6dς§?ΕLJ³o=mΧα_έ{°(3ή’mFm` ―4ƒE0KԚ Ψΐf5…―‡8…Ήδ́°Μύ©X•?΅z{ŽνGOςηN2ς‡Όϋ'"ΦqsζACτ"&bΘ*“(­§6&Š•4r ¬σ‘¦œHi)΅b–φ›=‰DœήΎ.*9β|Ž>ΒΙmX ΪLΕ.DPδW26Λ’i{$$šˆX+ξ‰ >’€>φ<±ύ`η‘χeΗϋbΟΉ™»;€ Μ}‰―²J1P\ δ;γ’ΐλamœ‘/x“x‹€EΓ"' kαΛΪοgλΥ6³ο ΡΏϋJ†Μπ‘°`-w‹sK K€½δ(eŒ TFEΜcabΗ V1―mLΈΤQD̐T8YŒc²τ?jή½Αk*hΰΐ‡u_HPά*ΐΚεV*Ψ.rrϋΘ«΅·^z[ψ@ mΙ Ίι΅³μœŠbxWŽ‰ς‰²2Ρ‘hξ8β(bΞ1η2’9‘`nƒ ’ήJ{Ν¬†—”ϊΘΝ^|Ν ΎDΤΑWΔQ ²—H jŠq˜½"α”`α€c†S 󜰘KεLΰΫθ »₯DΤΝ6[˜Π?ww§Ω΅₯9E@MƒKi@¬Γ'H« Έ ½ƒQ₯·0Π` ΚΗΜτt–€ο³}ΛίιΒΧfχHΘMΐfC¬g‹Ι›Œq7$‰!-Ϊ#ΞjXίΠ8η Φ1@£dηžΪΗΓ!Όqš aE³ΚΡyMuδ%cƒ 6fΌ³A&΄qB -m3i„λW)΄ρnυsΊίbΧύh°€lΑ2ƒ{» Ɲˆ[Œ Θ}Έ#–†PfžQX |$°Ζ)`πΖhma D{Kžƒ‡©šΚΑ²14Ra©ΠΪ•ηGƒ:‹Υ1 ₯ΔΤ)L…J΄² Ζ6ψΆ"|Τ&ΰN7 Mƒ'jHšΊnό²ˆ$1`%^&†!ΐΜKˆ7:NTl…0…£΄Όg·δΣΐ9θά¨η£\B\֞syJJ:OŒs–κ”mxT…ͺ£&h|@Ύ­¨’Ι[©ώiΟ½™ΪιLN;“Σ)³r΅˜χ™ ή­λ&rΰ•μκ}œsM£\άΎiΤ;XZ³ξ λtow«υ/-R>%ΣΜΰžŸ£>‹K<{‡b―ήδ[έO–Μ]GγV†ŽŠ»κ\şV°Iλμ.+₯k, +-ΉτΫ83Πςλ―SAάβάων•ΝƞU“}_βΜCfμω˜=₯viςT'Kσ_5Œ—ˆΚΛ‡/ύ2ι(n/”ΎL”X΄J%BϋΆ=Ύ.¦ϊΜͺZΟUΒ±˜ά'HGEK„±‚d‹ 61¬e`Z V0'lC0©‚§Κyb’_ΐ‰ί³©%6₯λ~ωΌ³[―ρθY*ά0 k5 ϊυ§^¬ad ½‰+:nR¦Πμ«Γ³φ Mξ΄|Γl²έ――aδτ?½έοςΨΒxήΔΪΩ©^ŠEreΠv,kΰ½½Gΐ·Ÿ¬τ>/E»@mό5ιWθΥΖ’zρHׁZT'Σ»N»Ύp:tQ–ηΗr†¦₯ω /·Ÿι€•³—εa΄Ξ ό}¬m¬Μ“ΪΔΈq&€Kσήυάxn΅2 Ξ&4H‡‰DšSοcΕ8eΜϊ˜l ‘>[Xι%ŽΖ΄%έ€‹«3κͺ»:τ'­…§‡.u \ZŸΨ8˜$Ζͺψ…©χœ“H²ΫBx#ΣΎ+Q$)΅GBhξ½η’­¨Έ€ͺƒ7xπ%†‘pΤxJ8Ζ'\¬b2ΗI4lՌH“x7ΒcxΙΰ(/ !ώ‚Αk­‚xθ§ς́ »Ζ±ΫθJ,[2lY?Ι²ΠsήeɁ猿 Ry‰ΙΣξO!³ΈRσt ZC] |‚‘]_ΤqaƒΖ4=А ±ΰΑ'žSnŒ3Ξ½νlω­ΜΧ©·ίšάΏu~Ξ–"ζ;|V&ˆV±a‰Žcζ‘&€ΩbVΑ§ΣυE” 3Ϋ'Yΐ xG΄%3£υζŸηάΛΧο1‘Αf¦ œtŒh€DΒv §=Ηδ·Δ$Bζ!Γ`Ήƒ4Φ°Ϊc.°χHβhχ‚8Ν–»Ώˆ T+$`Ÿ™ˆq…uD$mΦoγ(ˆE Z‘”,ΘλΈ#ΉlΫ&tŸŒμΒ’ΉϋWΡ֊„1ΰΓEbΰcPs©Κi,UΥLΑ  $Β[a°Gˆ>7ΌMχx ΄¦X‚υͺΦ°=-! ΊJΊ&Μh€ψ&1ΰy₯Ω2 63Τb§GŒgΛΕN™Ή“WmΏ+ΆθΚΦ--ςϋ‰I¬ŽXΐtΓ¦΄q@b]’lΒy ooΐβΝΖ}d0ΉW&ΨΓ0"X=ΘΌo:Νοώ1 ›ρ!ψή9#χΨΒ%N< ]bIͺΔC<§πα ‘…η˜ώΒωάK€dΡεVw¨χPΒβΗ…Τ³°ΨξŒJω8T”Πφ ΐ dMt0K}BaΉ%»al΅g^"•/w @έ2tγDž”!Έ?°Ε/Œ…CJυΨΒ γΖ ·μH€»x(Mh’’³ ν5LΑέηKΡGh*Αϊ@BC˜†^ΫΩΖ¬ΈυΌD˜,ύv—GΆsmΊΔΑοΏ_²­thLS8Qb’O_bσβ{g―TRN©Ÿ…n“ψpθ‹λ›e„α7ζ}"ζCαωΟ]ώu΅|yΉΰ»W.ώτ|ΊΐΉ[₯ύuν­Ž8cιύ¬EBΙ=:qj2‚mΖ7₯œ!>t\xAΉH@™ͺDH'ΐΦIΐ)36VLκ Ιω~8-―χ’_ξΟ¨j0IœEY`iΕΨ»-20χβX+τ@D\*P+T&Δ€rӏqΩΟ#XˆΝ΅½¬νݏχΤΊ–ε|IΣη’—Ά=}³[^μΆ1ΥεšΦΝεŸΚπŠΑY%‘B)omŒ…Τq›0– _ΉΑδŸ6ΏKR :N ŠWr€1mV](ά–yΤ΅šœ–UΪΆΎό.g5¬ΝλΑλ[") $€ϊΘZ †jŒž¨Ζn`Γ1ΐRŒ„*"c¬Oƒ—ΗΠs α2κΗΩδϋΦΫYšΓA. lpΗ 6Φ• Ε%Vb+I£rΜkdqβ6€ΐ’+P% a‚ΕιΌt€ίH~e€9Άύ3ώ=Ω.υzϋΊΪΎπίgώνό8υΘςπžW&°™%ˆ­#v&;’ο% η˜†ΙίΒƒH1ς“„€t1K@ΐK"Ξ”2NN9·WZL/³ΕΌJκΜδπ%ΌDκ‰H’XPΝ ²Ο…Œs0• ‘O”58]Y)ΰ3‰lI¬γ ΎΝu™ϋΧZBΞπΜ9Ν“ΘD Ά3γ ΰ"_Zsg‘"Η§tμ1IΌ9€„ύ0ΏA± ΩΨyA6Μ”ςξω Œh¬ŒiœφπV₯M½“$ΆqBXφ +Α#lλeI“δ3rΖάΫΒsYΜnl±έ£K[žwxoVo&@²ΑSZ0Τ©ˆcΨώQƒgŽΦΊi…V₯ήzNfφzm|ί§ŒΌ†”₯z£ΞOˆ…Œk@>οΠΜΦjΜ"1ηπ΅œ Ζ‹sΦmΒΠskI’(ο£ Αχ"I"!ul˜π±j†©…ͺϊΪϋΓS™ύlξ ΏU•Dπ/ϋX―^Οw―χT\π35Xμ`ΦS Β$ xg,τ°‡‡Ά"…ΘΰCr†Κ3‰ΡΪuyEλΣ¬<£.ŸAυ,Δ¦_ψπ4΄Hcξ¨N˜2ήcΗO₯ˆ²„% €PIŸΐH{€Zf,)+b–0- ‘νΧS£ΉΤ3ψσ©—δ‘﹌¦<‘πψ»$ΜzΠWΏ²»Gc@ΟΨ9> Ά  3Hsx‚&–ρ†Δ€O ‚=It,6θ‹< TELυj9ΞΉpJ—•”>ϋ"η/Ο6ΩΨX‘™ΑςͺηΥ&ZΡπμ°L[Ν΄ΡΜ)f„F‚Gί6’ΜšζξDQ’₯ FR‚n~iΣX¦p€YZ³ΖΠ“`6«χοdα"°%#ž€JiΪ ς- ,[M$DΨ€A?Œi“ ήΔ‘6Τ‚wΈ{΅<;Aψ(vπ0ΜΚ₯…©nx*ΑΤ‘ΐˆ’Η Ώ%6֍LϊtI³·ΰΠΟhλ_°δ_ηm“Μo³έD›Ωέ‰Χ9φ™΄IHxv–΅‘NŒτ6„X¬ ͺT+ˆ‘Β ¬jP&²[P^ρYI˜*γι{ WюλaUΐαVzΥ–J…δ°GΛ½{”‰]Šrξqfΰ‘¬‰¨6‹#©` 3f œŠi&R‘ŁΥ “΄=ꐯΉ»―Έΐd“`Γxcƒςθψmbΐ!Œ °‘YB˜ŸΤ°HLπA7ΞIΨKϊ‡BΏΨμ v³JŒβΈ(Ώ zψαyŽδ­ρΩνΚ~σ;VCξ?0xζ7ίgyω Ό£‘ΤΥκ%‹˜ ·ξ†5ΰs˜i Δa z"€» ‰8, `Στδ e~p*XЍi₯\ChζwS„ωΣm}Ήτ΅XͺV³2+~ ͺT<7ϋφsύΦΫ;…₯ͺϊwp;EcŽ΄«Ibbι΄’ Ÿ‰ρšψ`α{» •υZA œ”\˜p³($I d―Iδγw^¦Μ“Η€[υC•v·|›½λ½Λ?@a_‰Œ₯R>ΑόΠΙΊΕ$)™ #H9Μ~%‚;°pˆD0--o“v3·Τwχδx8ΐv¬E6 ”N°ŒvTΒκ=2N΄rRθΨ$°|¬Ζg€EΥƒ’»ΜΜά¬΄aΉΪ`θοg,΅£{‘<ŠjxC†‰°1!N"ΑxŒΤΒ†0K ¨«³wΠ·SΕ}H"ψ0`XΗ '?›ŸsrtΌlπ›em°Ό$2’Β:t˜§w΅;-;°΄ab&Βy,hvHS)oKaœtΘ  vxσΛΫͺ;ά•œCGΤVΊŽέλ°vKοςΧΜ~›όΜωd6/搒ƒηΪo]Ÿq΅›…·//œgžUŽΩX{XEωK€ο˜ *yšaλ&― ΡΟέR0ξ|ΙBώ&φ-žUuo žήM€%ΜH¬Ο ›D€"p Rk“†’ PΘ5²+КΫ%άonpoΜ–0–υ(o4xη@ušΖΘnGŠX簟₯S“‚&L"–L(ƒ/…ΔΖj Œ1,D΅.ρJέΒ-8[ξVΣUςFξ΄Ά›­ΎΧϊDΣΑMZΓ 6Y!‘žFR@‹CπJGήD–GΐΚ¨:M,¬L#y‘ žcο†Hϊ[fΜzι«„°ΓG”Ed< TXΕψ—³Ϊ‘Α0ˆ¨325˜υ`Ιι΄nΰ "@ SE[ύJιΓXmͺZ:|η9$w0“±x$|$6Œ`Ɓ€`ΣΖskΐΡH cΙΑsΤΨ!ΞΈ^Χ3ν"ŽύοΈc±°šͺI<Θ¦`-ŒŠvF00Q£˜3i“DyΚ%‰ˆhJ?XM5‹¬œ«υβΧ»CϋΰX¨θl&Ή†Yπ zJ*A Ε,†ξ㠍YL¬†ρ%<‰,ΨEΙ•ο·5ΗΠјΰμAΣΰŠδ„aιZ6Žƒ=c΅8K*V1—&vh \…(΄¬¬Ώ― ZΉuίΒ:΄. ΜP'°°δ†ρ8‚)΅1,,Μ$s ±h­‚vŒ}’ΰUa&r[ΨΩΒž§‚=εYpι-Γχχmcγΰ~\iΌ3εΤ‚Δ&Ι*r˜Mg`rΒƒb;lΑ\ml±“w >r.BωHPΝ†δ½]LNβ–WόΠΪΟ9kxQ6Έ5‚„Ό0˜ιΕ±' rΉ˜iΐ±ΥΚ:£3ΐLX–AB$ΐL†Ι‹υ·χfΛ­$9Άθ}>_‘Φωr―u)ΫηααΨω’2άΎ·*5•(ν!Ώώ.qˆ CΪΑκξc•V)Q> p`­œΖ-θ%ήό‘φzδw“ΑκbAρ%vΙ#‚ΕΉ‘SΉω[Η(ΗΜPΏzΎ{όRιω?6Ÿ!ςWΏ«ξαœH›„ˆ&Φ gλ‹ͺ,„ά˜uςŠ΄J•?S…q\ uTΟ²Η¨yPΐ²ύf―ΰEπΨΝv’'ffΟ'žΥβ*ΡT!_ΚbEbΘt#ZΑ>‰‹4prA^Lλπ1]tVλTkpαί¦‡0€ΘŸyθ•,μGβέ2 I€ ΞwM0¦>8«`j“’Ωα~Ώ‹² ZŠΔ°c¦ —ΨλW3ζ7*DFž½\?h!¨ΜFΚ&IπΦ5P‚U‰ ˆဌ ˆΈJmΜό‡_;……1£ξRUΧ„μ­ lρC5JvΕ‹°Ίά—D΅tν΅Ν₯ESQ³"ΓΗυΜΤοuq\»4Ξ)eΉχψJΩ$ΐZ‚JΡ9αΠpŠ`«•ΘˆΫ2–;ΛF|Ν”׌υ ιμαβqξbιε =9Ρi°€8-TΫεj#‰L‡0_²θ7c9Χ¨u“jŒΠ’Tώ·@σŠΊη‘Έ`Ψwƒ»ΝY˜Ε+Pl±™ξς¬&ά™Ω°£‘ta6Φ ΝMΦΑŽ\δ0q_paa7TΪ·«qgΞ,nσ€;Β6]y@άB―Ϊaμ_{§T-XCΒb9aœψNͺΨ.q|˜sδž%ξ>άbrΐVAyS89`ή¨©δκ]:Τ¨t_M΅ΔΊ “’#bλ©zUC$η„ΪζWRΤ‘αΌ$υ‘ΜAtΨDΉ£žCΩΏ5 ‡&0/~ξ[%Δ”}KE*ϊΆr\³Ž#'/叀έ·”½ˆ°z‡(?m)ͺΔ0#έΡη^»k9rJΥVμ+“R±›lΩΙ )RΪΓΆ±0Šq²ΉSμ!±ΟfN[νί¦ž΅~½•†Žϋγr€ιMσΙΈνeτ±]\Ο§ΝWo-B·ά°˜tlΐ’D΅ΑkΟ°@b„`M’ηY,k†E¬15UνΖ_½~&OˆςKΙAΕ.ά՘ζr`j¬T“–^]jS±EΌ² >‹Ό2M“1ν78Χ}“NΪ•“ &€ΎρΝ  zfιΦ΄‡χ5Λ{«R­IY¨σlu˜|Δu±’K]oh'D9t8φκE†Tx<\,i"šyΧ5¦Wφ|ς½eiΞ-^!Φ«žjKH½8{€C•¬C―1D© F§Fβπ}Y’±C~κύΨ„ΕΧUϋXœQΒπθ3₯ž‡žσVƒ— ηŠ¨―Ex³mŽΉ&«­R!b™Σ%Ζ•3γ{ωy;(―¬U η&_η΄M¨|&/}·―9J…Ή¨’j–ΊL5‡štšΚF±6§'€0IZ0SŒΦ™P*<&wrΫϋηΖ9BΆτ•RkΒ Jφ-&§l­ͺZて²JΨϋ­ε’ΙJβ*x„₯R ζ¨4 BΊRzηΜΎzΪP Ρ; ©<ŽΤ~s!Υ–Ε%Έ!Ε`>…Ζ,κΓe 2/νkN0d ΐ‘wJπ“[ϊ)fέV3Βΐ«€Hͺ""•‚άŽΛ%αUvΚGkœ#ο€V’…yγ*$ΰγŠΪ=ΏXσ™.ΙIوάq–^νδŽ“Π9%7΅’«Ω·-€&±±Žί„ΨΎLp]›uΡ€΄l‡?ΜA'ΞN“²BDΝ₯ΓΛ–ͺm§¦Ψh δFU‡$c―ξ8z©¬ΔRrRμju3™5Ž8l'Y`·΅/keΎ½{Β³έ˜©οΏ­o‡ς΅m υ ςθΒnφ„ΗεkΪkO ˜4+!+„%hq‡ '―%SaaοHκΨ€£>aWαGΗl8š™΅:fζu­Έ5#` ­χ)KtXΌΑFΏ³Ι‹ ]±Ί`T’kušqΉ6ͺΡer>ι<)ο²+ ί›“ί6gι2·™LΰΥ/©Ή΄'gœΑ ΰ•JQΑ` Π…Χs8—ΪbΗ΄α §BQ‘!Δqe>'Ηgw,N――WζvχΖω±ΌS)YΪΙ°¨ΎΚψC»tΟΑ(e-$F‡»…G΅CΎ‰†sΙ ΑœΉΥOρtJMƒ' ·­‘}ΔZ{ΉB€DͺkɁΓήvM@U‡6p?ɜeμίœH8Άk^Δkoh΅β—ΧΥΥ3 ±%c]aχFΐ\ c›΄—2g»”uFΰVŸcb% G0R΅λ Ηίξ_οN—lyΚ±KΑ΅l6Ά±τ’±"ΦΒ6wOΤ"Έh³αŒΖ¦©} sο΅…οΕ Fj„ λ ƒi³ XLΤL`H”©‘εΪ[―rλ]"Ό+₯,ύΉΰR!9OlΚ»Ž5=Ώ<ΏoΫο0[q}{Ή{ύyΣ_0kC5ιψΛοχsiWBBΆτ”[ΉUM›’HŠ 0žΥΥ«ΰ’Λ!xÜ ΰ#bƒΠ‹HθT τ’¦²3ΈΨf™ρΗ»γ~u½Ό/Œ€½Gm ›η)ΖιI΅g–m‰—Šw–=B"lDΥ ‹¦`½άo°½²Ό<-ߞξΪ‡¦#]‘ΨΗy%…γA;ΉpΛ^Tw\‰.ΑΧvG\δ₯ ΓΟΑϊλζŠΝέ;Κϋε¦cώ,,_Ν,’Iι{₯G¬": Ωκ,-βΝw7'••Ψ2ͺη³-ž½ΡΒFTb‰ΧŸ…§φς4‚q‘F΅Ψ#aͺ|υδ˜uτ9#άсHe {X8kͺ€α4kΐsSHG ‹ζδ°έu™Μ΅#΁ ό:5kΠΔΩY5Ά­§’Ζ ZΐΌ=DΡ}ζ£»+CΚ­‰*‹β%KMs–*rIςΡRδ £θρKgaξ.ˆ·|₯Η•{|­>°Ώ‚Tλy1,cο1063H0 Y±†Ρ©F˜K-μk­ΎiΩqαŸ4Ί9Ή@[\eGHΑΛ€ˆ#Υ”Χ­εT*ΚΥ&ŁyΠδ„°Θ7W 0O©έͺLqΦΞηΩκeξiIθJ½7χλŠΖΨ{y„C^―Ωnύυ΄4ay/μV='I4W•"[Υk‘•Mͺv²ή4ΔΩHΛT1Φ9.$ i*Ldpgπνακ ›T,ž:ΐ#•κ:ΑyŒOTΪ’ε,»+!0KπSΑ¦ ….ΐ Žί―I―¨°"ήo˜Ϊεϋ»ΗWώ²m!—ο_χΎyi§$r³k‘›žšέ_ΈφIδΣ€Τq ‹*:κbα]zίDHΟo†0ΓgΌ€N υRξΪsΉ©WΏφό¬Ζή 0ΐ₯ΨΚ‘ž’›$ŒαΙ²m‰‚76TUX-0^6`Ί%‹φ:―­ΌW„¨MΗ…σ$egχrŒ2βΑL"ϊœqͺ«€ω’a‘wq/ρχ6a}žΆg`œ΄v.ΞZΨsΰt#Biώžt,xS…“£ͺ@ZKwQ§K«Y•%ίοzšΊhήo’Ÿ»§‡£2άΕλ&p.CuYΔ‘ΩW8Ύ\}χΔ–ζ­˜uςΡb³Λ›Έͺ.)7αLΛHaΦp­ΪœαοŒέΥm»/BλT·’š‘ꂆxΛY―4‡μT1Α—+"Lμͺ¬·°d琀'΄MW›Ν{ΎWΦVΙŸ„`Ζα¨;)•αΣ{lExN­τU?œ½ΒΘκsE;%¬£rί+Xmο`Žmτˆ­4 {JpGrδœ Yτ­Ί4Ψ‡KΦμ#‚°ƒa°b'κvτ‹σγΘ§"€EΗ+Ί<ˆ•Ჴ΅΅J3T X+ xρ]€ώE5³ 3vdEΑαt0½“0˜σjp;‘cκΣΕ«–»8˜Ό9τή+€.b©f,ο{&M]eLAW΄Uι€u‡¦ͺ–Ÿο…w`S­=―ΰεΰwnχΪζΆyκΝWϋ?z}zΈ?7#Ÿ8οa>‰$žžFTτ5*οα‘!€ˆf’0l>«¬AΘ¨  V,™š[FΰΫJ°Χ5‘ψ8•ί8(Ε»Ά»Ζ‘Vi;*Iu 8€ΣΘr–±!}"K@˜ps Α‰€™mΣcγΣΑ§G‰Έ‰Ν’vΡ€˜€R•δ₯EΔκβ»˜sE ,Y&φ‘Ώ”)ͺΩΆγͺC)ϊΏΝΉ(8ΌψϋΩIΫάœ“- •"ΑM4ahΛ7§Ε|J4ΑΞ"’)ΑJΖθ’ήW*&P˜2Š5Ο―ό@~x΅c¨—“¨\ΣkXΙ@,ΒζXX[ŒF(ž{νD…7—.݁DΔΤ( ZTΆ:Iχΰ‡ϋΗφτΈ8,Ξίn€ΈO§dMˆή"f 8{/ΑHβŽΕ-‹p†{ιψA.ΕgRͺZ1]½΄m_κ'Ϊ†Ύun7ύώι(¬ΣWΈR‡ιυΤ­71΅fr—ΚYu)›Αn.²ςΪ }ΟR,Ÿ‹²ήΛ5…‚φ‰΄ϋp;=Ls…Κa4€€ζ£ %Ίξ&ω‹αŒ,b_0m°·Φ"ΑlΑF‰Z GΥ'XΡζ σίήξώβ«³Ν2ij“Άe„’”΄j„ιQ8ΰ«”όˆž­$%΄πWηYxŸš°;α–,Žή#UiŠ˜ψ•wVΙ«ί@†£s°z&·n <`@ΌΓ―)§›‘rλδkT‘ζh€Ι žL$ν'ΨΎΆ<^λ+ξM;Ψaζν†υο'αvDά9-Ÿ²…λΙd8±θς؎hWΕ^C‘„Έe:P GaEb₯ΎNΘ(°Ši^ϋτΑΜο(§ύZιώ~ψIXΓU)ήζ†ζn»—ίόυτΘwύιϊ€“)₯Zqz°‘JuWOš]FΙW‰884_Ό €Ά‰[+8‘<žۊvNqυzŠrτ]@±½Q5FD  ‘›βΌδ„»Α¦.Τ²MV…o SšΞRšMδΩoξžο'τSgYΆΦκ[πΥ΅μ³ΥTqΪ]NΘΓ4ˆEZ4Q‰ξDT)T―Τ+ΉΗΤuΪν}υUΓ³“(z)%΅ύUMΨyR› ŒdΥzοΨ.’0#ςΗ±UuΔ^εRjϊ2΅ΫzΗ#L†γΫ‘>έίs•ί:hwn…Tu/ΠέύyΙͺSrŸ BΞSŸ—§~ύΚo«ƒ²‘Ν7xόί6”fΒψi­ΜΉ7ϋ\ρύifiω›cΗ5λ"bCEͺφ> Tnδ« I… ωΑZS)ΙEμDDΙΤΙƒj¦€2ž™ίχJςνχ―Rͺuν`N EΨξχVmO₯&9*±Pρ@Ρ:ŒΚ³(b —’ΞζΰZ…!Θyr$xΔΗΧμφ§s…i7œnJΧΤu"cε.;H=Έλx/t0΅υ˜2Uγj·Γ•P0O£Χ“γΌnŸ99o δ`ΜE{ΫΛ₯aπ)cγlο ΎΥέ³pœcjέSΉΊ43œk²ΒžΦƒ’‘E‰…-α0ljAΡMυ·Υ¬<°υΌ·]δΓ&ˆ φ$Lδjψe]ΥsyΈοοΎφΈ“&Χ»θ–„έΉζT‚Β‰E΄QώSS‹‡95ι‚H₯—RLO‹ΦΊœ(Ύ‡χaq~ΕΊa}2RτŸ#Α<Ύ4.u/YR1>ϊ@fLΑͺα(t΅#5uΙ#γμΏΊ:PO%EΉΡΡ^ JξΟΚyΤΐRA#‚WΎ)ΓMkι™ͺήuD‰g²f Θ)Φ“½tφI[ϋkMσ@4-+ΙBΪ4…Γ6Dε ;Ξ›ά±-{n-­m*Ά £R1·¬™¦†pτϊzΚσsu˜;@ίuΘM!l’XcχΌCΆY±$Ψ;"ύlˆ/,·œw&«"]Ξ;Ώζ¦`œxοα‹«o[£raΌΐεόΕΪΙη^Ώz0b-…{S —…n½άύ:UΆΔœ‘ΛUi†3μWZ‹œZΟέy©A9?™Š«Φ_Δhlipπρ― 10 pό°ˆLĜD ώΟοŠΘtΉˆΩLhn¬πԚ=ςλm9V ‚u\>ϋ)ΡG"Dm]Dɝ2³¦LͺSμΉ’οX(a€„'ΡΦ+Ήcι9)=Uμ?Œ Ρ+ υΪρ(–gJmˆMÞD’Z‰”ΗΠiγ«t•+ΐWM%FΚ€'―%#ΆΦΞGJ*ΛΐΗovγt€»EΪ}·­ ŸΧiΏϋ•£ιY>0Kπβ$ε€oBX[ηB’p=ΪRD!’4lŒύ9€FS].Vσ/•>Qύ 0Π―~«FˆL˜96aΘ”΅Š©rΡ~ ι0>Ω:.†‚Ν 䟁€†A”Αϋq.Ηx ΦΩΔ₯k΅€Ώ}€wςρN¨η†>¬1MΆKΪτϋ)̟ειώβ΅LΗ=·K&3'WγΫ€Κσp4/½&’ Ζ΅PcιξŒοΡ ƒΎ”ϋώΰ[,©wM½γ­Ι°σ―j%Ίφ“ ΘχDχz°ΧΎqJKd#:·†¨ΨŽΘ°ΪΠUͺkΒΎi9"€PppΩλ(Bu†’%!ώNυRΊ~Ε ½ΎΎέ·ŒγξӞόΗ.™ρ?tν9#]Ψ!XVμ "ιœHn¨Vq ‹p+©bΘ1{„gΞfΨ‚—Q’όΑˆδ³32ά”œτŸη₯7PιͺΊTͺΨ΅0Ρμ«­-Ii†1M@VΤT#Ζ©ΰ”TΌtŸ;+φ—Β#―^OrWΰn ™D¦&. œΤ>³ ˆ'qͺkΔϊŠZ[ΜYΔόzf‘„R©e.n:½·ΗΣ„Εw¦7J[£}Υ0λcd€‰ΊR]ξLKΚE8J²°³Λ½0Φ  ΆζΚυ¬όs]Κ2ΜΎΊΎ:iI=¬*N›WdDΟΨφ!_­ͺΈͺ–φ.Δ™ΑXL@†?„}#©ΕφΡ4}ύϊς΄q‹]ψ57’±œ«όε™ ©p³T:Ύνν'άΌ¬ώΟ ϋί^Γ‰ŒZv9Ή` EJͺKΰD‡2a)αίηΎq†¬Ι 6Ϋ‹u[ο&ΔͺΦΫνΥζVczFΔΫΟUg“R//w›Xσ‹\­E‘ΖΦδθςσ­υφ…ωvV—}ο–φΘ-Ν D©IiƒRΩ₯Ύκ©θAαΈΏ„huοΝγ °]ΣXΉP-‹Zϋ{τi μF‘ό"ΜΫk€vο4ØΓο[29(m7£7λΏ~ƒo_ξκΥ©RzκVa*βޜ­\T‘°‡#H(°‹^ΐτYθ$7V€ )iΚ¨š»λj’TfDΐζS‰ELΚσλύΟλη°OΊTfH3‹8ΡΑFΌX³” α0Ύd―π’—Qp Ϊ ρ©Η.ς·J·ΐΩ^―NΚ9dxeΠa,ŽPAhu.E2γΩ„τ-\Ž‚>€Ϋb‹SΐΒ¨Ÿ€Ώj–ΆςQτrnΐ›˜ηΪΓΆ ½ ρ±Π­UJXMvΙ$ψGΓ쌊:Χκ:λ ›@Ρw²σ$₯ΉώΉι‘άΘούΆV< fΫr: ΅½Ί‹ίkJΒΌο_οκΧK³:ڌ²ό΄&PΑh¨Δφ6(i#o69Qƒ%4•^R$­cs81" Θ?ΑLD?Ώ>}ŸœΘΟۏݜ^{Z0©IΙJΆŠn"OT»Š U8Ά‘*ΧpΉe6€eϊΨaoΊ.eώ!;;ή΅:¬zH³δ_ΆgΓx·ŸτΚ =Φ―ϋ>εwI«p!Bτ†”Τέ(ΖpI5‘rXv=a 'Ξ6Ϊ αΫΎΩ δX:θ MmΗf₯r΄ ͺ γιE³ξ8› yX‹N›©lr§nŠ$ΓΣe<½.“ΊοΆΌ©Η›|$?4"υΆ-8<ΫZΥΛδπSώ nœέFΩΔpήυΌ2]ΛK Κu\φ6>+ς§¦YΨ.£ΛΐHΑxi5*. ΅_uAL\NS˜Π7ΏΤΓΉ^ίγxyιάE΅MͺT’eμφ΄kr_+ί’1AJ{T€λΤ‘υΦ™δ^¬η’ Ε‰œ‰ρ βΡΗΜΐσ₯«DκQίfη=HyοΛο€c + #W kk`M–γ=(8Ϊ’§DŸV±S Β»ς₯CάΏ/ΈΈ+ IΨΓͺΤ!ΑπIk΅ν_Πσz£‰!£•6=auN τΛ)`‹ @Tl%Wͺ-Ϊρn}©ΦtΪ !€_¦‡£bαχΉ»)ΨΦοΙUm’κi:©Ύ_5<LŠΑμ ˆη.Șˆθ­MzV=τŒXθ™QίJφθVόœJόρ#ξΨώvά΄=~ΐήOΪζ‘>] ~Xヲ‡:3«ΧΣޟ©)(’ #;P~D›Ξ¨―αq>&£Ύ½Όΰσή>Π#}™qς†ρŒ₯λ"ώΗϊςσY>ςθΫ[ώρότςΊyuXΆ‘Kl…Aΐn…Χmnγt‘'»€tnχ¦£―ΜTΑζ₯›έΚά=Ύ>έ>mΒc„]3ΐ BόιΖƒ1Uρέx@ŽΊί+ωΫΊ?rD»ψ½γΦjυzιLΊΜα`•nρ‰Ψ _.”α…ο0ZηΟΝA Ψjυz{χ {hΫqpE‰r{ϊ–£.ŒVnωΖX)0ˆmFwΖ–Μm―Mγ -γννΝθϐ9;Ι7/ΞοδRrT¦œLΛ­™ͺ0-΄»ΰ:“«Fy'4F₯χXƒ(οf;‘"½V¨Ο/›₯=ναΓΰ††ΕυρZΏΦ†!Οοή™‘x… +bnN.cJι¬jRΦ™L$ΙG%ρΫr±Aδέ»β”{΅>ο\Sφ„λΧ“τ•ποϊυ“©σϋ―}]φήο>Χ/š½εΫE‹ϊrHHˆτZ0ZΨX’¨ ν…7 h©ϊ&_1§•€y^9ΘαDΩ?NχXΨ€Ίχ‰ZΏλΜάl>πϊ„ν– e ½—«Vο¬s€‰r4IHΓ{ κ’Dhdš2Θ{j!M΄jTs³yόρ-σαq/Ÿάf-wž΅+_3kXα E ΧΌG°Ι»X©‡RLσΖ(«ρPu―ͺd| œψ)ˆZΎ~,Rθ_“-Bd˜L­Φ$tΖDQ`Ho±Z‹Yχ»ΒΑ {i9γ6‘r³?Nχ™q._•«΅dq–+)ί1hT”jο( Ι8–ŠΒIοCΚϋYQ-M’ αρΠ–ΏΚJθL½¦¬a΄Έkƒ¨¬P- IT„ςzχNE=[›p&aΓzh)#†ƒ+uή/WEχ£θd›Θ`3²ix­σP΄NarjΥx/™%§€gχˆγŁž½HήXδ«χήW²,ΤΕ²Ž8]ΝgjDzβιN.Ο¬\*fesh63E!2 AΫzρά]6¬'£\ή¨Z•Τ ‡@pΈέpμNŠ‹sΣAK3ͺV*J©C„ε-&6£‹±F Ε.Žς²½[] „ ΔΦ†£ιΰ3…eTΊg€Δ$n₯`M»ν=0W¬9& εD0₯‚ltump •¦ͺ.R-*₯K-Jα¬*kՍ¦z.Εc› W‘:ΓΖ²πη7QNϋ±]ϋγιeυυξ$Ίό’6γΌ¨†Ώ`Χ8©]Ϊ‘΅Π†`ΆmQJ₯ΰ JΜ†7²ΕFΰ'£κ’~Gΐ"‘Ωώ8σΛη諉΅ψ˜DL^8Ε›c‘=φ>ΤLšΌvˆΚΨHΟ'1 μίΤzhiNj’εo/‰39ΐŸOGYϊ+ΤcS&‘|ɝΰ1”°Ώ’t©h%’Ί*(Ε–B„3ΕNmRΉdEh’£‰Ψΰ2‡Φ6™tΣ€hΪΉΫ₯`†Qޜ'ΝΩ{Ο±dφβ5T¬xχ’ΟWfξ)—H1Ϊ ¨υΠ·λ²ͺ~θΧ.¬ž”D&(ΐί§`_αflbή_ΘΦ)˜ίώίO μ»”"šν6šΙXœa1&x7.1Šv—Χ>iιό βο²ΦTΊΒKψ@­»˜c@š•σi’šδ4M15Θ}N’“kΏΈ,³ΉΰθhΧ&4—F||©V*h,ˆ.—.ς –R†Δ>ˆψ1 άT£ήΉQ,ί.™LTΒ ,u ˆp`³7φέ‘D4p8°Γ/τH₯HYΗљ葝a‡AΎ­N»ω–ί”ή @7έΆ$DΨo57ξ†ZΛ•`Λ;ϋy-Χ*έΠB οMA^*άLh=Ε‰59_ލύυ@›j7U[­riΛMβ^Η°y/΅Ϊ¨2Γj©j­μͺxΐލKΉ2Q I_₯:α…Vw›Ϋχ½ΊΗaX7«Ÿ―τc“Μ}ΛΉ½ͺηϊ€ΧΏ&.ζ^ιδμ¦ΕI& `«„ QIDUS,-‹ ΧΨDΈiP£¬ΆγΥΐΩI—Pm‘eUΉη‹χžg‡Ή™“rq–HD“°ΏFͺˆx RF`S|‘Zρ%:i}φ­³²žqcΧ6Ž6©O¨‡§o|Ϋξ^nO-”_| g―4g+Δύ)•l}ζZ e#d#T­ν ζI.¦³¨v¬ŸX^ c6ό ϊ$Ϋ:έ«3*$*,^Κ†ά%Ωΰku’*εζRz©aͺ[ŠΦΰΠN‡YW;Α₯C+±^cWˆ[Ž£ΫΝΧφNmΩF.Ωdl»/nΚS[Σn}ύωΌΑ|ΓWƒόαίΆ½”ΓWX½KOά·=l/kφ4ΧՐGŒLϋ_#„c·Vo/χΓ/mΈ7ŽΉΊŽώή=Ρl½χΒΝfJŽΊ°‡­„pn­žξΏq»=˜¬ΣŸ}Α»₯;yϋ~ϋ:“œν°γιαMιΘύόΗn;/^hoΩOωί&oρOξ?exιύήπ„ξύrqλ1Έ½ϋΕ3[απΚυ“b’Šζσ”{“bŸ§λΉc¬;:»:Ε‘Gη£wΩΗ΅PΏX―1Ήίne@ΧW.ή”‚k0αΚ[mC―T#»”¬hrtί+p† Ϊ’zτL½$% [eJθΰεK9Ή.\\UΔ¨<Œ°ΐhΧ΄Ιl”ξ©Ϊš*ΐrŽRωeŒ‹‰TΣ9Γ;η’”3ά[™zφΣ ―Γςδ#CΤβ€wsͺ'Χ…]ξxπrOπΦ#Ό―Ω&Š-H\†ΤB€cLŸH~L’†ο”3†‰γ°φ(―ς΄χsδ-ζ1⭜Οφ-%“ΉΪ|ΚψαοM 3“ dˆ#Eζ¨K@蝀j΅Š"δJšΫϊ6~{ΆΫ“3zΧ>4|ΚΆ,ξΛWν’ΉYΩDp/7GΓ«ίq–„‰°Ϊ„Ψ”v‘V—»ρ±΅δKί»6‘ρD^Χδ,kΈ4œ‹ͺF,ξ;Pš€FS(h;Wˆ"αο6Fmσκκξ @ΛΫΖg7 Ϊ «ωΥ¦ λέKύxΈΏy™±bοOρίhέφzO¬nω‡^νϊψFVk·H“s·ϊΊUω{ŸΕΏψεIΨα/MγŸ«VϋώΈ€ωtΒφOτ™i;?-O'}φ]φΥΉΏΘά¬με;f¦z·x…§γœ£Ψ·E_ψŒΓ8ˆΆΎ>Pς#»xΉέψΘ“Ξε’ωJζΐφ]X΄ΧΦφξό9=ήΗ©†»[˜ e}΅»‚βi‚pj³sΞ»Rο¦oΘ1{°ΎJ)Χͺ·Žι&SSNΊ–>‘$χή­zf€{¬D'μωKΓ} +λͺ8ˆΒE`₯²Άl­°ΉvˆΠΧδ|r‹’ZπΕ4aΔ,ΒϋΣd 5 cθJΉ6]gτNα‹’¬r`ΞX:V„o\ˆ­rRΙ’YJο΅)ϋήr1©–τιdτώι? ˆ'ΓΆ‰νP[6ά/ˆlz €J Ά*%Ύ&yBaνqΆ½ ‹ήγ„jՎυ?Ÿ-$=3Π+θi«Φ1§X½.(…/­j’¬Θ“ι₯ΔΧ/Ϊ°9ΤΠ‰΅χΜηͺυ₯‘Žσ*ΚΕ7CΚ†VC3-υ¦₯¨ΒΞͺΐ&—¦³-ߐΞD…%OΖ6OB,39„53ΒώΒ5δ±RžcQFg’ίζΝx|o|s1ψκs‰5gΛ°&Ϊη^ΔXsJNΫsδ!ƒ©SG‘Θ@`t>ίΆw“vΤΦΆͺOΟόε^Ϊ&Γ°¦Zρ—xtΪυξlπύm5ή^{4v>’€ψωvυ ΔΝΆ M©Αa»pgaaάM Ψ=˜Dkœω–&•ZΛ³Σ<%έ²’Ξ˜Ζ“sn―”©lc•֍8“hοΐνΔځE¨Ϊδcχ5%ί¬7EŠŠŒΆ#¦μ¬kjςρψ¦λhΘόϋ₯οΕ“ηΤ„ΘΌκS‚mRD*ΗE‚:h5‚q*γΝ‘Ψ ’°^]|Ο\¬έœOΓΆ%3WG kΰ€ΌŽ0₯’ άGΫmΦ"ςCιΒ4ηU3ή ’\Ω[2©‰1gpζ©½|,Έ|_&ΐ‰Πl2βl:)'ΞƒH$SΡ‘RΓ6ΥU7[’ PπΙͺΕ4išWL'€Θ]αρρTJtP\ξρ""ΘΘΔؐ!wQӈxIυ0΄ΗZrΒH” …2ωψ›ϋ’Ο]ΊυHξέ¬\μ™{ΟΓ\F]Ύ―Ψ>ςMΑ+7ν! Γς%Ϊ6DUt3ˆ‚°Ζλ 5άc$)‡©Jn₯™l/-Χj©j­; σ.-͐u‘κ¦?½=Άw―uτΪϋ•ρ±£<‘σ|³οΜbΔνΝV€AΡ c‰ΚVΩγŠyŠψ†]ΑQŒ.xψοΣ¬Ν;rΦ$MΞ„@ΘΎΑΕo‹ KΥQ Age GφΦχ\‰KLF΄Ύ#ŒOΔΖιˆQUΛδ”›hΥ[?ϋΝ€b^~S»VΪνΙϋȐυςΕΔ@•«IdJͺl•&rs#žE™€Ju-₯ΐ΅ ΒΣZ%$Vσ‡FΊΌi”ΧΤ΅2VπL—ž!ΏνJD§Cƒ₯@„ΗΙ4c­¨΅vcNIjοΒ„VέρH΅:W#~πξλ…₯DΊuγ-ϋ$άCΖfƒ£-ϊY»‚™h€-BςzO€jR°ώά †α/œ Βsϋ₯FͺuΌ•ήš kKg­†aχΕIΣ BΣ [ €­'Τ^žΟ@ζIξD…Ε-νИœF`-¦€vQΉ+₯1b4KΎl?ަζΰjεͺΔͺ1ΑΠζ‰yΰΗΟ ρΆ–§—λWˆ!ήΪ~2=+N%ZŒKs pœM»1()Λς‹6`&2“' ’¦=¬x6ο+έχyvto:Ώ€™½Λl §ͺ—„¨―`ΉTξ΄zΝέ Σ’QI#βν¦Ϋ€΅t3„¨S¨KκΧ¬‡~χεριe„QyqiΓjjlRLξΊι@YΙHΫGν³“΄|joΚzXαštW‘‡nNiυΐoLoζK# κρ†₯Cώ˜3ηΨ°ˆ™±{½d€ ˆŸt!RιGς©ϊHΩ2V]aπrΖΰγψa½{}ΪtX|›Ώ›χςφΧφ!,Ν%qθΟΈ€Χ„…M ˆ ήΔΩζlΟZ<„ΦR‘€›r1ΕΩΚγ£ξO/Η—Ÿ›‰ΡγΈ}ρ–€άlσ0Gƒ‘R€7 ΝkDΗ֐mΉ $τ°ιNΚW&NwvgοδŸεβ ·o½v8ξTT A@Ι’-η‚§¦[ν€’₯ ξ(“₯NΩ‰ΈWΖβg› ‰‘ Ϋ³o³ £Eρβm} Y[=Ύ"«χΦΟΦ«Ξη:WΤzL)4ŸIhΊδu”-h*g{R»Ιάκ-1η%‚ŸΖψ|Υλ>ΙΦi%μ³ΟΆβψΣρ|ςaΝ‹\Ύί€°φ RvŽfςΓύ+Ο·ν;ΟΚ3άJ_›8ίdkmL­uF¨ΚdBw"₯γK#˜hαR)=ΑfΙ-’i5‰¬Ίj°UBn['N&ζΟ,qߞ‰“ϋ‚‘υ¦<=έ<=Σ?ίψ¦qyϋrnrξωΗifuiO.m0hΕ!R)ΫC'j’1ίΰΆρσΠeγ|m‘\ΛͺΙ5_†M67SqΡzγ₯Π[D™78oάrHNqm\=e՝p7l„Ϊ΅‘fΉE6Ψˍx’δlzΚq^•δψϋΉίH}όΝv`GΙ,3«ΘG“ͺ‘z8`¦*D?€œ…[Ξ‰•Ρ͊Z’VZ΄zδZkg•9ßοV"τκχ°$²ΚNΧh£α(­5EdŸΰP“ͺζΪΰ₯,6ϋœkΑB“‰:[o€yuJohuOεκΌ-’S-04>dD;‘Β\x δt)Δη5[²X„Ό­a$–λ§μ˜₯·yςٟŽeΝύbLmpŠ΅e‚uογΐˆ"υhEDjTΌ+Z’*o56JΜ³ί k“²9FŸ2bπ@ISR8C­~ _όσ•ώ„~{ύ@ΟδΎCώ lya^}Ώ[}ύ½O’bρA`]Tδ€–ͺHΟ¨³9g€Wl:Χ5 y/]c½~ŸϋΖρЬ—z³ϊΎΑ‘S•Ρ›I:7 'α«Ή7F«ΐρΤ»a υDV˜—ΐ‘Υ†ΐFgχΨ Ψ_”ξLSAW;! Ί¨§K/O€έΓy†ξ%3Ύjιzk]~#sC£₯‰"α€#$TV=ΚΕ7w«-»drva| Όn0θώLμŽ… λcGβvTλ`ω+DkΥb•“·B8Ψ ώ‘5)ΩΚδπ’ιθAJ`œμΥ<°€υή²hT·₯ά;‡‚x’$ˆΐΑб°Ύd>(δzΎ~EšΫέμ?jv-’ 6ΥΗ¬\ˆΉP¬CO’ETτδ‹΄Kj—˜cιXiΌΥLVμS X˜QΌΆίθu’¬ϊhZŠΰO#»•¬ n?Ιu’²šAz½ίΨ;“Ϋϊ0Iu”‡ϊTΓν *η έΥsREcΌΝS{τ•ΚύππάΧ‹qK/RΧp)f0˜6a’’€½΄uSb %‘¦ ”š”} ρ4€b…½j“ΔΓέ ΆΞ¬^;KMF$ μ€s Φ‘ΆYν”0LtΟb‚Œ† ™#©.$%Ι­q±p›ΆOδEφαIΓΧςΠ‚=ΤΒΟ¦DΑ\;ΨDΦMT‘’EœBx\Σ*lcΕSΗΥ‹Œ‹Εq™ΐκξα€λzρ &―u­Έκ}&qΦP) –-ΫδRzρ­qP"ގuΙΉ±Ζž’@yϊΌ|5UYea‡9cs{%Ή@DΚ1WΡυΡΚΙ=^-RNF°«₯ˆΨ³EαΊκaϊιίκλΣσ)ο‘Y<%hBCΜj26…sΉ«’CΟΨ$ΦΏήφ,ΤΨΉU‘₯PTω‹Ερη‰.ŒέΙ±9ή μ’*ήΙ;1‡^œlέ³t.ο#ΰ*£<ΜBΤˆ²WX ܈'EΫΆ&Ϋs£hθ'ϚΣE₯¦C½ξ_Πp“ΉyΈΎžS΄:UαIφ…|μαžEΌTμFξφΘK·ε¬šƒehΑA6$~<4<ϋεΛΚύw tιθŽ9ρVQL‘ρ€’»£,œoΑΊΞ‘ξΥ%―ω7Dχ&Δ.χͺΪεΉ+±E~+―GΥπΧHξXaΔξ^«j²φ‘tγdΧuΔ (’ΩIrΔΑ!Bτ NΖuS-ްͺO"ϟειΡ'εα(G•ΐk TA’ζΠ•ˆ²κ"E¨­™ ”ά(Š΄ξΦJ\^«.ΡF„»ΒοααχΣ8‘ϋpγ΄ΡΛxΰ‡­ZεښΡΆ2Ϊ"x))1Š₯ Š€ώ‹lδζα”4sK˜%±aVΨ@E•M,φ8’+ŽŽaΤ€€λήΦ»ψp©ΟLΑi©M4‹ ›³Τšr/¨“<«VRΨ‰ΖΒ)|Q£p‡Γΐ…W|΅Z*Ι|0=5Kς1Έ€·‹·…ŠX±fM₯ ‘Δ‚ύξC/5JާSοO?nv’„η'²“ΧWˆH\kΫ’#]=Γ}…X0Wλ*P§‹Δ‚9«uΨηR‹‘{ƒ9kIηρ„ξφιΟ'tήuυqΒ·h9X„Ίq%ώ§•t„š»Ο„γΙΞθ €šqž4δ !¦“‹97ikψαΉέ–,½Ϋ΅οπ+½(Δθ­‡”YΑR6]t±‘E5ιŠ9F 0‰ˆP*­i!(‘Mk"όΆ–[t0°N―Ϋ6A·?h{…$X£ͺkΤ­πͺiΥS‚ΫΝ%e§›K•ŠΰK„ˆZcμC§Ν’…OQq™¨N?ρ·£’SuocόΛ#Σ5ΫΏ_ͺ^£:Έϊ,ζ―fίr€S*άXΨ£• 8 „γ-΅¬rPCO¬α €V°γΗϋύΥ>9ΐGζ`υz»)ύxΥθ|©Κΰφ’ν'Ιτe²ηόƒλΫλΖ=žM©›”MΌΘ'ϊ.WΈ‹Žλ#ί³ά—9C‡?QŸyσjυτ²0‡μΙMΖΘτνΟΖA‰κ:ηΏ^’³ƒŸVpΥn|.šηφΙIωsκa1οL ΪˍΎGiώA4I©Βώ`Ωυ΄tλωΉόάeΥq υErΰ %џεήΫ€—耦iΡ!}ωΠf^ΰͺςβڍ.Βω΄ΝΑQδi»`YΦx„€ωΨΞώ’E~a‰c6~€v§cžSΩΣμϊμξό€X΅Lΐ\.rB8ω}CŠz,Y}¨σΎmω”Λ―/"ΫΌcΨ~'bP7;-ίχ—aϊ ΓfYΝι,Yτ²ώsvoύεΝW¦ϋ -Ο;―ίΈM<‘–lΣϊ>x.ΧΊΘΆ¦ξ±’˜ΓϊnQe8/Ÿ6―eŸμ9™Τ“Ύ,!½9OπξΕηv–~Όvαέy€ͺ‘/_^>…v―o‘ικτΟ/ηΑVθz‡šπΕνWΎίξ‹M7— WΩ‡ΧηhΦ„ ₯-ΥHŽKθ^κf«΅Š]E%―BΝΞǚ›u&E–r§$νS9Ίc:¬©Qξ2gΗ‰y³ψU9gbλJrAΔpD]sn-(Za₯Z•V@#y€’T>!@Τ½vF$hΗωαvΟƒ-|?cœλχ]}°ΉQέXNΎh½tήgο"Ψ™ΘfΈT4©κ…QΎf«’qΑ€Φό’­%ΔΧ&ul’Gnk§ΐ5τ’+E³vΙ₯F8Μ‚Ι’Z’Β$pΦ- Ήh7ƒxjj˜GvižŸο~+–υž6“yδMl[γ­FΚ/˜Ό=Λ6ύΨ±Λƒέ>ΤΌρ6zΉίz₯_½‘>‚™ΨκρηΧ-Έ:ΐRλJΫ‡­:‚'ΏRηwV„γ8 ~Z7aŽ,L°}χΪοψ~νͺh£€#ςξ‘Άι›‚z‘<|yσϊΧy6Η€Gσω z7#Ηζρια7‡ή$έίΆ½Ω«©”oχπη°τάnϊύ OδuψŠ ŠqsEF0ΤI9αΨOe¦«4Χ‡υς.xΗ7>ΣΛΈƒβΌb{¬~Ϋ\^Σ#ζn§'rΫi1 ώΛΝδ₯ΞιγžΏ_tnέQτ·wwλu!Ι\›‘#7λXν€ύ“ƒ‡]­ξGß3AΝQrhw°6ά‘ηΩψYZfέ?ˆνΏ?}§ŸsPΌDϋ‹νεζξ†ξŸΏ₯ΈfMΗΊoγλSΉ”ύΙ₯<ΑΨN™4xλnŸοίΖο.y“`ΗΩ…Ω)ΟaOπτ5Εώ+·λ4Λhz°±y3‚ Y…iϊŠίjŒδ ΅¦€kφΩ‘ΞίγλΣνΣNψyάΟJωŽH ΑξΚ"&Ι6FLNπNΦ°%ί+,χtOR)o/ψ׎ωο§Χ»ώsΜςμ‰.εbΞ¦£z„ yšc‰΅G~¬†τ³­_Kχkςks”χfqΔ›:ž zWb[[XΪU[εˆyΟg­nΉΊ~)Ε΄,^#ΥnFΉαε_ž1:FnssHGΧϋ›ωδbc"«΄Υάψ%ΣΌS 0φ@ΚoφΧέs?ο΅nκλύ-Ί’?}ωWπεΝΙϊOΰ)zhΞδ…ΧŒUsi‰ή[F>KR΄; η§ηφμ?xS0uΊyές=Ω&Υ€ΨY銌ΑζξœΥ!SPΊΠΊœΒ υΧΦο Œ»Ύτ’…ΰœZŸΧ$ΊvR•PΪΝΪϋ@Ο׏ΌυdNώέΛίΊyo.”|ΛφV‘ Φκ’ΌŽΉΉZΌς5΅΄£Θ:5“SަK'ήΕΆr―΅χlbO‘Ωs’}{€γώ&ζƒιΧή"Άb€ž€Ώ€¨}©>&―t"›RΡζ’“*Uz¦³­ug³mΦ6—₯ŒmήωθŽψέΞ|οΩƒ½½;³χηκνX΅ζΤΝz±ƒ%³%s2ίMΛ~Λίφκ-Ǎӑݘš± t~ΘG±ίτx#Ή“4δμiΪϋ}ΰφτ(Ά˜wKzšψ€ρΊτ€ƒΩγ9]Εs)Σ1ͺ»sΛ6R£0΅p›ύ™Ήέάί=Œζqψ™Šυ3qωQ½.$­ίWώrDϋΌŽ  mϊ)=λKθCAέμΰ΅ θΨΎ«}5'&›‘•š©+yΌgΧdYS[ψζΰ·nvD;ΣρΞωζύΠ$qΒArb2tΨ »ΟΉ”Ζ|8•–s‹+ό”ΤjΪχPυΠ%b„ήή2₯΄$*Κ.ΖAΠ ±σEg¬’›ΌΖ„™^σΈjYαΓGκsοξ²W';Άt@¦©κΌ§V½(œ9ξΐŸΚSFΥ|£ΌeΕ9[)Ξcρ=/“:Δ¨#α"IΠσέγ—JΟ!°‘ΔvΔ±xCDΎwνU>μ. Υψ&,FΖΔY@ ”Υλώ]ΟΑ!ί~sSήξξΫωan3½sΛνΪι΅ΔQφΰμmΝprX&Π ͺkOΞlˆ ­ξΑ8ΦFT‚}β8g‘+ŚμDͺP΅D/VfDΕ`άύΑΔΤώeΤ±Έ=΅‡»§!g₯υ˜υίoΝ;Ιٍ©¬Ž’yΎΎ½TδΜ³}hBO8]Wχ(¦IΓ°σ.΅=λ“N^ΞΥ©‚ 1u“«U ab Œˆί!K:D}ψphkζϋθ?¬Ύ4 "²ξAΈEkς6t‡­¨2%Κ}`0³QΥ£βZΊΦΒάmlPBCd„ Xz5β’+ΓΐadΎρrΏvοU-}›₯™‚Ψ·j’ΣξOθΰm/%/-γΪ΄ͺ„Μ=&.ΉDΗηήσΟP>L8/SΥ…«―ΒVJQ³u>'ej$μω”΅ΡΙΊ²‘ώ`εzœ}­ΎiX/γΖ‹±Fνp©j,N€Cz19ο­ρ.xy;ΕwωVΫΝλΛέ©e\αϊИ…ΒMψάTΣδJηΫίέ”EΌcQNŒNΤ@¨Ά§ž`C|CT§žθΈ]έψ!τN‘9`LŒF#vΙΞ q_Š˜k«:Bw ½ωxΟBˆD =ωιa¬ΫeΚ]»;K³4ΉάMip9€{πJV±nE2’ϊ^»$EΟ‘|CTΪ FΌΦ6tΝO72œ» ίρριεξοώZ‹Ÿ8δ₯Μ»˜½5…ZƒΫ°Ι₯¬lV‘A„σ"ϊΥd©b}Ξ‚κ€›ΟΤi"uϊ^|a΄+ώ"|T§ƒΥWΐ’:΄€­Wλ$coQLxφ#./jeα»2,«·±ο#°Ζ/XΌοΒζ\χr―ΨΑ^T’J‚ύ¦‹ΐίΐX0 #m0lX‘ρΚΪμ„*Πi`ηΔUΜ„ :6κΒ „(νΪ#™ΐR,5 &+׈°ΥΗŒBΆ +Χ<0‘ι ±7)"p‰ΣFβU`D9qρτŒφ‘Β"Γr1Ε`Ό‚qVΆ΅ΰ΅Œ'―e@ ‚?NΏΘU=7EŠ+ΧMΗ ΰ‹σοy`9›¬p<[`…¦SΠ€=β“mΒ–f„ήE;‘χ)x ލ€€˜κ|ΡΗφHο•°›Ϋεj±)ρΪΣ C|υݘ»]qΒΒά›Ά'«₯†ΈΑ%E±τ*Vξ–:l+ΐw,λ"t4΅˜#—fρ¨ΌW>yo*φd•)00Ε‘³–XβQβ` ].ΆVΙ¦xd yt9δ—GΎ·fZξ~wO`ώHgΦπνĘ€Ε7t©°Ο"]]lœ“¬0<˜B)κζ{ΊγL†€`BzŽΨΞ!Β•‘­Œ'ΖΏπ« ⧇aˆvŽhι7Ίς‚η»}αΎI-ώ΅ošκEK…”sΡ26.’ηž$Q=Β,( ¬GwΓl$€•Œ; UpιSFθ[}ώσΛιΎ]zγ₯J₯ U€₯1Ά[fFΎŒΠ8—Ψkkx‹χΨΖthˆ$e›±†1χ)Vt€ŽΫ‡“πt…s7…'‘rEL΄KΔV― ΥΆ’Β`80†K#-œb•M‘Κ)VΰβΙΗžϊvψS'Pbιά”(Δ‹Bu ΜHe&@zo©ΤAu%Ψ€ΰ’ΤΒ.U`χ\+ωd\ͺUDϋŸΔςοΕγH†ιΛΒ;H9%ΈαV2’ ½(Pωα'E Ώ*X³ HD<9ˆcMΊ‘”ci-O¬SVz9Ν@€€0G#HΘ@HQ;ά±lΝ-¦"ΨA φΖ7ΉΨφ§#»;τΠ/ΝeKpˆ.%Ι•ͺ°»9+¦Πβ½"’ο‘‘(*ΈΤΨ©•’˜‰E‘ ¨zjή·εψΗΌΪ‹ …Ζ¨“ΑF·ΎgΪΘcΪC³P4;Dg‰HSΝEŸ[­φΥWM¦ΗqBκ•°—ξ*“Ž.Σ·/ܜϘ|§ΗΧ«gΥuexΒ€σ kΓyξ ˆnK™<Œ-ΞMa€Β[Χε’½FΖE¬8žΐΪ匢™Φ3c\έ]ΐ°€\meWdK’ƒ Ϊ<8Q>©PcίzdΟ$‰θθƒΤPu‚έι zςμ§λίευAδkυυιυζω…ΏέρχΕkκee DNXSS΅ @ͺỀA X˜o‘GFP5±†ι1=άό½S’σG\zaΌ‡ΉˆΪΨΖΡuΥHnι›Rœv‹ΉlK6]xTKa€œθ]ρΆπΌ+‘ΙjΔύΑ‹ΞnΤχχJΩ*ώμυ'(–κ‘ςΠΨCd κΨPΎ*xRΪ&©zͺ ƒςkkσζ«Ο€H‹β,±2M !3sε‹ζ€™π)0gŽžzpδZ Σξ¦|Ο氜dυ—ΎzQKΘZ„b”²rQ‘γ §΅ΆRR–“v¦!œMkΌ₯R΅rνCReΌΫjΪ L-έΧ»z˜$vWη2±€6ΊΤ!†¨Ρ7Ο=1c₯f,0¬‘–δά±†'‘ΐNχ€΅ζΉU{—ƒSΓ οΙζLKγΩ%"UMΚπ­[硉8ΜZW۝3ή'gͺξ‘b‘ο΅²”UV)N…γ£O/h~a@T“Eπ 0T[D›=βΩl bprJΝΩDψϊ ΩJ}Κ7“‘T=. ² 6ξάožλ ΎmOίW7_ίφc‘)άwϊ†³ΛΉ)?Ή›Z::nV‹œ ³£J.ζ(‰ιP΄εGDέ:hƒ0™DΫΚfE]D;Žy.υ쒎NΜ΅uSaO Ž&pœQŽΆε’³f©1·υ{χN ΛKΑˆ»εή%n‘βuX9?’ΡΎ¬₯-KΤ!*u#,-ΞϋΘ½)Ξ°0U”œ”EΜΡlξδ»νΙ ΈΔι“Šžs{υRΩωΩ-{ν₯ƒO`ƒ(ΡiΉ ­š‘³ιŘN"=ξ]ΠΔ’%€€i@˜ sΣ+‚-˜ΣK‡‡»z,,υΠ­ϋ%¬JξΕΒ@ωδŠh7†XαRƒ…Ljλš”>Ϊ恏cYύ•U[™ΫΝUΒ΅/CšΟ•ECG2ΕXƒ@ !>€IΆΡΒΙ %Ε9—_φ¬―A§AΔ›•Ϗr}Υqd'‡]zμ7ββM`•*:ψήΛ+Œ$‰ž˜υNIeΚc>r.^’£€H'†Z§κn'ΈξκjέΧόό΅o{ΐ*υBί…ωΝn›ϊΡΎœ\y.Q’rHšH.’τˆαD€^<€½ŠΝ§Idpa’δ¦!§ΤΈ&Ρ7Z'ΖύαώT1}yVο°ΆRܝͺ/+gŠc ·„ν²qΟ‚―Θ{Ÿϋˆ±Έ‡Ψ?ρτC#γgϊΥ€θλ?δ·χ₯μ„…αεwxα{a 8†‘9ΐM—dUΛΝυμ;° gΏPŽίδmέΌK«―[YΏ]§ξqφβ =j―!κ½3υ¨½υ ΨmbcώΕ/OD{ν[<[n"?λjΝͺ{VΑ%O5Uρ3^T_₯ηξ₯;)H‰F'l[£v₯‰εlφŸ=\C٘5V.@Ε6qτΙ ο¬΅ΪV€Φ‚… &Λ°ˆ““tNS(ž]œΥk;ρ(Z*ςΏΛΟδͺfρƒ«qŽa:g#uVQ‹―m0 ρ#œ}­΅•ƒc΄->wx©WM¦Άi‚>a*ΛγϊB_Οόσ?όΟ?σΟΪ??Φό0cargo-0.86.0/benches/workspaces/toml-rs.tgz000064400000000000000000000033661046102023000167350ustar 00000000000000‹toml-rs.tarνY[oλ6Ξ³~… >nlσ~)ΆEΪ>Ψƒ]΄η­ΗxΪΪΨ’W’Σ“.ϊίw('©;MOΧ ŠΦΜƒ)iHΞπ›ω†Γ νz5ιϊΩ4ΈnΡ^έ„ώͺnR;ύwί6'j›βθϋά§ΨΧLi‘“Ψ§Œ~A.^‘mϋΑueyρm-Κ²ZΤCυi™»ψΠ/Ε§Κπ¨ŠDοœKke±Β8 F+N*+Cͺ.ΗqeΥΑΊ ]Γ¦t6Γy—[? νzζVπ!tuXm3vNWαΐŸςθjγ†%ϊ]vΏ<Ύ*~*.Ξν5Ϊ³/sψOσΣιΧx!ώ©ϊiό"Ε9ώ_‘}aM„&ΤΠΟ‹ΊεgeE§djuU¦5φ>¬έf^΄›‘n·Bα‘ΫBq]/ξΖξήLŽΜ~‘«oΰApχ2η›½± ά°νς˜ΙmW~ϋ~^lπt7pΥβ˜.Ώ«ξ5ͺζ8lγΒ΅[ΐΌpΫaΩvύ(ρ©§όςŽ{ΚΏg&ϊbŸŽ2?}ŽΓƒ`Ρv¨ι8,΄MͺΥeY‘ϊm¬›±Ώqj0©Χ›¬‘\ή…ΎΚzφ8αΈ)َ7eƒŸΠΜoΡΑΚqTΨ5±Œ°λ·©|χΟ·˜€Ά[»a€X¦z…kg™~θΐ­ϋiω―½©qκχΝ“σπa (‰ς‹εwΈ«nU³―ςνϊ«‡ΎΔ5ΖΕΚθWνϋ&ΉP―jœ P‘{y΄q·όήσ¨?κ³ # ΣχMUΔ6lTΙΦή>~θ§Θ&™Gͺb}/ΐ5U±lΧ°A|φ‡Ό˜#αφ„{ΚσbUhϊq·ίΌ›½Aμ—0aΩ·ίοΤΐ­Œ»ηoΏ~σΥΫ―§λ˜_nΪΎΪξφ£”Ωσr2•S“}΅»ξqut»5¬=άΉέύ0ι·5¦Δyρ‡ηΎ ³UνΌWηάωŸ¨3Ώ"ώ?{λι/α/4?8S©ΟψΏNώš₯=v–cvEŽ£ΥGdν§sMG©yqŸΝG^άM„œψς‰atBΜϊXd©ι΄ϊsόAJΪOW9v”]lΆ~UχyέδV=Ί8Ό8’Αύ ρcΈ3ρYMφwι±μδη6Μ2˜,£’Ι§tυΜ^NRO•—ψ œSτz0ybΗμ˸ўσΔ«σqΟνάΞνάώ¨νη‚"&cargo-0.86.0/build.rs000064400000000000000000000123551046102023000124650ustar 00000000000000use flate2::{Compression, GzBuilder}; use std::ffi::OsStr; use std::fs; use std::path::Path; use std::process::Command; fn main() { commit_info(); compress_man(); windows_manifest(); // ALLOWED: Accessing environment during build time shouldn't be prohibited. #[allow(clippy::disallowed_methods)] let target = std::env::var("TARGET").unwrap(); println!("cargo:rustc-env=RUST_HOST_TARGET={target}"); } fn compress_man() { // ALLOWED: Accessing environment during build time shouldn't be prohibited. #[allow(clippy::disallowed_methods)] let out_path = Path::new(&std::env::var("OUT_DIR").unwrap()).join("man.tgz"); let dst = fs::File::create(out_path).unwrap(); let encoder = GzBuilder::new() .filename("man.tar") .write(dst, Compression::best()); let mut ar = tar::Builder::new(encoder); ar.mode(tar::HeaderMode::Deterministic); let mut add_files = |dir, extension| { let mut files = fs::read_dir(dir) .unwrap() .map(|e| e.unwrap().path()) .collect::>(); files.sort(); for path in files { if path.extension() != Some(extension) { continue; } println!("cargo:rerun-if-changed={}", path.display()); ar.append_path_with_name(&path, path.file_name().unwrap()) .unwrap(); } }; add_files(Path::new("src/etc/man"), OsStr::new("1")); add_files(Path::new("src/doc/man/generated_txt"), OsStr::new("txt")); let encoder = ar.into_inner().unwrap(); encoder.finish().unwrap(); } struct CommitInfo { hash: String, short_hash: String, date: String, } fn commit_info_from_git() -> Option { if !Path::new(".git").exists() { return None; } let output = match Command::new("git") .arg("log") .arg("-1") .arg("--date=short") .arg("--format=%H %h %cd") .arg("--abbrev=9") .output() { Ok(output) if output.status.success() => output, _ => return None, }; let stdout = String::from_utf8(output.stdout).unwrap(); let mut parts = stdout.split_whitespace().map(|s| s.to_string()); Some(CommitInfo { hash: parts.next()?, short_hash: parts.next()?, date: parts.next()?, }) } // The rustc source tarball is meant to contain all the source code to build an exact copy of the // toolchain, but it doesn't include the git repository itself. It wouldn't thus be possible to // populate the version information with the commit hash and the commit date. // // To work around this, the rustc build process obtains the git information when creating the // source tarball and writes it to the `git-commit-info` file. The build process actually creates // at least *two* of those files, one for Rust as a whole (in the root of the tarball) and one // specifically for Cargo (in src/tools/cargo). This function loads that file. // // The file is a newline-separated list of full commit hash, short commit hash, and commit date. fn commit_info_from_rustc_source_tarball() -> Option { let path = Path::new("git-commit-info"); if !path.exists() { return None; } // Dependency tracking is a nice to have for this (git doesn't do it), so if the path is not // valid UTF-8 just avoid doing it rather than erroring out. if let Some(utf8) = path.to_str() { println!("cargo:rerun-if-changed={utf8}"); } let content = std::fs::read_to_string(&path).ok()?; let mut parts = content.split('\n').map(|s| s.to_string()); Some(CommitInfo { hash: parts.next()?, short_hash: parts.next()?, date: parts.next()?, }) } fn commit_info() { // Var set by bootstrap whenever omit-git-hash is enabled in rust-lang/rust's config.toml. println!("cargo:rerun-if-env-changed=CFG_OMIT_GIT_HASH"); // ALLOWED: Accessing environment during build time shouldn't be prohibited. #[allow(clippy::disallowed_methods)] if std::env::var_os("CFG_OMIT_GIT_HASH").is_some() { return; } let Some(git) = commit_info_from_git().or_else(commit_info_from_rustc_source_tarball) else { return; }; println!("cargo:rustc-env=CARGO_COMMIT_HASH={}", git.hash); println!("cargo:rustc-env=CARGO_COMMIT_SHORT_HASH={}", git.short_hash); println!("cargo:rustc-env=CARGO_COMMIT_DATE={}", git.date); } #[allow(clippy::disallowed_methods)] fn windows_manifest() { use std::env; let target_os = env::var("CARGO_CFG_TARGET_OS"); let target_env = env::var("CARGO_CFG_TARGET_ENV"); if Ok("windows") == target_os.as_deref() && Ok("msvc") == target_env.as_deref() { static WINDOWS_MANIFEST_FILE: &str = "windows.manifest.xml"; let mut manifest = env::current_dir().unwrap(); manifest.push(WINDOWS_MANIFEST_FILE); println!("cargo:rerun-if-changed={WINDOWS_MANIFEST_FILE}"); // Embed the Windows application manifest file. println!("cargo:rustc-link-arg-bin=cargo=/MANIFEST:EMBED"); println!( "cargo:rustc-link-arg-bin=cargo=/MANIFESTINPUT:{}", manifest.to_str().unwrap() ); // Turn linker warnings into errors. println!("cargo:rustc-link-arg-bin=cargo=/WX"); } } cargo-0.86.0/ci/clean-test-output.sh000075500000000000000000000002061046102023000153370ustar 00000000000000#!/bin/bash # This script remove test and benchmark output and displays disk usage. set -euo pipefail df -h rm -rf target/tmp df -h cargo-0.86.0/ci/dump-environment.sh000075500000000000000000000006071046102023000152560ustar 00000000000000#!/bin/bash # This script dumps information about the build environment to stdout. set -euo pipefail IFS=$'\n\t' echo "environment variables:" printenv | sort echo echo "disk usage:" df -h echo echo "CPU info:" if [[ "${OSTYPE}" = "darwin"* ]]; then system_profiler SPHardwareDataType || true sysctl hw || true else cat /proc/cpuinfo || true cat /proc/meminfo || true fi cargo-0.86.0/ci/fetch-smoke-test.sh000075500000000000000000000011251046102023000151250ustar 00000000000000#!/bin/bash # This script builds with static curl, and verifies that fetching works. set -ex if [[ -z "$RUNNER_TEMP" ]] then echo "RUNNER_TEMP must be set" exit 1 fi if [ ! -f Cargo.toml ]; then echo "Must be run from root of project." exit 1 fi # Building openssl on Windows is a pain. if [[ $(rustc -Vv | grep host:) != *windows* ]]; then FEATURES='vendored-openssl,curl-sys/static-curl,curl-sys/force-system-lib-on-osx' export LIBZ_SYS_STATIC=1 fi cargo build --features "$FEATURES" export CARGO_HOME=$RUNNER_TEMP/chome target/debug/cargo fetch rm -rf $CARGO_HOME cargo-0.86.0/ci/generate.py000064400000000000000000000032521046102023000135530ustar 00000000000000#!/usr/bin/env python3 MAPPING = { "build-script.html": "https://doc.rust-lang.org/cargo/reference/build-scripts.html", "config.html": None, "crates-io.html": "https://doc.rust-lang.org/cargo/reference/publishing.html", "environment-variables.html": None, "external-tools.html": None, "faq.html": "https://doc.rust-lang.org/cargo/faq.html", "guide.html": "https://doc.rust-lang.org/cargo/guide/", "index.html": "https://doc.rust-lang.org/cargo/", "manifest.html": None, "pkgid-spec.html": None, "policies.html": "https://crates.io/policies", "source-replacement.html": None, "specifying-dependencies.html": None, } TEMPLATE = """\ Page Moved This page has moved. Click here to go to the new page. """ def main(): for name in sorted(MAPPING): with open(name, 'w') as f: mapped = MAPPING[name] if mapped is None: mapped = "https://doc.rust-lang.org/cargo/reference/{}".format(name) f.write(TEMPLATE.format(name=name, mapped=mapped)) # WARN: The CNAME file is for GitHub to redirect requests to the custom domain. # Missing this may entail security hazard and domain takeover. # See with open('CNAME', 'w') as f: f.write('doc.crates.io') if __name__ == '__main__': main() cargo-0.86.0/ci/validate-man.sh000075500000000000000000000011251046102023000143050ustar 00000000000000#!/bin/bash # This script validates that there aren't any changes to the man pages. set -e cargo_man="src/doc" mdman_man="crates/mdman/doc" changes=$(git status --porcelain -- $cargo_man $mdman_man) if [ -n "$changes" ] then echo "git directory must be clean before running this script." exit 1 fi cargo build-man changes=$(git status --porcelain -- $cargo_man $mdman_man) if [ -n "$changes" ] then echo "Detected changes of man pages:" echo "$changes" echo echo 'Please run `cargo build-man` to rebuild the man pages' echo "and commit the changes." exit 1 fi cargo-0.86.0/ci/validate-version-bump.sh000075500000000000000000000014471046102023000161670ustar 00000000000000#!/bin/bash # This script checks if a crate needs a version bump. # # At the time of writing, it doesn't check what kind of bump is required. # In the future, we could take SemVer compatibliity into account, like # integrating `cargo-semver-checks` of else # # Inputs: # BASE_SHA The commit SHA of the branch where the PR wants to merge into. # HEAD_SHA The commit SHA that triggered the workflow. set -euo pipefail # When `BASE_SHA` is missing, we assume it is from GitHub merge queue merge commit, # so hope `HEAD~` to find the previous commit on master branch. base_sha=$(git rev-parse "${BASE_SHA:-HEAD~1}") head_sha=$(git rev-parse "${HEAD_SHA:-HEAD}") echo "Base revision is $base_sha" echo "Head revision is $head_sha" cargo bump-check --base-rev "$base_sha" --head-rev "$head_sha" cargo-0.86.0/clippy.toml000064400000000000000000000011541046102023000132100ustar 00000000000000allow-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" }, { path = "std::env::vars", reason = "not recommended to use in Cargo. See rust-lang/cargo#11588" }, { path = "std::env::vars_os", reason = "not recommended to use in Cargo. See rust-lang/cargo#11588" }, ] disallowed-types = [ { path = "std::sync::atomic::AtomicU64", reason = "not portable. See rust-lang/cargo#12988" }, ] cargo-0.86.0/credential/README.md000064400000000000000000000004471046102023000144100ustar 00000000000000# Cargo Credential Packages This directory contains Cargo packages for handling storage of tokens in a secure manner. `cargo-credential` is a generic library to assist writing a credential process. The other directories contain implementations that integrate with specific credential systems. cargo-0.86.0/deny.toml000064400000000000000000000253001046102023000126460ustar 00000000000000# This template contains all of the possible sections and their default values # Note that all fields that take a lint level have these possible values: # * deny - An error will be produced and the check will fail # * warn - A warning will be produced, but the check will not fail # * allow - No warning or error will be produced, though in some cases a note # will be # The values provided in this template are the default values that will be used # when any section or field is not specified in your own configuration # Root options # If 1 or more target triples (and optionally, target_features) are specified, # only the specified targets will be checked when running `cargo deny check`. # This means, if a particular package is only ever used as a target specific # dependency, such as, for example, the `nix` crate only being used via the # `target_family = "unix"` configuration, that only having windows targets in # this list would mean the nix crate, as well as any of its exclusive # dependencies not shared by any other crates, would be ignored, as the target # list here is effectively saying which targets you are building for. targets = [ # The triple can be any string, but only the target triples built in to # rustc (as of 1.40) can be checked against actual config expressions #{ triple = "x86_64-unknown-linux-musl" }, # You can also specify which target_features you promise are enabled for a # particular target. target_features are currently not validated against # the actual valid features supported by the target architecture. #{ triple = "wasm32-unknown-unknown", features = ["atomics"] }, ] # When creating the dependency graph used as the source of truth when checks are # executed, this field can be used to prune crates from the graph, removing them # from the view of cargo-deny. This is an extremely heavy hammer, as if a crate # is pruned from the graph, all of its dependencies will also be pruned unless # they are connected to another crate in the graph that hasn't been pruned, # so it should be used with care. The identifiers are [Package ID Specifications] # (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html) #exclude = [] # If true, metadata will be collected with `--all-features`. Note that this can't # be toggled off if true, if you want to conditionally enable `--all-features` it # is recommended to pass `--all-features` on the cmd line instead all-features = false # If true, metadata will be collected with `--no-default-features`. The same # caveat with `all-features` applies no-default-features = false # If set, these feature will be enabled when collecting metadata. If `--features` # is specified on the cmd line they will take precedence over this option. #features = [] # When outputting inclusion graphs in diagnostics that include features, this # option can be used to specify the depth at which feature edges will be added. # This option is included since the graphs can be quite large and the addition # of features from the crate(s) to all of the graph roots can be far too verbose. # This option can be overridden via `--feature-depth` on the cmd line feature-depth = 1 # This section is considered when running `cargo deny check advisories` # More documentation for the advisories section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html [advisories] # The path where the advisory database is cloned/fetched into db-path = "~/.cargo/advisory-db" # The url(s) of the advisory databases to use db-urls = ["https://github.com/rustsec/advisory-db"] yanked = "warn" # A list of advisory IDs to ignore. Note that ignored advisories will still # output a note when they are encountered. ignore = [ #"RUSTSEC-0000-0000", ] # Threshold for security vulnerabilities, any vulnerability with a CVSS score # lower than the range specified will be ignored. Note that ignored advisories # will still output a note when they are encountered. # * None - CVSS Score 0.0 # * Low - CVSS Score 0.1 - 3.9 # * Medium - CVSS Score 4.0 - 6.9 # * High - CVSS Score 7.0 - 8.9 # * Critical - CVSS Score 9.0 - 10.0 #severity-threshold = # If this is true, then cargo deny will use the git executable to fetch advisory database. # If this is false, then it uses a built-in git library. # Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support. # See Git Authentication for more information about setting up git authentication. #git-fetch-with-cli = true # This section is considered when running `cargo deny check licenses` # More documentation for the licenses section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html [licenses] # List of explicitly allowed licenses # See https://spdx.org/licenses/ for list of possible licenses # [possible values: any SPDX 3.11 short identifier (+ optional exception)]. allow = [ "MIT", "MIT-0", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "MPL-2.0", "Unicode-DFS-2016", "CC0-1.0", "ISC", ] # The confidence threshold for detecting a license from license text. # The higher the value, the more closely the license text must be to the # canonical license text of a valid SPDX license file. # [possible values: any between 0.0 and 1.0]. confidence-threshold = 0.8 # Allow 1 or more licenses on a per-crate basis, so that particular licenses # aren't accepted for every possible crate as with the normal allow list exceptions = [ # Each entry is the crate and version constraint, and its specific allow # list #{ allow = ["Zlib"], name = "adler32", version = "*" }, ] # Some crates don't have (easily) machine readable licensing information, # adding a clarification entry for it allows you to manually specify the # licensing information #[[licenses.clarify]] # The name of the crate the clarification applies to #name = "ring" # The optional version constraint for the crate #version = "*" # The SPDX expression for the license requirements of the crate #expression = "MIT AND ISC AND OpenSSL" # One or more files in the crate's source used as the "source of truth" for # the license expression. If the contents match, the clarification will be used # when running the license check, otherwise the clarification will be ignored # and the crate will be checked normally, which may produce warnings or errors # depending on the rest of your configuration #license-files = [ # Each entry is a crate relative path, and the (opaque) hash of its contents #{ path = "LICENSE", hash = 0xbd0eed23 } #] [licenses.private] # If true, ignores workspace crates that aren't published, or are only # published to private registries. # To see how to mark a crate as unpublished (to the official registry), # visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field. ignore = false # One or more private registries that you might publish crates to, if a crate # is only published to private registries, and ignore is true, the crate will # not have its license(s) checked registries = [ #"https://sekretz.com/registry ] # This section is considered when running `cargo deny check bans`. # More documentation about the 'bans' section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html [bans] # Lint level for when multiple versions of the same crate are detected multiple-versions = "warn" # Lint level for when a crate version requirement is `*` wildcards = "allow" # The graph highlighting used when creating dotgraphs for crates # with multiple versions # * lowest-version - The path to the lowest versioned duplicate is highlighted # * simplest-path - The path to the version with the fewest edges is highlighted # * all - Both lowest-version and simplest-path are used highlight = "all" # The default lint level for `default` features for crates that are members of # the workspace that is being checked. This can be overridden by allowing/denying # `default` on a crate-by-crate basis if desired. workspace-default-features = "allow" # The default lint level for `default` features for external crates that are not # members of the workspace. This can be overridden by allowing/denying `default` # on a crate-by-crate basis if desired. external-default-features = "allow" # List of crates that are allowed. Use with care! allow = [ #{ name = "ansi_term", version = "=0.11.0" }, ] # List of crates to deny deny = [ # Each entry the name of a crate and a version range. If version is # not specified, all versions will be matched. #{ name = "ansi_term", version = "=0.11.0" }, # # Wrapper crates can optionally be specified to allow the crate when it # is a direct dependency of the otherwise banned crate #{ name = "ansi_term", version = "=0.11.0", wrappers = [] }, ] # List of features to allow/deny # Each entry the name of a crate and a version range. If version is # not specified, all versions will be matched. #[[bans.features]] #name = "reqwest" # Features to not allow #deny = ["json"] # Features to allow #allow = [ # "rustls", # "__rustls", # "__tls", # "hyper-rustls", # "rustls", # "rustls-pemfile", # "rustls-tls-webpki-roots", # "tokio-rustls", # "webpki-roots", #] # If true, the allowed features must exactly match the enabled feature set. If # this is set there is no point setting `deny` #exact = true # Certain crates/versions that will be skipped when doing duplicate detection. skip = [ #{ name = "ansi_term", version = "=0.11.0" }, ] # Similarly to `skip` allows you to skip certain crates during duplicate # detection. Unlike skip, it also includes the entire tree of transitive # dependencies starting at the specified crate, up to a certain depth, which is # by default infinite. skip-tree = [ #{ name = "ansi_term", version = "=0.11.0", depth = 20 }, ] # This section is considered when running `cargo deny check sources`. # More documentation about the 'sources' section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html [sources] # Lint level for what to happen when a crate from a crate registry that is not # in the allow list is encountered unknown-registry = "warn" # Lint level for what to happen when a crate from a git repository that is not # in the allow list is encountered unknown-git = "warn" # List of URLs for allowed crate registries. Defaults to the crates.io index # if not specified. If it is specified but empty, no registries are allowed. allow-registry = ["https://github.com/rust-lang/crates.io-index"] # List of URLs for allowed Git repositories allow-git = [] [sources.allow-org] # 1 or more github.com organizations to allow git sources for github = [] # 1 or more gitlab.com organizations to allow git sources for gitlab = [] # 1 or more bitbucket.org organizations to allow git sources for bitbucket = [] cargo-0.86.0/publish.py000075500000000000000000000042241046102023000130370ustar 00000000000000#!/usr/bin/env python3 # This script is used to publish Cargo to crates.io. # # This is run automatically every 6 weeks by the Release team's automation # whose source is at https://github.com/rust-lang/simpleinfra/. # # See https://doc.crates.io/contrib/process/release.html for more about # Cargo's release process. import os import re import subprocess import urllib.request from urllib.error import HTTPError # Whenever you add a new crate to this list that does NOT start with "cargo-" # you must reach out to the infra team to add the crate to the list of crates # allowed to be published from the "cargo CI" crates.io token. TO_PUBLISH = [ 'credential/cargo-credential', 'credential/cargo-credential-libsecret', 'credential/cargo-credential-wincred', 'credential/cargo-credential-1password', 'credential/cargo-credential-macos-keychain', 'crates/rustfix', 'crates/cargo-platform', 'crates/cargo-util', 'crates/crates-io', 'crates/cargo-util-schemas', 'crates/cargo-test-macro', 'crates/cargo-test-support', '.', ] def already_published(name, version): url = f'https://static.crates.io/crates/{name}/{version}/download' try: urllib.request.urlopen(url) except HTTPError as e: # 403 and 404 are common responses to assume it is not published if 400 <= e.code < 500: return False print(f'error: failed to check if {name} {version} is already published') print(f' HTTP response error code {e.code} checking {url}') raise return True def maybe_publish(path): content = open(os.path.join(path, 'Cargo.toml')).read() name = re.search('^name = "([^"]+)"', content, re.M).group(1) version = re.search('^version = "([^"]+)"', content, re.M).group(1) if already_published(name, version): print('%s %s is already published, skipping' % (name, version)) return False subprocess.check_call(['cargo', 'publish', '--no-verify'], cwd=path) return True def main(): print('Starting publish...') for path in TO_PUBLISH: maybe_publish(path) print('Publish complete!') if __name__ == '__main__': main() cargo-0.86.0/src/bin/cargo/cli.rs000064400000000000000000000646161046102023000145760ustar 00000000000000use anyhow::{anyhow, Context as _}; use cargo::core::{features, CliUnstable}; use cargo::util::context::TermConfig; use cargo::{drop_print, drop_println, CargoResult}; use clap::builder::UnknownArgumentValueParser; use itertools::Itertools; use std::collections::HashMap; use std::ffi::OsStr; use std::ffi::OsString; use std::fmt::Write; use super::commands; use super::list_commands; use crate::command_prelude::*; use crate::util::is_rustup; use cargo::core::shell::ColorChoice; use cargo::util::style; #[tracing::instrument(skip_all)] pub fn main(gctx: &mut GlobalContext) -> CliResult { // CAUTION: Be careful with using `config` until it is configured below. // In general, try to avoid loading config values unless necessary (like // the [alias] table). let args = cli(gctx).try_get_matches()?; // Update the process-level notion of cwd if let Some(new_cwd) = args.get_one::("directory") { // This is a temporary hack. // This cannot access `GlobalContext`, so this is a bit messy. // This does not properly parse `-Z` flags that appear after the subcommand. // The error message is not as helpful as the standard one. let nightly_features_allowed = matches!(&*features::channel(), "nightly" | "dev"); if !nightly_features_allowed || (nightly_features_allowed && !args .get_many("unstable-features") .map(|mut z| z.any(|value: &String| value == "unstable-options")) .unwrap_or(false)) { return Err(anyhow::format_err!( "the `-C` flag is unstable, \ pass `-Z unstable-options` on the nightly channel to enable it" ) .into()); } std::env::set_current_dir(&new_cwd).context("could not change to requested directory")?; gctx.reload_cwd()?; } let (expanded_args, global_args) = expand_aliases(gctx, args, vec![])?; let is_verbose = expanded_args.verbose() > 0; if expanded_args .get_one::("unstable-features") .map(String::as_str) == Some("help") { // Don't let config errors get in the way of parsing arguments let _ = configure_gctx(gctx, &expanded_args, None, global_args, None); print_zhelp(gctx); } else if expanded_args.flag("version") { // Don't let config errors get in the way of parsing arguments let _ = configure_gctx(gctx, &expanded_args, None, global_args, None); let version = get_version_string(is_verbose); drop_print!(gctx, "{}", version); } else if let Some(code) = expanded_args.get_one::("explain") { // Don't let config errors get in the way of parsing arguments let _ = configure_gctx(gctx, &expanded_args, None, global_args, None); let mut procss = gctx.load_global_rustc(None)?.process(); procss.arg("--explain").arg(code).exec()?; } else if expanded_args.flag("list") { // Don't let config errors get in the way of parsing arguments let _ = configure_gctx(gctx, &expanded_args, None, global_args, None); print_list(gctx, is_verbose); } else { let (cmd, subcommand_args) = match expanded_args.subcommand() { Some((cmd, args)) => (cmd, args), _ => { // No subcommand provided. cli(gctx).print_help()?; return Ok(()); } }; let exec = Exec::infer(cmd)?; configure_gctx( gctx, &expanded_args, Some(subcommand_args), global_args, Some(&exec), )?; super::init_git(gctx); exec.exec(gctx, subcommand_args)?; } Ok(()) } fn print_zhelp(gctx: &GlobalContext) { let header = style::HEADER; let literal = style::LITERAL; let placeholder = style::PLACEHOLDER; let options = CliUnstable::help(); let max_length = options .iter() .filter(|(_, help)| help.is_some()) .map(|(option_name, _)| option_name.len()) .max() .unwrap_or(0); let z_flags = options .iter() .filter(|(_, help)| help.is_some()) .map(|(opt, help)| { let opt = opt.replace("_", "-"); let help = help.unwrap(); format!(" {literal}-Z {opt:Installed Commands:") ); for (name, command) in list_commands(gctx) { let known_external_desc = known_external_command_descriptions.get(name.as_str()); let literal = style::LITERAL; match command { CommandInfo::BuiltIn { about } => { assert!( known_external_desc.is_none(), "known_external_commands shouldn't contain builtin `{name}`", ); let summary = about.unwrap_or_default(); let summary = summary.lines().next().unwrap_or(&summary); // display only the first line drop_println!(gctx, " {literal}{name:<20}{literal:#} {summary}"); } CommandInfo::External { path } => { if let Some(desc) = known_external_desc { drop_println!(gctx, " {literal}{name:<20}{literal:#} {desc}"); } else if is_verbose { drop_println!( gctx, " {literal}{name:<20}{literal:#} {}", path.display() ); } else { drop_println!(gctx, " {literal}{name}{literal:#}"); } } CommandInfo::Alias { target } => { drop_println!( gctx, " {literal}{name:<20}{literal:#} alias: {}", target.iter().join(" ") ); } } } } pub fn get_version_string(is_verbose: bool) -> String { let version = cargo::version(); let mut version_string = format!("cargo {}\n", version); if is_verbose { version_string.push_str(&format!("release: {}\n", version.version)); if let Some(ref ci) = version.commit_info { version_string.push_str(&format!("commit-hash: {}\n", ci.commit_hash)); version_string.push_str(&format!("commit-date: {}\n", ci.commit_date)); } writeln!(version_string, "host: {}", env!("RUST_HOST_TARGET")).unwrap(); add_libgit2(&mut version_string); add_curl(&mut version_string); add_ssl(&mut version_string); writeln!(version_string, "os: {}", os_info::get()).unwrap(); } version_string } fn add_libgit2(version_string: &mut String) { let git2_v = git2::Version::get(); let lib_v = git2_v.libgit2_version(); let vendored = if git2_v.vendored() { format!("vendored") } else { format!("system") }; writeln!( version_string, "libgit2: {}.{}.{} (sys:{} {})", lib_v.0, lib_v.1, lib_v.2, git2_v.crate_version(), vendored ) .unwrap(); } fn add_curl(version_string: &mut String) { let curl_v = curl::Version::get(); let vendored = if curl_v.vendored() { format!("vendored") } else { format!("system") }; writeln!( version_string, "libcurl: {} (sys:{} {} ssl:{})", curl_v.version(), curl_sys::rust_crate_version(), vendored, curl_v.ssl_version().unwrap_or("none") ) .unwrap(); } fn add_ssl(version_string: &mut String) { #[cfg(feature = "openssl")] { writeln!(version_string, "ssl: {}", openssl::version::version()).unwrap(); } #[cfg(not(feature = "openssl"))] { let _ = version_string; // Silence unused warning. } } /// Expands aliases recursively to collect all the command line arguments. /// /// [`GlobalArgs`] need to be extracted before expanding aliases because the /// clap code for extracting a subcommand discards global options /// (appearing before the subcommand). #[tracing::instrument(skip_all)] fn expand_aliases( gctx: &mut GlobalContext, args: ArgMatches, mut already_expanded: Vec, ) -> Result<(ArgMatches, GlobalArgs), CliError> { if let Some((cmd, sub_args)) = args.subcommand() { let exec = commands::builtin_exec(cmd); let aliased_cmd = super::aliased_command(gctx, cmd); match (exec, aliased_cmd) { (Some(_), Ok(Some(_))) => { // User alias conflicts with a built-in subcommand gctx.shell().warn(format!( "user-defined alias `{}` is ignored, because it is shadowed by a built-in command", cmd, ))?; } (Some(_), Ok(None) | Err(_)) => { // 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) = sub_args.get_many::("") { // Command is built-in and is not conflicting with alias, but contains ignored values. return Err(anyhow::format_err!( "\ trailing arguments after built-in command `{}` are unsupported: `{}` To pass the arguments to the subcommand, remove `--`", cmd, values.map(|s| s.to_string_lossy()).join(" "), ) .into()); } } (None, Ok(None)) => {} (None, Ok(Some(alias))) => { // Check if a user-defined alias is shadowing an external subcommand // (binary of the form `cargo-`) // Currently this is only a warning, but after a transition period this will become // a hard error. if super::builtin_aliases_execs(cmd).is_none() { if let Some(path) = super::find_external_subcommand(gctx, cmd) { gctx.shell().warn(format!( "\ user-defined alias `{}` is shadowing an external subcommand found at: `{}` This was previously accepted but is being phased out; it will become a hard error in a future release. For more information, see issue #10049 .", cmd, path.display(), ))?; } } if commands::run::is_manifest_command(cmd) { if gctx.cli_unstable().script { return Ok((args, GlobalArgs::default())); } else { gctx.shell().warn(format_args!( "\ user-defined alias `{cmd}` has the appearance of a manifest-command This was previously accepted but will be phased out when `-Zscript` is stabilized. For more information, see issue #12207 ." ))?; } } let mut alias = alias .into_iter() .map(|s| OsString::from(s)) .collect::>(); alias.extend( sub_args .get_many::("") .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(sub_args); let new_args = cli(gctx).no_binary_name(true).try_get_matches_from(alias)?; let Some(new_cmd) = new_args.subcommand_name() else { return Err(anyhow!( "subcommand is required, add a subcommand to the command alias `alias.{cmd}`" ) .into()); }; already_expanded.push(cmd.to_string()); if already_expanded.contains(&new_cmd.to_string()) { // Crash if the aliases are corecursive / unresolvable return Err(anyhow!( "alias {} has unresolvable recursive definition: {} -> {}", already_expanded[0], already_expanded.join(" -> "), new_cmd, ) .into()); } let (expanded_args, _) = expand_aliases(gctx, new_args, already_expanded)?; return Ok((expanded_args, global_args)); } (None, Err(e)) => return Err(e.into()), } }; Ok((args, GlobalArgs::default())) } #[tracing::instrument(skip_all)] fn configure_gctx( gctx: &mut GlobalContext, args: &ArgMatches, subcommand_args: Option<&ArgMatches>, global_args: GlobalArgs, exec: Option<&Exec>, ) -> CliResult { let arg_target_dir = &subcommand_args.and_then(|a| a.value_of_path("target-dir", gctx)); 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 mut quiet = args.flag("quiet") || subcommand_args.map(|a| a.flag("quiet")).unwrap_or_default() || global_args.quiet; if matches!(exec, Some(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 !gctx.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::("color") .map(String::as_str) .or_else(|| global_color.as_deref()); let frozen = args.flag("frozen") || global_args.frozen; let locked = args.flag("locked") || global_args.locked; let offline = args.flag("offline") || global_args.offline; let mut unstable_flags = global_args.unstable_flags; if let Some(values) = args.get_many::("unstable-features") { unstable_flags.extend(values.cloned()); } let mut config_args = global_args.config_args; if let Some(values) = args.get_many::("config") { config_args.extend(values.cloned()); } gctx.configure( verbose, quiet, color, frozen, locked, offline, arg_target_dir, &unstable_flags, &config_args, )?; Ok(()) } 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 { 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())) } } #[tracing::instrument(skip_all)] fn exec(self, gctx: &mut GlobalContext, subcommand_args: &ArgMatches) -> CliResult { match self { Self::Builtin(exec) => exec(gctx, subcommand_args), Self::Manifest(cmd) => { let ext_path = super::find_external_subcommand(gctx, &cmd); if !gctx.cli_unstable().script && ext_path.is_some() { gctx.shell().warn(format_args!( "\ external subcommand `{cmd}` has the appearance of a manifest-command This was previously accepted but will be phased out when `-Zscript` is stabilized. For more information, see issue #12207 .", ))?; Self::External(cmd).exec(gctx, subcommand_args) } else { let ext_args: Vec = subcommand_args .get_many::("") .unwrap_or_default() .cloned() .collect(); commands::run::exec_manifest_command(gctx, &cmd, &ext_args) } } Self::External(cmd) => { let mut ext_args = vec![OsStr::new(&cmd)]; ext_args.extend( subcommand_args .get_many::("") .unwrap_or_default() .map(OsString::as_os_str), ); super::execute_external_subcommand(gctx, &cmd, &ext_args) } } } } #[derive(Default)] struct GlobalArgs { verbose: u32, quiet: bool, color: Option, frozen: bool, locked: bool, offline: bool, unstable_flags: Vec, config_args: Vec, } impl GlobalArgs { fn new(args: &ArgMatches) -> GlobalArgs { GlobalArgs { verbose: args.verbose(), quiet: args.flag("quiet"), color: args.get_one::("color").cloned(), frozen: args.flag("frozen"), locked: args.flag("locked"), offline: args.flag("offline"), unstable_flags: args .get_many::("unstable-features") .unwrap_or_default() .cloned() .collect(), config_args: args .get_many::("config") .unwrap_or_default() .cloned() .collect(), } } } #[tracing::instrument(skip_all)] pub fn cli(gctx: &GlobalContext) -> Command { // Don't let config errors get in the way of parsing arguments let term = gctx.get::("term").unwrap_or_default(); let color = term .color .and_then(|c| c.parse().ok()) .unwrap_or(ColorChoice::CargoAuto); let color = match color { ColorChoice::Always => clap::ColorChoice::Always, ColorChoice::Never => clap::ColorChoice::Never, ColorChoice::CargoAuto => clap::ColorChoice::Auto, }; let usage = if is_rustup() { color_print::cstr!("cargo [+toolchain] [OPTIONS] [COMMAND]\n cargo [+toolchain] [OPTIONS] -Zscript <> [ARGS]...") } else { color_print::cstr!("cargo [OPTIONS] [COMMAND]\n cargo [OPTIONS] -Zscript <> [ARGS]...") }; let styles = { clap::builder::styling::Styles::styled() .header(style::HEADER) .usage(style::USAGE) .literal(style::LITERAL) .placeholder(style::PLACEHOLDER) .error(style::ERROR) .valid(style::VALID) .invalid(style::INVALID) }; Command::new("cargo") // Subcommands all count their args' display order independently (from 0), // which makes their args interspersed with global args. This puts global args last. // // We also want these to come before auto-generated `--help` .next_display_order(800) .allow_external_subcommands(true) .color(color) .styles(styles) // Provide a custom help subcommand for calling into man pages .disable_help_subcommand(true) .override_usage(usage) .help_template(color_print::cstr!( "\ Rust's package manager Usage: {usage} Options: {options} Commands: build, b Compile the current package check, c Analyze the current package and report errors, but don't build object files clean Remove the target directory doc, d Build this package's and its dependencies' documentation new Create a new cargo package init Create a new cargo package in an existing directory add Add dependencies to a manifest file remove Remove dependencies from a manifest file run, r Run a binary or example of the local package test, t Run the tests bench Run the benchmarks update Update dependencies listed in Cargo.lock search Search registry for crates publish Package and upload this package to the registry install Install a Rust binary uninstall Uninstall a Rust binary ... See all commands with --list See 'cargo help <>' for more information on a specific command.\n", )) .arg(flag("version", "Print version info and exit").short('V')) .arg(flag("list", "List installed commands")) .arg( opt( "explain", "Provide a detailed explanation of a rustc error message", ) .value_name("CODE"), ) .arg( opt( "verbose", "Use verbose output (-vv very verbose/build.rs output)", ) .short('v') .action(ArgAction::Count) .global(true), ) .arg(flag("quiet", "Do not print cargo log messages").short('q').global(true)) .arg( opt("color", "Coloring: auto, always, never") .value_name("WHEN") .global(true), ) .arg( Arg::new("directory") .help("Change to DIRECTORY before doing anything (nightly-only)") .short('C') .value_name("DIRECTORY") .value_hint(clap::ValueHint::DirPath) .value_parser(clap::builder::ValueParser::path_buf()), ) .arg( flag("locked", "Assert that `Cargo.lock` will remain unchanged") .help_heading(heading::MANIFEST_OPTIONS) .global(true), ) .arg( flag("offline", "Run without accessing the network") .help_heading(heading::MANIFEST_OPTIONS) .global(true), ) .arg( flag("frozen", "Equivalent to specifying both --locked and --offline") .help_heading(heading::MANIFEST_OPTIONS) .global(true), ) // Better suggestion for the unsupported short config flag. .arg( Arg::new("unsupported-short-config-flag") .help("") .short('c') .value_parser(UnknownArgumentValueParser::suggest_arg("--config")) .action(ArgAction::SetTrue) .global(true) .hide(true)) .arg(multi_opt("config", "KEY=VALUE|PATH", "Override a configuration value").global(true)) // Better suggestion for the unsupported lowercase unstable feature flag. .arg( Arg::new("unsupported-lowercase-unstable-feature-flag") .help("") .short('z') .value_parser(UnknownArgumentValueParser::suggest_arg("-Z")) .action(ArgAction::SetTrue) .global(true) .hide(true)) .arg(Arg::new("unstable-features") .help("Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details") .short('Z') .value_name("FLAG") .action(ArgAction::Append) .global(true) .add(clap_complete::ArgValueCandidates::new(|| { let flags = CliUnstable::help(); flags.into_iter().map(|flag| { clap_complete::CompletionCandidate::new(flag.0.replace("_", "-")).help(flag.1.map(|help| { help.into() })) }).collect() }))) .subcommands(commands::builtin()) } #[test] fn verify_cli() { let gctx = GlobalContext::default().unwrap(); cli(&gctx).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" ) } } cargo-0.86.0/src/bin/cargo/commands/add.rs000064400000000000000000000350651046102023000163540ustar 00000000000000use cargo::sources::CRATES_IO_REGISTRY; use cargo::util::print_available_packages; use indexmap::IndexMap; use indexmap::IndexSet; use cargo::core::dependency::DepKind; use cargo::core::FeatureValue; use cargo::ops::cargo_add::add; use cargo::ops::cargo_add::AddOptions; use cargo::ops::cargo_add::DepOp; use cargo::ops::resolve_ws; use cargo::util::command_prelude::*; use cargo::util::interning::InternedString; use cargo::util::toml_mut::manifest::DepTable; use cargo::CargoResult; pub fn cli() -> Command { clap::Command::new("add") .about("Add dependencies to a Cargo.toml manifest file") .override_usage( color_print::cstr!("\ cargo add [OPTIONS] <>[@<>] ... cargo add [OPTIONS] --path <> ... cargo add [OPTIONS] --git <> ..." )) .after_help(color_print::cstr!("Run `cargo help add` for more detailed information.\n")) .group(clap::ArgGroup::new("selected").multiple(true).required(true)) .args([ clap::Arg::new("crates") .value_name("DEP_ID") .num_args(0..) .help("Reference to a package to add as a dependency") .long_help( "Reference to a package to add as a dependency You can reference a package by: - ``, like `cargo add serde` (latest version will be used) - `@`, like `cargo add serde@1` or `cargo add serde@=1.0.38`" ) .group("selected"), flag("no-default-features", "Disable the default features"), flag("default-features", "Re-enable the default features") .overrides_with("no-default-features"), clap::Arg::new("features") .short('F') .long("features") .value_name("FEATURES") .action(ArgAction::Append) .help("Space or comma separated list of features to activate"), flag("optional", "Mark the dependency as optional") .long_help("Mark the dependency as optional The package name will be exposed as feature of your crate.") .conflicts_with("dev"), flag("no-optional", "Mark the dependency as required") .long_help("Mark the dependency as required The package will be removed from your features.") .conflicts_with("dev") .overrides_with("optional"), flag("public", "Mark the dependency as public (unstable)") .conflicts_with("dev") .conflicts_with("build") .long_help("Mark the dependency as public (unstable) The dependency can be referenced in your library's public API."), flag("no-public", "Mark the dependency as private (unstable)") .conflicts_with("dev") .conflicts_with("build") .overrides_with("public") .long_help("Mark the dependency as private (unstable) While you can use the crate in your implementation, it cannot be referenced in your public API."), clap::Arg::new("rename") .long("rename") .action(ArgAction::Set) .value_name("NAME") .help("Rename the dependency") .long_help("Rename the dependency Example uses: - Depending on multiple versions of a crate - Depend on crates with the same name from different registries"), ]) .arg_manifest_path_without_unsupported_path_tip() .arg_lockfile_path() .arg_package("Package to modify") .arg_ignore_rust_version() .arg_dry_run("Don't actually write the manifest") .arg_silent_suggestion() .next_help_heading("Source") .args([ clap::Arg::new("path") .long("path") .action(ArgAction::Set) .value_name("PATH") .help("Filesystem path to local crate to add") .group("selected") .conflicts_with("git"), clap::Arg::new("base") .long("base") .action(ArgAction::Set) .value_name("BASE") .help("The path base to use when adding from a local crate (unstable).") .requires("path"), clap::Arg::new("git") .long("git") .action(ArgAction::Set) .value_name("URI") .help("Git repository location") .long_help("Git repository location Without any other information, cargo will use latest commit on the main branch.") .group("selected"), clap::Arg::new("branch") .long("branch") .action(ArgAction::Set) .value_name("BRANCH") .help("Git branch to download the crate from") .requires("git") .group("git-ref"), clap::Arg::new("tag") .long("tag") .action(ArgAction::Set) .value_name("TAG") .help("Git tag to download the crate from") .requires("git") .group("git-ref"), clap::Arg::new("rev") .long("rev") .action(ArgAction::Set) .value_name("REV") .help("Git reference to download the crate from") .long_help("Git reference to download the crate from This is the catch all, handling hashes to named references in remote repositories.") .requires("git") .group("git-ref"), clap::Arg::new("registry") .long("registry") .action(ArgAction::Set) .value_name("NAME") .help("Package registry for this dependency") .add(clap_complete::ArgValueCandidates::new(|| { let candidates = get_registry_candidates(); candidates.unwrap_or_default() })), ]) .next_help_heading("Section") .args([ flag("dev", "Add as development dependency") .long_help("Add as development dependency Dev-dependencies are not used when compiling a package for building, but are used for compiling tests, examples, and benchmarks. These dependencies are not propagated to other packages which depend on this package.") .group("section"), flag("build", "Add as build dependency") .long_help("Add as build dependency Build-dependencies are the only dependencies available for use by build scripts (`build.rs` files).") .group("section"), clap::Arg::new("target") .long("target") .action(ArgAction::Set) .value_name("TARGET") .value_parser(clap::builder::NonEmptyStringValueParser::new()) .help("Add as dependency to the given target platform") ]) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let dry_run = args.dry_run(); let section = parse_section(args); let ws = args.workspace(gctx)?; if args.is_present_with_zero_values("package") { print_available_packages(&ws)?; } let packages = args.packages_from_flags()?; let packages = packages.get_packages(&ws)?; let spec = match packages.len() { 0 => { return Err(CliError::new( anyhow::format_err!( "no packages selected to modify. Please specify one with `-p `" ), 101, )); } 1 => packages[0], _ => { let names = packages.iter().map(|p| p.name()).collect::>(); return Err(CliError::new( anyhow::format_err!( "`cargo add` could not determine which package to modify. \ Use the `--package` option to specify a package. \n\ available packages: {}", names.join(", ") ), 101, )); } }; let dependencies = parse_dependencies(gctx, args)?; let honor_rust_version = args.honor_rust_version(); let options = AddOptions { gctx, spec, dependencies, section, dry_run, honor_rust_version, }; add(&ws, &options)?; // Reload the workspace since we've changed dependencies let ws = args.workspace(gctx)?; resolve_ws(&ws, dry_run)?; Ok(()) } fn parse_dependencies(gctx: &GlobalContext, matches: &ArgMatches) -> CargoResult> { let path = matches.get_one::("path"); let base = matches.get_one::("base"); let git = matches.get_one::("git"); let branch = matches.get_one::("branch"); let rev = matches.get_one::("rev"); let tag = matches.get_one::("tag"); let rename = matches.get_one::("rename"); let registry = match matches.registry(gctx)? { Some(reg) if reg == CRATES_IO_REGISTRY => None, reg => reg, }; let default_features = default_features(matches); let optional = optional(matches); let public = public(matches); let mut crates = matches .get_many::("crates") .into_iter() .flatten() .map(|c| (Some(c.clone()), None)) .collect::>(); 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); infer_crate_name = true; } else { unreachable!("clap should ensure we have some source selected"); } } for feature in matches .get_many::("features") .into_iter() .flatten() .map(String::as_str) .flat_map(parse_feature) { let parsed_value = FeatureValue::new(InternedString::new(feature)); match parsed_value { FeatureValue::Feature(_) => { if 1 < crates.len() { let candidates = crates .keys() .map(|c| { format!( "`{}/{}`", c.as_deref().expect("only none when there is 1"), feature ) }) .collect::>(); anyhow::bail!("feature `{feature}` must be qualified by the dependency it's being activated for, like {}", candidates.join(", ")); } crates .first_mut() .expect("always at least one crate") .1 .get_or_insert_with(IndexSet::new) .insert(feature.to_owned()); } FeatureValue::Dep { .. } => { anyhow::bail!("feature `{feature}` is not allowed to use explicit `dep:` syntax",) } FeatureValue::DepFeature { dep_name, dep_feature, .. } => { if infer_crate_name { anyhow::bail!("`{feature}` is unsupported when inferring the crate name, use `{dep_feature}`"); } if dep_feature.contains('/') { anyhow::bail!("multiple slashes in feature `{feature}` is not allowed"); } crates.get_mut(&Some(dep_name.as_str().to_owned())).ok_or_else(|| { anyhow::format_err!("feature `{dep_feature}` activated for crate `{dep_name}` but the crate wasn't specified") })? .get_or_insert_with(IndexSet::new) .insert(dep_feature.as_str().to_owned()); } } } let mut deps: Vec = Vec::new(); for (crate_spec, features) in crates { let dep = DepOp { crate_spec, rename: rename.map(String::from), features, default_features, optional, public, registry: registry.clone(), path: path.map(String::from), base: base.map(String::from), git: git.map(String::from), branch: branch.map(String::from), rev: rev.map(String::from), tag: tag.map(String::from), }; deps.push(dep); } if deps.len() > 1 && rename.is_some() { anyhow::bail!("cannot specify multiple crates with `--rename`"); } Ok(deps) } fn default_features(matches: &ArgMatches) -> Option { resolve_bool_arg( matches.flag("default-features"), matches.flag("no-default-features"), ) } fn optional(matches: &ArgMatches) -> Option { resolve_bool_arg(matches.flag("optional"), matches.flag("no-optional")) } fn public(matches: &ArgMatches) -> Option { resolve_bool_arg(matches.flag("public"), matches.flag("no-public")) } fn resolve_bool_arg(yes: bool, no: bool) -> Option { match (yes, no) { (true, false) => Some(true), (false, true) => Some(false), (false, false) => None, (_, _) => unreachable!("clap should make this impossible"), } } fn parse_section(matches: &ArgMatches) -> DepTable { let kind = if matches.flag("dev") { DepKind::Development } else if matches.flag("build") { DepKind::Build } else { DepKind::Normal }; let mut table = DepTable::new().set_kind(kind); if let Some(target) = matches.get_one::("target") { assert!(!target.is_empty(), "Target specification may not be empty"); table = table.set_target(target); } table } /// Split feature flag list fn parse_feature(feature: &str) -> impl Iterator { // Not re-using `CliFeatures` because it uses a BTreeSet and loses user's ordering feature .split_whitespace() .flat_map(|s| s.split(',')) .filter(|s| !s.is_empty()) } cargo-0.86.0/src/bin/cargo/commands/bench.rs000064400000000000000000000054731046102023000167030ustar 00000000000000use crate::command_prelude::*; use cargo::ops::{self, TestOptions}; pub fn cli() -> Command { subcommand("bench") .about("Execute all benchmarks of a local package") .next_display_order(0) .arg( Arg::new("BENCHNAME") .action(ArgAction::Set) .help("If specified, only run benches containing this string in their names"), ) .arg( Arg::new("args") .value_name("ARGS") .help("Arguments for the bench binary") .num_args(0..) .last(true), ) .arg(flag("no-run", "Compile, but don't run benchmarks")) .arg(flag( "no-fail-fast", "Run all benchmarks regardless of failure", )) .arg_message_format() .arg_silent_suggestion() .arg_package_spec( "Package to run benchmarks for", "Benchmark all packages in the workspace", "Exclude packages from the benchmark", ) .arg_targets_all( "Benchmark only this package's library", "Benchmark only the specified binary", "Benchmark all binaries", "Benchmark only the specified example", "Benchmark all examples", "Benchmark only the specified test target", "Benchmark all targets that have `test = true` set", "Benchmark only the specified bench target", "Benchmark all targets that have `bench = true` set", "Benchmark all targets", ) .arg_features() .arg_jobs() .arg_unsupported_keep_going() .arg_profile("Build artifacts with the specified profile") .arg_target_triple("Build for the target triple") .arg_target_dir() .arg_unit_graph() .arg_timings() .arg_manifest_path() .arg_lockfile_path() .arg_ignore_rust_version() .after_help(color_print::cstr!( "Run `cargo help bench` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let ws = args.workspace(gctx)?; let mut compile_opts = args.compile_options(gctx, CompileMode::Bench, Some(&ws), ProfileChecking::Custom)?; compile_opts.build_config.requested_profile = args.get_profile_name("bench", ProfileChecking::Custom)?; let ops = TestOptions { no_run: args.flag("no-run"), no_fail_fast: args.flag("no-fail-fast"), compile_opts, }; let bench_args = args.get_one::("BENCHNAME").into_iter(); let bench_args = bench_args.chain(args.get_many::("args").unwrap_or_default()); let bench_args = bench_args.map(String::as_str).collect::>(); ops::run_benches(&ws, &ops, &bench_args) } cargo-0.86.0/src/bin/cargo/commands/build.rs000064400000000000000000000065201046102023000167150ustar 00000000000000use crate::command_prelude::*; use cargo::ops; pub fn cli() -> Command { subcommand("build") // subcommand aliases are handled in aliased_command() // .alias("b") .about("Compile a local package and all of its dependencies") .arg_future_incompat_report() .arg_message_format() .arg_silent_suggestion() .arg_package_spec( "Package to build (see `cargo help pkgid`)", "Build all packages in the workspace", "Exclude packages from the build", ) .arg_targets_all( "Build only this package's library", "Build only the specified binary", "Build all binaries", "Build only the specified example", "Build all examples", "Build only the specified test target", "Build all targets that have `test = true` set", "Build only the specified bench target", "Build all targets that have `bench = true` set", "Build all targets", ) .arg_features() .arg_release("Build artifacts in release mode, with optimizations") .arg_redundant_default_mode("debug", "build", "release") .arg_profile("Build artifacts with the specified profile") .arg_parallel() .arg_target_triple("Build for the target triple") .arg_target_dir() .arg_artifact_dir() .arg_build_plan() .arg_unit_graph() .arg_timings() .arg_manifest_path() .arg_lockfile_path() .arg_ignore_rust_version() .after_help(color_print::cstr!( "Run `cargo help build` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let ws = args.workspace(gctx)?; let mut compile_opts = args.compile_options(gctx, CompileMode::Build, Some(&ws), ProfileChecking::Custom)?; if let Some(artifact_dir) = args.value_of_path("artifact-dir", gctx) { // If the user specifies `--artifact-dir`, use that compile_opts.build_config.export_dir = Some(artifact_dir); } else if let Some(artifact_dir) = args.value_of_path("out-dir", gctx) { // `--out-dir` is deprecated, but still supported for now gctx.shell() .warn("the --out-dir flag has been changed to --artifact-dir")?; compile_opts.build_config.export_dir = Some(artifact_dir); } else if let Some(artifact_dir) = gctx.build_config()?.artifact_dir.as_ref() { // If a CLI option is not specified for choosing the artifact dir, use the `artifact-dir` from the build config, if // present let artifact_dir = artifact_dir.resolve_path(gctx); compile_opts.build_config.export_dir = Some(artifact_dir); } else if let Some(artifact_dir) = gctx.build_config()?.out_dir.as_ref() { // As a last priority, check `out-dir` in the build config gctx.shell() .warn("the out-dir config option has been changed to artifact-dir")?; let artifact_dir = artifact_dir.resolve_path(gctx); compile_opts.build_config.export_dir = Some(artifact_dir); } if compile_opts.build_config.export_dir.is_some() { gctx.cli_unstable() .fail_if_stable_opt("--artifact-dir", 6790)?; } ops::compile(&ws, &compile_opts)?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/check.rs000064400000000000000000000040731046102023000166740ustar 00000000000000use crate::command_prelude::*; use cargo::ops; pub fn cli() -> Command { subcommand("check") // subcommand aliases are handled in aliased_command() // .alias("c") .about("Check a local package and all of its dependencies for errors") .arg_future_incompat_report() .arg_message_format() .arg_silent_suggestion() .arg_package_spec( "Package(s) to check", "Check all packages in the workspace", "Exclude packages from the check", ) .arg_targets_all( "Check only this package's library", "Check only the specified binary", "Check all binaries", "Check only the specified example", "Check all examples", "Check only the specified test target", "Check all targets that have `test = true` set", "Check only the specified bench target", "Check all targets that have `bench = true` set", "Check all targets", ) .arg_features() .arg_parallel() .arg_release("Check artifacts in release mode, with optimizations") .arg_profile("Check artifacts with the specified profile") .arg_target_triple("Check for the target triple") .arg_target_dir() .arg_unit_graph() .arg_timings() .arg_manifest_path() .arg_lockfile_path() .arg_ignore_rust_version() .after_help(color_print::cstr!( "Run `cargo help check` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let ws = args.workspace(gctx)?; // This is a legacy behavior that causes `cargo check` to pass `--test`. let test = matches!( args.get_one::("profile").map(String::as_str), Some("test") ); let mode = CompileMode::Check { test }; let compile_opts = args.compile_options(gctx, mode, Some(&ws), ProfileChecking::LegacyTestOnly)?; ops::compile(&ws, &compile_opts)?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/clean.rs000064400000000000000000000167541046102023000167120ustar 00000000000000use crate::command_prelude::*; use crate::util::cache_lock::CacheLockMode; use cargo::core::gc::Gc; use cargo::core::gc::{parse_human_size, parse_time_span, GcOpts}; use cargo::core::global_cache_tracker::GlobalCacheTracker; use cargo::ops::CleanContext; use cargo::ops::{self, CleanOptions}; use cargo::util::print_available_packages; use std::time::Duration; pub fn cli() -> Command { subcommand("clean") .about("Remove artifacts that cargo has generated in the past") .arg_doc("Whether or not to clean just the documentation directory") .arg_silent_suggestion() .arg_package_spec_simple("Package to clean artifacts for") .arg_release("Whether or not to clean release artifacts") .arg_profile("Clean artifacts of the specified profile") .arg_target_triple("Target triple to clean output for") .arg_target_dir() .arg_manifest_path() .arg_lockfile_path() .arg_dry_run("Display what would be deleted without deleting anything") .args_conflicts_with_subcommands(true) .subcommand( subcommand("gc") .about("Clean global caches") .hide(true) .arg_silent_suggestion() .arg_dry_run("Display what would be deleted without deleting anything") // NOTE: Not all of these options may get stabilized. Some of them are // very low-level details, and may not be something typical users need. .arg( opt( "max-src-age", "Deletes source cache files that have not been used \ since the given age (unstable)", ) .value_name("DURATION") .value_parser(parse_time_span), ) .arg( opt( "max-crate-age", "Deletes crate cache files that have not been used \ since the given age (unstable)", ) .value_name("DURATION") .value_parser(parse_time_span), ) .arg( opt( "max-index-age", "Deletes registry indexes that have not been used \ since the given age (unstable)", ) .value_name("DURATION") .value_parser(parse_time_span), ) .arg( opt( "max-git-co-age", "Deletes git dependency checkouts that have not been used \ since the given age (unstable)", ) .value_name("DURATION") .value_parser(parse_time_span), ) .arg( opt( "max-git-db-age", "Deletes git dependency clones that have not been used \ since the given age (unstable)", ) .value_name("DURATION") .value_parser(parse_time_span), ) .arg( opt( "max-download-age", "Deletes any downloaded cache data that has not been used \ since the given age (unstable)", ) .value_name("DURATION") .value_parser(parse_time_span), ) .arg( opt( "max-src-size", "Deletes source cache files until the cache is under the \ given size (unstable)", ) .value_name("SIZE") .value_parser(parse_human_size), ) .arg( opt( "max-crate-size", "Deletes crate cache files until the cache is under the \ given size (unstable)", ) .value_name("SIZE") .value_parser(parse_human_size), ) .arg( opt( "max-git-size", "Deletes git dependency caches until the cache is under \ the given size (unstable)", ) .value_name("SIZE") .value_parser(parse_human_size), ) .arg( opt( "max-download-size", "Deletes downloaded cache data until the cache is under \ the given size (unstable)", ) .value_name("SIZE") .value_parser(parse_human_size), ), ) .after_help(color_print::cstr!( "Run `cargo help clean` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { match args.subcommand() { Some(("gc", args)) => { return gc(gctx, args); } Some((cmd, _)) => { unreachable!("unexpected command {}", cmd) } None => {} } let ws = args.workspace(gctx)?; if args.is_present_with_zero_values("package") { print_available_packages(&ws)?; } let opts = CleanOptions { gctx, spec: values(args, "package"), targets: args.targets()?, requested_profile: args.get_profile_name("dev", ProfileChecking::Custom)?, profile_specified: args.contains_id("profile") || args.flag("release"), doc: args.flag("doc"), dry_run: args.dry_run(), }; ops::clean(&ws, &opts)?; Ok(()) } fn gc(gctx: &GlobalContext, args: &ArgMatches) -> CliResult { gctx.cli_unstable().fail_if_stable_command( gctx, "clean gc", 12633, "gc", gctx.cli_unstable().gc, )?; let size_opt = |opt| -> Option { args.get_one::(opt).copied() }; let duration_opt = |opt| -> Option { args.get_one::(opt).copied() }; let mut gc_opts = GcOpts { max_src_age: duration_opt("max-src-age"), max_crate_age: duration_opt("max-crate-age"), max_index_age: duration_opt("max-index-age"), max_git_co_age: duration_opt("max-git-co-age"), max_git_db_age: duration_opt("max-git-db-age"), max_src_size: size_opt("max-src-size"), max_crate_size: size_opt("max-crate-size"), max_git_size: size_opt("max-git-size"), max_download_size: size_opt("max-download-size"), }; if let Some(age) = duration_opt("max-download-age") { gc_opts.set_max_download_age(age); } // If the user sets any options, then only perform the options requested. // If no options are set, do the default behavior. if !gc_opts.is_download_cache_opt_set() { gc_opts.update_for_auto_gc(gctx)?; } let _lock = gctx.acquire_package_cache_lock(CacheLockMode::MutateExclusive)?; let mut cache_track = GlobalCacheTracker::new(&gctx)?; let mut gc = Gc::new(gctx, &mut cache_track)?; let mut clean_ctx = CleanContext::new(gctx); clean_ctx.dry_run = args.dry_run(); gc.gc(&mut clean_ctx, &gc_opts)?; clean_ctx.display_summary()?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/config.rs000064400000000000000000000036741046102023000170720ustar 00000000000000use crate::command_prelude::*; use cargo::ops::cargo_config; pub fn cli() -> Command { subcommand("config") .about("Inspect configuration values") .subcommand_required(true) .arg_required_else_help(true) .subcommand( subcommand("get") .arg( Arg::new("key") .action(ArgAction::Set) .help("The config key to display"), ) .arg( opt("format", "Display format") .value_parser(cargo_config::ConfigFormat::POSSIBLE_VALUES) .default_value("toml"), ) .arg(flag( "show-origin", "Display where the config value is defined", )) .arg( opt("merged", "Whether or not to merge config values") .value_parser(["yes", "no"]) .default_value("yes"), ), ) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { gctx.cli_unstable().fail_if_stable_command( gctx, "config", 9301, "unstable-options", gctx.cli_unstable().unstable_options, )?; match args.subcommand() { Some(("get", args)) => { let opts = cargo_config::GetOptions { key: args.get_one::("key").map(String::as_str), format: args.get_one::("format").unwrap().parse()?, show_origin: args.flag("show-origin"), merged: args.get_one::("merged").map(String::as_str) == Some("yes"), }; cargo_config::get(gctx, &opts)?; } Some((cmd, _)) => { unreachable!("unexpected command {}", cmd) } None => { unreachable!("unexpected command") } } Ok(()) } cargo-0.86.0/src/bin/cargo/commands/doc.rs000064400000000000000000000042261046102023000163640ustar 00000000000000use crate::command_prelude::*; use cargo::ops::{self, DocOptions}; pub fn cli() -> Command { subcommand("doc") // subcommand aliases are handled in aliased_command() // .alias("d") .about("Build a package's documentation") .arg(flag( "open", "Opens the docs in a browser after the operation", )) .arg(flag( "no-deps", "Don't build documentation for dependencies", )) .arg(flag("document-private-items", "Document private items")) .arg_message_format() .arg_silent_suggestion() .arg_package_spec( "Package to document", "Document all packages in the workspace", "Exclude packages from the build", ) .arg_features() .arg_targets_lib_bin_example( "Document only this package's library", "Document only the specified binary", "Document all binaries", "Document only the specified example", "Document all examples", ) .arg_parallel() .arg_release("Build artifacts in release mode, with optimizations") .arg_profile("Build artifacts with the specified profile") .arg_target_triple("Build for the target triple") .arg_target_dir() .arg_unit_graph() .arg_timings() .arg_manifest_path() .arg_lockfile_path() .arg_ignore_rust_version() .after_help(color_print::cstr!( "Run `cargo help doc` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let ws = args.workspace(gctx)?; let mode = CompileMode::Doc { deps: !args.flag("no-deps"), json: false, }; let mut compile_opts = args.compile_options(gctx, mode, Some(&ws), ProfileChecking::Custom)?; compile_opts.rustdoc_document_private_items = args.flag("document-private-items"); let doc_opts = DocOptions { open_result: args.flag("open"), output_format: ops::OutputFormat::Html, compile_opts, }; ops::doc(&ws, &doc_opts)?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/fetch.rs000064400000000000000000000013441046102023000167060ustar 00000000000000use crate::command_prelude::*; use cargo::ops; use cargo::ops::FetchOptions; pub fn cli() -> Command { subcommand("fetch") .about("Fetch dependencies of a package from the network") .arg_silent_suggestion() .arg_target_triple("Fetch dependencies for the target triple") .arg_manifest_path() .arg_lockfile_path() .after_help(color_print::cstr!( "Run `cargo help fetch` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let ws = args.workspace(gctx)?; let opts = FetchOptions { gctx, targets: args.targets()?, }; let _ = ops::fetch(&ws, &opts)?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/fix.rs000064400000000000000000000071431046102023000164060ustar 00000000000000use crate::command_prelude::*; use cargo::core::Workspace; use cargo::ops; pub fn cli() -> Command { subcommand("fix") .about("Automatically fix lint warnings reported by rustc") .arg(flag("edition", "Fix in preparation for the next edition")) .arg(flag( "edition-idioms", "Fix warnings to migrate to the idioms of an edition", )) .arg(flag( "broken-code", "Fix code even if it already has compiler errors", )) .arg(flag( "allow-no-vcs", "Fix code even if a VCS was not detected", )) .arg(flag( "allow-dirty", "Fix code even if the working directory is dirty", )) .arg(flag( "allow-staged", "Fix code even if the working directory has staged changes", )) .arg_message_format() .arg_silent_suggestion() .arg_package_spec( "Package(s) to fix", "Fix all packages in the workspace", "Exclude packages from the fixes", ) .arg_targets_all( "Fix only this package's library", "Fix only the specified binary", "Fix all binaries", "Fix only the specified example", "Fix all examples", "Fix only the specified test target", "Fix all targets that have `test = true` set", "Fix only the specified bench target", "Fix all targets that have `bench = true` set", "Fix all targets (default)", ) .arg_features() .arg_parallel() .arg_release("Fix artifacts in release mode, with optimizations") .arg_profile("Build artifacts with the specified profile") .arg_target_triple("Fix for the target triple") .arg_target_dir() .arg_timings() .arg_manifest_path() .arg_lockfile_path() .arg_ignore_rust_version() .after_help(color_print::cstr!( "Run `cargo help fix` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { // This is a legacy behavior that causes `cargo fix` to pass `--test`. let test = matches!( args.get_one::("profile").map(String::as_str), Some("test") ); let mode = CompileMode::Check { test }; // Unlike other commands default `cargo fix` to all targets to fix as much // code as we can. let root_manifest = args.root_manifest(gctx)?; // Can't use workspace() to avoid using -Zavoid-dev-deps (if passed) let mut ws = Workspace::new(&root_manifest, gctx)?; ws.set_resolve_honors_rust_version(args.honor_rust_version()); let lockfile_path = args.lockfile_path(gctx)?; ws.set_requested_lockfile_path(lockfile_path.clone()); let mut opts = args.compile_options(gctx, mode, Some(&ws), ProfileChecking::LegacyTestOnly)?; if !opts.filter.is_specific() { // cargo fix with no target selection implies `--all-targets`. opts.filter = ops::CompileFilter::new_all_targets(); } ops::fix( gctx, &ws, &root_manifest, &mut ops::FixOptions { edition: args.flag("edition"), idioms: args.flag("edition-idioms"), compile_opts: opts, allow_dirty: args.flag("allow-dirty"), allow_no_vcs: args.flag("allow-no-vcs"), allow_staged: args.flag("allow-staged"), broken_code: args.flag("broken-code"), requested_lockfile_path: lockfile_path, }, )?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/generate_lockfile.rs000064400000000000000000000012171046102023000212560ustar 00000000000000use crate::command_prelude::*; use cargo::ops; pub fn cli() -> Command { subcommand("generate-lockfile") .about("Generate the lockfile for a package") .arg_silent_suggestion() .arg_manifest_path() .arg_lockfile_path() .arg_ignore_rust_version_with_help("Ignore `rust-version` specification in packages") .after_help(color_print::cstr!( "Run `cargo help generate-lockfile` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let ws = args.workspace(gctx)?; ops::generate_lockfile(&ws)?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/git_checkout.rs000064400000000000000000000006271046102023000202700ustar 00000000000000//! Removed. use crate::command_prelude::*; const REMOVED: &str = "The `git-checkout` command has been removed."; pub fn cli() -> Command { subcommand("git-checkout") .about("REMOVED: This command has been removed") .hide(true) .override_help(REMOVED) } pub fn exec(_gctx: &mut GlobalContext, _args: &ArgMatches) -> CliResult { Err(anyhow::format_err!(REMOVED).into()) } cargo-0.86.0/src/bin/cargo/commands/help.rs000064400000000000000000000130071046102023000165440ustar 00000000000000use crate::aliased_command; use crate::command_prelude::*; use cargo::drop_println; use cargo::util::errors::CargoResult; use cargo_util::paths::resolve_executable; use flate2::read::GzDecoder; use std::ffi::OsStr; use std::ffi::OsString; use std::io::Read; use std::io::Write; use std::path::Path; const COMPRESSED_MAN: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/man.tgz")); pub fn cli() -> Command { subcommand("help") .about("Displays help for a cargo subcommand") .arg(Arg::new("COMMAND").action(ArgAction::Set).add( clap_complete::ArgValueCandidates::new(|| { super::builtin() .iter() .map(|cmd| { let name = cmd.get_name(); clap_complete::CompletionCandidate::new(name) .help(cmd.get_about().cloned()) .hide(cmd.is_hide_set()) }) .collect() }), )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let subcommand = args.get_one::("COMMAND"); if let Some(subcommand) = subcommand { if !try_help(gctx, subcommand)? { match check_builtin(&subcommand) { Some(s) => { crate::execute_internal_subcommand( gctx, &[OsStr::new(s), OsStr::new("--help")], )?; } None => { crate::execute_external_subcommand( gctx, subcommand, &[OsStr::new(subcommand), OsStr::new("--help")], )?; } } } } else { let mut cmd = crate::cli::cli(gctx); let _ = cmd.print_help(); } Ok(()) } fn try_help(gctx: &GlobalContext, subcommand: &str) -> CargoResult { let subcommand = match check_alias(gctx, subcommand) { // If this alias is more than a simple subcommand pass-through, show the alias. Some(argv) if argv.len() > 1 => { let alias = argv.join(" "); drop_println!(gctx, "`{}` is aliased to `{}`", subcommand, alias); return Ok(true); } // Otherwise, resolve the alias into its subcommand. Some(argv) => { // An alias with an empty argv can be created via `"empty-alias" = ""`. let first = argv.get(0).map(String::as_str).unwrap_or(subcommand); first.to_string() } None => subcommand.to_string(), }; let subcommand = match check_builtin(&subcommand) { Some(s) => s, None => return Ok(false), }; if resolve_executable(Path::new("man")).is_ok() { let man = match extract_man(subcommand, "1") { Some(man) => man, None => return Ok(false), }; write_and_spawn(subcommand, &man, "man")?; } else { let txt = match extract_man(subcommand, "txt") { Some(txt) => txt, None => return Ok(false), }; if resolve_executable(Path::new("less")).is_ok() { write_and_spawn(subcommand, &txt, "less")?; } else if resolve_executable(Path::new("more")).is_ok() { write_and_spawn(subcommand, &txt, "more")?; } else { drop(std::io::stdout().write_all(&txt)); } } Ok(true) } /// Checks if the given subcommand is an alias. /// /// Returns None if it is not an alias. fn check_alias(gctx: &GlobalContext, subcommand: &str) -> Option> { aliased_command(gctx, subcommand).ok().flatten() } /// Checks if the given subcommand is a built-in command (not via an alias). /// /// Returns None if it is not a built-in command. fn check_builtin(subcommand: &str) -> Option<&str> { super::builtin_exec(subcommand).map(|_| subcommand) } /// Extracts the given man page from the compressed archive. /// /// Returns None if the command wasn't found. fn extract_man(subcommand: &str, extension: &str) -> Option> { let extract_name = OsString::from(format!("cargo-{}.{}", subcommand, extension)); let gz = GzDecoder::new(COMPRESSED_MAN); let mut ar = tar::Archive::new(gz); // Unwraps should be safe here, since this is a static archive generated // by our build script. It should never be an invalid format! for entry in ar.entries().unwrap() { let mut entry = entry.unwrap(); let path = entry.path().unwrap(); if path.file_name().unwrap() != extract_name { continue; } let mut result = Vec::new(); entry.read_to_end(&mut result).unwrap(); return Some(result); } None } /// Write the contents of a man page to disk and spawn the given command to /// display it. fn write_and_spawn(name: &str, contents: &[u8], command: &str) -> CargoResult<()> { let prefix = format!("cargo-{}.", name); let mut tmp = tempfile::Builder::new().prefix(&prefix).tempfile()?; let f = tmp.as_file_mut(); f.write_all(contents)?; f.flush()?; let path = tmp.path(); // Use a path relative to the temp directory so that it can work on // cygwin/msys systems which don't handle windows-style paths. let mut relative_name = std::ffi::OsString::from("./"); relative_name.push(path.file_name().unwrap()); let mut cmd = std::process::Command::new(command) .arg(relative_name) .current_dir(path.parent().unwrap()) .spawn()?; drop(cmd.wait()); Ok(()) } cargo-0.86.0/src/bin/cargo/commands/info.rs000064400000000000000000000022141046102023000165450ustar 00000000000000use anyhow::Context; use cargo::ops::info; use cargo::util::command_prelude::*; use cargo_util_schemas::core::PackageIdSpec; pub fn cli() -> Command { Command::new("info") .about("Display information about a package") .arg( Arg::new("package") .required(true) .value_name("SPEC") .help_heading(heading::PACKAGE_SELECTION) .help("Package to inspect"), ) .arg_index("Registry index URL to search packages in") .arg_registry("Registry to search packages in") .arg_silent_suggestion() .after_help(color_print::cstr!( "Run `cargo help info` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let package = args .get_one::("package") .map(String::as_str) .unwrap(); let spec = PackageIdSpec::parse(package) .with_context(|| format!("invalid package ID specification: `{package}`"))?; let reg_or_index = args.registry_or_index(gctx)?; info(&spec, gctx, reg_or_index)?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/init.rs000064400000000000000000000013231046102023000165550ustar 00000000000000use crate::command_prelude::*; use cargo::ops; pub fn cli() -> Command { subcommand("init") .about("Create a new cargo package in an existing directory") .arg( Arg::new("path") .value_name("PATH") .action(ArgAction::Set) .default_value("."), ) .arg_new_opts() .arg_registry("Registry to use") .arg_silent_suggestion() .after_help(color_print::cstr!( "Run `cargo help init` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let opts = args.new_options(gctx)?; ops::init(&opts, gctx)?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/install.rs000064400000000000000000000252171046102023000172700ustar 00000000000000use crate::command_prelude::*; use anyhow::anyhow; use anyhow::bail; use anyhow::format_err; use cargo::core::{GitReference, SourceId, Workspace}; use cargo::ops; use cargo::util::IntoUrl; use cargo::util::VersionExt; use cargo::CargoResult; use itertools::Itertools; use semver::VersionReq; use cargo_util::paths; pub fn cli() -> Command { subcommand("install") .about("Install a Rust binary") .arg( Arg::new("crate") .value_name("CRATE[@]") .help("Select the package from the given source") .value_parser(parse_crate) .num_args(0..), ) .arg( opt("version", "Specify a version to install") .alias("vers") .value_name("VERSION") .value_parser(parse_semver_flag) .requires("crate"), ) .arg( opt("index", "Registry index to install from") .value_name("INDEX") .requires("crate") .conflicts_with_all(&["git", "path", "registry"]), ) .arg( opt("registry", "Registry to use") .value_name("REGISTRY") .requires("crate") .conflicts_with_all(&["git", "path", "index"]), ) .arg( opt("git", "Git URL to install the specified crate from") .value_name("URL") .conflicts_with_all(&["path", "index", "registry"]), ) .arg( opt("branch", "Branch to use when installing from git") .value_name("BRANCH") .requires("git"), ) .arg( opt("tag", "Tag to use when installing from git") .value_name("TAG") .requires("git"), ) .arg( opt("rev", "Specific commit to use when installing from git") .value_name("SHA") .requires("git"), ) .arg( opt("path", "Filesystem path to local crate to install from") .value_name("PATH") .conflicts_with_all(&["git", "index", "registry"]), ) .arg(opt("root", "Directory to install packages into").value_name("DIR")) .arg(flag("force", "Force overwriting existing crates or binaries").short('f')) .arg_dry_run("Perform all checks without installing (unstable)") .arg(flag("no-track", "Do not save tracking information")) .arg(flag( "list", "List all installed packages and their versions", )) .arg_ignore_rust_version() .arg_message_format() .arg_silent_suggestion() .arg_targets_bins_examples( "Install only the specified binary", "Install all binaries", "Install only the specified example", "Install all examples", ) .arg_features() .arg_parallel() .arg( flag( "debug", "Build in debug mode (with the 'dev' profile) instead of release mode", ) .conflicts_with("profile"), ) .arg_redundant_default_mode("release", "install", "debug") .arg_profile("Install artifacts with the specified profile") .arg_target_triple("Build for the target triple") .arg_target_dir() .arg_timings() .arg_lockfile_path() .after_help(color_print::cstr!( "Run `cargo help install` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let path = args.value_of_path("path", gctx); if let Some(path) = &path { gctx.reload_rooted_at(path)?; } else { // TODO: Consider calling set_search_stop_path(home). gctx.reload_rooted_at(gctx.home().clone().into_path_unlocked())?; } // In general, we try to avoid normalizing paths in Cargo, // but in these particular cases we need it to fix rust-lang/cargo#10283. // (Handle `SourceId::for_path` and `Workspace::new`, // but not `GlobalContext::reload_rooted_at` which is always cwd) let path = path.map(|p| paths::normalize_path(&p)); let version = args.get_one::("version"); let krates = args .get_many::("crate") .unwrap_or_default() .cloned() .dedup_by(|x, y| x == y) .map(|(krate, local_version)| resolve_crate(krate, local_version, version)) .collect::>>()?; 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()); } if let Ok(url) = crate_name.into_url() { if matches!(url.scheme(), "http" | "https") { return Err(anyhow!( "invalid package name: `{url}` Use `cargo install --git {url}` if you meant to install from a git repository." ) .into()); } } } let mut from_cwd = false; let source = if let Some(url) = args.get_one::("git") { let url = url.into_url()?; let gitref = if let Some(branch) = args.get_one::("branch") { GitReference::Branch(branch.clone()) } else if let Some(tag) = args.get_one::("tag") { GitReference::Tag(tag.clone()) } else if let Some(rev) = args.get_one::("rev") { GitReference::Rev(rev.clone()) } else { GitReference::DefaultBranch }; SourceId::for_git(&url, gitref)? } else if let Some(path) = &path { SourceId::for_path(path)? } else if krates.is_empty() { from_cwd = true; SourceId::for_path(gctx.cwd())? } else if let Some(reg_or_index) = args.registry_or_index(gctx)? { match reg_or_index { ops::RegistryOrIndex::Registry(r) => SourceId::alt_registry(gctx, &r)?, ops::RegistryOrIndex::Index(url) => SourceId::for_registry(&url)?, } } else { SourceId::crates_io(gctx)? }; let root = args.get_one::("root").map(String::as_str); // We only provide workspace information for local crate installation from // one of the following sources: // - From current working directory (only work for edition 2015). // - From a specific local file path (from `--path` arg). // // This workspace information is for emitting helpful messages from // `ArgMatchesExt::compile_options` and won't affect the actual compilation. let workspace = if from_cwd { args.workspace(gctx).ok() } else if let Some(path) = &path { Workspace::new(&path.join("Cargo.toml"), gctx).ok() } else { None }; let mut compile_opts = args.compile_options( gctx, CompileMode::Build, workspace.as_ref(), ProfileChecking::Custom, )?; compile_opts.build_config.requested_profile = args.get_profile_name("release", ProfileChecking::Custom)?; if args.dry_run() { gctx.cli_unstable().fail_if_stable_opt("--dry-run", 11123)?; } let requested_lockfile_path = args.lockfile_path(gctx)?; // 14421: lockfile path should imply --locked on running `install` if requested_lockfile_path.is_some() { gctx.set_locked(true); } if args.flag("list") { ops::install_list(root, gctx)?; } else { ops::install( gctx, root, krates, source, from_cwd, &compile_opts, args.flag("force"), args.flag("no-track"), args.dry_run(), requested_lockfile_path.as_deref(), )?; } Ok(()) } type CrateVersion = (String, Option); fn parse_crate(krate: &str) -> crate::CargoResult { let (krate, version) = if let Some((k, v)) = krate.split_once('@') { if k.is_empty() { // by convention, arguments starting with `@` are response files anyhow::bail!("missing crate name before '@'"); } let krate = k.to_owned(); let version = Some(parse_semver_flag(v)?); (krate, version) } else { let krate = krate.to_owned(); let version = None; (krate, version) }; if krate.is_empty() { anyhow::bail!("crate name is empty"); } Ok((krate, version)) } /// Parses x.y.z as if it were =x.y.z, and gives CLI-specific error messages in the case of invalid /// values. fn parse_semver_flag(v: &str) -> CargoResult { // If the version begins with character <, >, =, ^, ~ parse it as a // version range, otherwise parse it as a specific version let first = v .chars() .next() .ok_or_else(|| format_err!("no version provided for the `--version` flag"))?; let is_req = "<>=^~".contains(first) || v.contains('*'); if is_req { match v.parse::() { Ok(v) => Ok(v), Err(_) => bail!( "the `--version` provided, `{}`, is \ not a valid semver version requirement\n\n\ Please have a look at \ https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html \ for the correct format", v ), } } else { match v.trim().parse::() { Ok(v) => Ok(v.to_exact_req()), Err(e) => { let mut msg = e.to_string(); // If it is not a valid version but it is a valid version // requirement, add a note to the warning if v.parse::().is_ok() { msg.push_str(&format!( "\n\n tip: if you want to specify SemVer range, \ add an explicit qualifier, like '^{}'", v )); } bail!(msg); } } } } fn resolve_crate( krate: String, local_version: Option, version: Option<&VersionReq>, ) -> crate::CargoResult { let version = match (local_version, version) { (Some(_), Some(_)) => { anyhow::bail!("cannot specify both `@` and `--version `"); } (Some(l), None) => Some(l), (None, Some(g)) => Some(g.to_owned()), (None, None) => None, }; Ok((krate, version)) } cargo-0.86.0/src/bin/cargo/commands/locate_project.rs000064400000000000000000000047421046102023000206170ustar 00000000000000use crate::command_prelude::*; use anyhow::bail; use cargo::{drop_println, CargoResult}; use serde::Serialize; pub fn cli() -> Command { subcommand("locate-project") .about("Print a JSON representation of a Cargo.toml file's location") .arg(flag("workspace", "Locate Cargo.toml of the workspace root")) .arg( opt( "message-format", "Output representation [possible values: json, plain]", ) .value_name("FMT"), ) .arg_silent_suggestion() .arg_manifest_path() .after_help(color_print::cstr!( "Run `cargo help locate-project` for more detailed information.\n" )) } #[derive(Serialize)] pub struct ProjectLocation<'a> { root: &'a str, } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let root_manifest; let workspace; let root = match WhatToFind::parse(args) { WhatToFind::CurrentManifest => { root_manifest = args.root_manifest(gctx)?; &root_manifest } WhatToFind::Workspace => { workspace = args.workspace(gctx)?; workspace.root_manifest() } }; let root = root .to_str() .ok_or_else(|| { anyhow::format_err!( "your package path contains characters \ not representable in Unicode" ) }) .map_err(|e| CliError::new(e, 1))?; let location = ProjectLocation { root }; match MessageFormat::parse(args)? { MessageFormat::Json => gctx.shell().print_json(&location)?, MessageFormat::Plain => drop_println!(gctx, "{}", location.root), } Ok(()) } enum WhatToFind { CurrentManifest, Workspace, } impl WhatToFind { fn parse(args: &ArgMatches) -> Self { if args.flag("workspace") { WhatToFind::Workspace } else { WhatToFind::CurrentManifest } } } enum MessageFormat { Json, Plain, } impl MessageFormat { fn parse(args: &ArgMatches) -> CargoResult { let fmt = match args.get_one::("message-format") { Some(fmt) => fmt, None => return Ok(MessageFormat::Json), }; match fmt.to_ascii_lowercase().as_str() { "json" => Ok(MessageFormat::Json), "plain" => Ok(MessageFormat::Plain), s => bail!("invalid message format specifier: `{}`", s), } } } cargo-0.86.0/src/bin/cargo/commands/login.rs000064400000000000000000000022531046102023000167250ustar 00000000000000use cargo::ops; use cargo::ops::RegistryOrIndex; use crate::command_prelude::*; pub fn cli() -> Command { subcommand("login") .about("Log in to a registry.") .arg(Arg::new("token").value_name("TOKEN").action(ArgAction::Set)) .arg_registry("Registry to use") .arg( Arg::new("args") .help("Additional arguments for the credential provider") .num_args(0..) .last(true), ) .arg_silent_suggestion() .after_help(color_print::cstr!( "Run `cargo help login` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let reg = args.registry_or_index(gctx)?; assert!( !matches!(reg, Some(RegistryOrIndex::Index(..))), "must not be index URL" ); let extra_args = args .get_many::("args") .unwrap_or_default() .map(String::as_str) .collect::>(); ops::registry_login( gctx, args.get_one::("token").map(|s| s.as_str().into()), reg.as_ref(), &extra_args, )?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/logout.rs000064400000000000000000000012611046102023000171240ustar 00000000000000use cargo::ops; use cargo::ops::RegistryOrIndex; use crate::command_prelude::*; pub fn cli() -> Command { subcommand("logout") .about("Remove an API token from the registry locally") .arg_registry("Registry to use") .arg_silent_suggestion() .after_help(color_print::cstr!( "Run `cargo help logout` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let reg = args.registry_or_index(gctx)?; assert!( !matches!(reg, Some(RegistryOrIndex::Index(..))), "must not be index URL" ); ops::registry_logout(gctx, reg)?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/metadata.rs000064400000000000000000000034501046102023000173750ustar 00000000000000use cargo::ops::{self, OutputMetadataOptions}; use crate::command_prelude::*; pub fn cli() -> Command { subcommand("metadata") .about( "Output the resolved dependencies of a package, \ the concrete used versions including overrides, \ in machine-readable format", ) .arg(multi_opt( "filter-platform", "TRIPLE", "Only include resolve dependencies matching the given target-triple", )) .arg(flag( "no-deps", "Output information only about the workspace members \ and don't fetch dependencies", )) .arg( opt("format-version", "Format version") .value_name("VERSION") .value_parser(["1"]), ) .arg_silent_suggestion() .arg_features() .arg_manifest_path() .arg_lockfile_path() .after_help(color_print::cstr!( "Run `cargo help metadata` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let ws = args.workspace(gctx)?; let version = match args.get_one::("format-version") { None => { gctx.shell().warn( "please specify `--format-version` flag explicitly \ to avoid compatibility problems", )?; 1 } Some(version) => version.parse().unwrap(), }; let options = OutputMetadataOptions { cli_features: args.cli_features()?, no_deps: args.flag("no-deps"), filter_platforms: args._values_of("filter-platform"), version, }; let result = ops::output_metadata(&ws, &options)?; gctx.shell().print_json(&result)?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/mod.rs000064400000000000000000000061511046102023000163750ustar 00000000000000use crate::command_prelude::*; pub fn builtin() -> Vec { vec![ add::cli(), bench::cli(), build::cli(), check::cli(), clean::cli(), config::cli(), doc::cli(), fetch::cli(), fix::cli(), generate_lockfile::cli(), git_checkout::cli(), help::cli(), info::cli(), init::cli(), install::cli(), locate_project::cli(), login::cli(), logout::cli(), metadata::cli(), new::cli(), owner::cli(), package::cli(), pkgid::cli(), publish::cli(), read_manifest::cli(), remove::cli(), report::cli(), run::cli(), rustc::cli(), rustdoc::cli(), search::cli(), test::cli(), tree::cli(), uninstall::cli(), update::cli(), vendor::cli(), verify_project::cli(), version::cli(), yank::cli(), ] } pub type Exec = fn(&mut GlobalContext, &ArgMatches) -> CliResult; pub fn builtin_exec(cmd: &str) -> Option { let f = match cmd { "add" => add::exec, "bench" => bench::exec, "build" => build::exec, "check" => check::exec, "clean" => clean::exec, "config" => config::exec, "doc" => doc::exec, "fetch" => fetch::exec, "fix" => fix::exec, "generate-lockfile" => generate_lockfile::exec, "git-checkout" => git_checkout::exec, "help" => help::exec, "info" => info::exec, "init" => init::exec, "install" => install::exec, "locate-project" => locate_project::exec, "login" => login::exec, "logout" => logout::exec, "metadata" => metadata::exec, "new" => new::exec, "owner" => owner::exec, "package" => package::exec, "pkgid" => pkgid::exec, "publish" => publish::exec, "read-manifest" => read_manifest::exec, "remove" => remove::exec, "report" => report::exec, "run" => run::exec, "rustc" => rustc::exec, "rustdoc" => rustdoc::exec, "search" => search::exec, "test" => test::exec, "tree" => tree::exec, "uninstall" => uninstall::exec, "update" => update::exec, "vendor" => vendor::exec, "verify-project" => verify_project::exec, "version" => version::exec, "yank" => yank::exec, _ => return None, }; Some(f) } pub mod add; pub mod bench; pub mod build; pub mod check; pub mod clean; pub mod config; pub mod doc; pub mod fetch; pub mod fix; pub mod generate_lockfile; pub mod git_checkout; pub mod help; pub mod info; pub mod init; pub mod install; pub mod locate_project; pub mod login; pub mod logout; pub mod metadata; pub mod new; pub mod owner; pub mod package; pub mod pkgid; pub mod publish; pub mod read_manifest; pub mod remove; pub mod report; pub mod run; pub mod rustc; pub mod rustdoc; pub mod search; pub mod test; pub mod tree; pub mod uninstall; pub mod update; pub mod vendor; pub mod verify_project; pub mod version; pub mod yank; cargo-0.86.0/src/bin/cargo/commands/new.rs000064400000000000000000000012761046102023000164120ustar 00000000000000use crate::command_prelude::*; use cargo::ops; pub fn cli() -> Command { subcommand("new") .about("Create a new cargo package at ") .arg( Arg::new("path") .value_name("PATH") .action(ArgAction::Set) .required(true), ) .arg_new_opts() .arg_registry("Registry to use") .arg_silent_suggestion() .after_help(color_print::cstr!( "Run `cargo help new` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let opts = args.new_options(gctx)?; ops::new(&opts, gctx)?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/owner.rs000064400000000000000000000032751046102023000167540ustar 00000000000000use crate::command_prelude::*; use cargo::ops::{self, OwnersOptions}; use cargo_credential::Secret; pub fn cli() -> Command { subcommand("owner") .about("Manage the owners of a crate on the registry") .arg(Arg::new("crate").value_name("CRATE").action(ArgAction::Set)) .arg( multi_opt( "add", "LOGIN", "Name of a user or team to invite as an owner", ) .short('a'), ) .arg( multi_opt( "remove", "LOGIN", "Name of a user or team to remove as an owner", ) .short('r'), ) .arg(flag("list", "List owners of a crate").short('l')) .arg_index("Registry index URL to modify owners for") .arg_registry("Registry to modify owners for") .arg(opt("token", "API token to use when authenticating").value_name("TOKEN")) .arg_silent_suggestion() .after_help(color_print::cstr!( "Run `cargo help owner` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let opts = OwnersOptions { krate: args.get_one::("crate").cloned(), token: args.get_one::("token").cloned().map(Secret::from), reg_or_index: args.registry_or_index(gctx)?, to_add: args .get_many::("add") .map(|xs| xs.cloned().collect()), to_remove: args .get_many::("remove") .map(|xs| xs.cloned().collect()), list: args.flag("list"), }; ops::modify_owners(gctx, &opts)?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/package.rs000064400000000000000000000054411046102023000172120ustar 00000000000000use crate::command_prelude::*; use cargo::ops::{self, PackageOpts}; pub fn cli() -> Command { subcommand("package") .about("Assemble the local package into a distributable tarball") .arg_index("Registry index URL to prepare the package for (unstable)") .arg_registry("Registry to prepare the package for (unstable)") .arg( flag( "list", "Print files included in a package without making one", ) .short('l'), ) .arg(flag( "no-verify", "Don't verify the contents by building them", )) .arg(flag( "no-metadata", "Ignore warnings about a lack of human-usable metadata", )) .arg(flag( "allow-dirty", "Allow dirty working directories to be packaged", )) .arg_silent_suggestion() .arg_package_spec_no_all( "Package(s) to assemble", "Assemble all packages in the workspace", "Don't assemble specified packages", ) .arg_features() .arg_target_triple("Build for the target triple") .arg_target_dir() .arg_parallel() .arg_manifest_path() .arg_lockfile_path() .after_help(color_print::cstr!( "Run `cargo help package` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { if args._value_of("registry").is_some() { gctx.cli_unstable().fail_if_stable_opt_custom_z( "--registry", 13947, "package-workspace", gctx.cli_unstable().package_workspace, )?; } if args._value_of("index").is_some() { gctx.cli_unstable().fail_if_stable_opt_custom_z( "--index", 13947, "package-workspace", gctx.cli_unstable().package_workspace, )?; } let reg_or_index = args.registry_or_index(gctx)?; let ws = args.workspace(gctx)?; if ws.root_maybe().is_embedded() { return Err(anyhow::format_err!( "{} is unsupported by `cargo package`", ws.root_manifest().display() ) .into()); } let specs = args.packages_from_flags()?; ops::package( &ws, &PackageOpts { gctx, verify: !args.flag("no-verify"), list: args.flag("list"), check_metadata: !args.flag("no-metadata"), allow_dirty: args.flag("allow-dirty"), to_package: specs, targets: args.targets()?, jobs: args.jobs()?, keep_going: args.keep_going(), cli_features: args.cli_features()?, reg_or_index, }, )?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/pkgid.rs000064400000000000000000000023071046102023000167130ustar 00000000000000use crate::command_prelude::*; use cargo::ops; use cargo::util::print_available_packages; pub fn cli() -> Command { subcommand("pkgid") .about("Print a fully qualified package specification") .arg(Arg::new("spec").value_name("SPEC").action(ArgAction::Set)) .arg_silent_suggestion() .arg_package("Argument to get the package ID specifier for") .arg_manifest_path() .arg_lockfile_path() .after_help(color_print::cstr!( "Run `cargo help pkgid` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let ws = args.workspace(gctx)?; if ws.root_maybe().is_embedded() { return Err(anyhow::format_err!( "{} is unsupported by `cargo pkgid`", ws.root_manifest().display() ) .into()); } if args.is_present_with_zero_values("package") { print_available_packages(&ws)? } let spec = args .get_one::("spec") .or_else(|| args.get_one::("package")) .map(String::as_str); let spec = ops::pkgid(&ws, spec)?; cargo::drop_println!(gctx, "{}", spec); Ok(()) } cargo-0.86.0/src/bin/cargo/commands/publish.rs000064400000000000000000000053651046102023000172720ustar 00000000000000use crate::command_prelude::*; use cargo::ops::{self, PublishOpts}; pub fn cli() -> Command { subcommand("publish") .about("Upload a package to the registry") .arg_dry_run("Perform all checks without uploading") .arg_index("Registry index URL to upload the package to") .arg_registry("Registry to upload the package to") .arg(opt("token", "Token to use when uploading").value_name("TOKEN")) .arg(flag( "no-verify", "Don't verify the contents by building them", )) .arg(flag( "allow-dirty", "Allow dirty working directories to be packaged", )) .arg_silent_suggestion() .arg_package_spec_no_all( "Package(s) to publish", "Publish all packages in the workspace (unstable)", "Don't publish specified packages (unstable)", ) .arg_features() .arg_parallel() .arg_target_triple("Build for the target triple") .arg_target_dir() .arg_manifest_path() .arg_lockfile_path() .after_help(color_print::cstr!( "Run `cargo help publish` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let reg_or_index = args.registry_or_index(gctx)?; let ws = args.workspace(gctx)?; if ws.root_maybe().is_embedded() { return Err(anyhow::format_err!( "{} is unsupported by `cargo publish`", ws.root_manifest().display() ) .into()); } let unstable = gctx.cli_unstable(); let enabled = unstable.package_workspace; if args.get_flag("workspace") { unstable.fail_if_stable_opt_custom_z("--workspace", 10948, "package-workspace", enabled)?; } if args._value_of("exclude").is_some() { unstable.fail_if_stable_opt_custom_z("--exclude", 10948, "package-workspace", enabled)?; } if args._values_of("package").len() > 1 { unstable.fail_if_stable_opt_custom_z( "--package (multiple occurrences)", 10948, "package-workspace", enabled, )?; } ops::publish( &ws, &PublishOpts { gctx, token: args .get_one::("token") .map(|s| s.to_string().into()), reg_or_index, verify: !args.flag("no-verify"), allow_dirty: args.flag("allow-dirty"), to_publish: args.packages_from_flags()?, targets: args.targets()?, jobs: args.jobs()?, keep_going: args.keep_going(), dry_run: args.dry_run(), cli_features: args.cli_features()?, }, )?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/read_manifest.rs000064400000000000000000000011641046102023000204160ustar 00000000000000//! Deprecated. use crate::command_prelude::*; pub fn cli() -> Command { subcommand("read-manifest") .hide(true) .about(color_print::cstr!( "\ DEPRECATED: Print a JSON representation of a Cargo.toml manifest. Use `cargo metadata --no-deps` instead.\ " )) .arg_silent_suggestion() .arg_manifest_path() } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let ws = args.workspace(gctx)?; gctx.shell().print_json( &ws.current()? .serialized(gctx.cli_unstable(), ws.unstable_features()), )?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/remove.rs000064400000000000000000000315311046102023000171130ustar 00000000000000use cargo::core::dependency::DepKind; use cargo::core::PackageIdSpec; use cargo::core::PackageIdSpecQuery; use cargo::core::Resolve; use cargo::core::Workspace; use cargo::ops::cargo_remove::remove; use cargo::ops::cargo_remove::RemoveOptions; use cargo::ops::resolve_ws; use cargo::util::command_prelude::*; use cargo::util::print_available_packages; use cargo::util::toml_mut::dependency::Dependency; use cargo::util::toml_mut::dependency::MaybeWorkspace; use cargo::util::toml_mut::dependency::Source; use cargo::util::toml_mut::manifest::DepTable; use cargo::util::toml_mut::manifest::LocalManifest; use cargo::CargoResult; pub fn cli() -> clap::Command { clap::Command::new("remove") // Subcommand aliases are handled in `aliased_command()`. // .alias("rm") .about("Remove dependencies from a Cargo.toml manifest file") .args([clap::Arg::new("dependencies") .action(clap::ArgAction::Append) .required(true) .num_args(1..) .value_name("DEP_ID") .help("Dependencies to be removed")]) .arg_dry_run("Don't actually write the manifest") .arg_silent_suggestion() .next_help_heading("Section") .args([ clap::Arg::new("dev") .long("dev") .conflicts_with("build") .action(clap::ArgAction::SetTrue) .group("section") .help("Remove from dev-dependencies"), clap::Arg::new("build") .long("build") .conflicts_with("dev") .action(clap::ArgAction::SetTrue) .group("section") .help("Remove from build-dependencies"), clap::Arg::new("target") .long("target") .num_args(1) .value_name("TARGET") .value_parser(clap::builder::NonEmptyStringValueParser::new()) .help("Remove from target-dependencies"), ]) .arg_package("Package to remove from") .arg_manifest_path() .arg_lockfile_path() .after_help(color_print::cstr!( "Run `cargo help remove` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let dry_run = args.dry_run(); let workspace = args.workspace(gctx)?; if args.is_present_with_zero_values("package") { print_available_packages(&workspace)?; } let packages = args.packages_from_flags()?; let packages = packages.get_packages(&workspace)?; let spec = match packages.len() { 0 => { return Err(CliError::new( anyhow::format_err!( "no packages selected to modify. Please specify one with `-p `" ), 101, )); } 1 => packages[0], _ => { let names = packages.iter().map(|p| p.name()).collect::>(); return Err(CliError::new( anyhow::format_err!( "`cargo remove` could not determine which package to modify. \ Use the `--package` option to specify a package. \n\ available packages: {}", names.join(", ") ), 101, )); } }; let dependencies = args .get_many::("dependencies") .expect("required(true)") .cloned() .collect::>(); let section = parse_section(args); let options = RemoveOptions { gctx, spec, dependencies, section, dry_run, }; remove(&options)?; if !dry_run { // Clean up the workspace gc_workspace(&workspace)?; // Reload the workspace since we've changed dependencies let ws = args.workspace(gctx)?; let resolve = { // HACK: Avoid unused patch warnings by temporarily changing the verbosity. // In rare cases, this might cause index update messages to not show up let verbosity = ws.gctx().shell().verbosity(); ws.gctx() .shell() .set_verbosity(cargo::core::Verbosity::Quiet); let resolve = resolve_ws(&ws, dry_run); ws.gctx().shell().set_verbosity(verbosity); resolve?.1 }; // Attempt to gc unused patches and re-resolve if anything is removed if gc_unused_patches(&workspace, &resolve)? { let ws = args.workspace(gctx)?; resolve_ws(&ws, dry_run)?; } } Ok(()) } fn parse_section(args: &ArgMatches) -> DepTable { let dev = args.flag("dev"); let build = args.flag("build"); let kind = if dev { DepKind::Development } else if build { DepKind::Build } else { DepKind::Normal }; let mut table = DepTable::new().set_kind(kind); if let Some(target) = args.get_one::("target") { assert!(!target.is_empty(), "Target specification may not be empty"); table = table.set_target(target); } table } /// Clean up the workspace.dependencies, profile, patch, and replace sections of the root manifest /// by removing dependencies which no longer have a reference to them. fn gc_workspace(workspace: &Workspace<'_>) -> CargoResult<()> { let mut workspace_manifest = LocalManifest::try_new(workspace.root_manifest())?; let mut is_modified = true; let members = workspace .members() .map(|p| { Ok(( LocalManifest::try_new(p.manifest_path())?, p.manifest().unstable_features(), )) }) .collect::>>()?; let mut dependencies = members .into_iter() .flat_map(|(member_manifest, unstable_features)| { member_manifest .get_sections() .into_iter() .flat_map(move |(_, table)| { table .as_table_like() .unwrap() .iter() .map(|(key, item)| { Dependency::from_toml( workspace.gctx(), workspace.root(), &member_manifest.path, &unstable_features, key, item, ) }) .collect::>() }) }) .collect::>>()?; // Clean up the workspace.dependencies section and replace instances of // workspace dependencies with their definitions if let Some(toml_edit::Item::Table(deps_table)) = workspace_manifest .data .get_mut("workspace") .and_then(|t| t.get_mut("dependencies")) { deps_table.set_implicit(true); for (key, item) in deps_table.iter_mut() { let ws_dep = Dependency::from_toml( workspace.gctx(), workspace.root(), &workspace.root(), workspace.unstable_features(), key.get(), item, )?; // search for uses of this workspace dependency let mut is_used = false; for dep in dependencies.iter_mut().filter(|d| { d.toml_key() == key.get() && matches!(d.source(), Some(Source::Workspace(_))) }) { // HACK: Replace workspace references in `dependencies` to simplify later GC steps: // 1. Avoid having to look it up again to determine the dependency source / spec // 2. The entry might get deleted, preventing us from looking it up again // // This does lose extra information, like features enabled, but that shouldn't be a // problem for GC *dep = ws_dep.clone(); is_used = true; } if !is_used { *item = toml_edit::Item::None; is_modified = true; } } } // Clean up the profile section // // Example tables: // - profile.dev.package.foo // - profile.release.package."foo:2.1.0" if let Some(toml_edit::Item::Table(profile_section_table)) = workspace_manifest.data.get_mut("profile") { profile_section_table.set_implicit(true); for (_, item) in profile_section_table.iter_mut() { if let toml_edit::Item::Table(profile_table) = item { profile_table.set_implicit(true); if let Some(toml_edit::Item::Table(package_table)) = profile_table.get_mut("package") { package_table.set_implicit(true); for (key, item) in package_table.iter_mut() { let key = key.get(); // Skip globs. Can't do anything with them. // For example, profile.release.package."*". if crate::util::restricted_names::is_glob_pattern(key) { continue; } if !spec_has_match( &PackageIdSpec::parse(key)?, &dependencies, workspace.gctx(), )? { *item = toml_edit::Item::None; is_modified = true; } } } } } } // Clean up the replace section if let Some(toml_edit::Item::Table(table)) = workspace_manifest.data.get_mut("replace") { table.set_implicit(true); for (key, item) in table.iter_mut() { if !spec_has_match( &PackageIdSpec::parse(key.get())?, &dependencies, workspace.gctx(), )? { *item = toml_edit::Item::None; is_modified = true; } } } if is_modified { workspace_manifest.write()?; } Ok(()) } /// Check whether or not a package ID spec matches any non-workspace dependencies. fn spec_has_match( spec: &PackageIdSpec, dependencies: &[Dependency], gctx: &GlobalContext, ) -> CargoResult { for dep in dependencies { if spec.name() != &dep.name { continue; } let version_matches = match (spec.version(), dep.version()) { (Some(v), Some(vq)) => semver::VersionReq::parse(vq)?.matches(&v), (Some(_), None) => false, (None, None | Some(_)) => true, }; if !version_matches { continue; } match dep.source_id(gctx)? { MaybeWorkspace::Other(source_id) => { if spec.url().map(|u| u == source_id.url()).unwrap_or(true) { return Ok(true); } } MaybeWorkspace::Workspace(_) => {} } } Ok(false) } /// Removes unused patches from the manifest fn gc_unused_patches(workspace: &Workspace<'_>, resolve: &Resolve) -> CargoResult { let mut workspace_manifest = LocalManifest::try_new(workspace.root_manifest())?; let mut modified = false; // Clean up the patch section if let Some(toml_edit::Item::Table(patch_section_table)) = workspace_manifest.data.get_mut("patch") { patch_section_table.set_implicit(true); for (_, item) in patch_section_table.iter_mut() { if let toml_edit::Item::Table(patch_table) = item { patch_table.set_implicit(true); for (key, item) in patch_table.iter_mut() { let dep = Dependency::from_toml( workspace.gctx(), workspace.root(), &workspace.root_manifest(), workspace.unstable_features(), key.get(), item, )?; // Generate a PackageIdSpec url for querying let url = if let MaybeWorkspace::Other(source_id) = dep.source_id(workspace.gctx())? { format!("{}#{}", source_id.url(), dep.name) } else { continue; }; if PackageIdSpec::query_str(&url, resolve.unused_patches().iter().cloned()) .is_ok() { *item = toml_edit::Item::None; modified = true; } } } } } if modified { workspace_manifest.write()?; } Ok(modified) } cargo-0.86.0/src/bin/cargo/commands/report.rs000064400000000000000000000035111046102023000171260ustar 00000000000000use crate::command_prelude::*; use cargo::core::compiler::future_incompat::{OnDiskReports, REPORT_PREAMBLE}; use cargo::drop_println; pub fn cli() -> Command { subcommand("report") .about("Generate and display various kinds of reports") .after_help(color_print::cstr!( "Run `cargo help report` for more detailed information.\n" )) .subcommand_required(true) .arg_required_else_help(true) .subcommand( subcommand("future-incompatibilities") .alias("future-incompat") .about("Reports any crates which will eventually stop compiling") .arg( opt( "id", "identifier of the report generated by a Cargo command invocation", ) .value_name("id"), ) .arg_package("Package to display a report for"), ) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { match args.subcommand() { Some(("future-incompatibilities", args)) => report_future_incompatibilities(gctx, args), Some((cmd, _)) => { unreachable!("unexpected command {}", cmd) } None => { unreachable!("unexpected command") } } } fn report_future_incompatibilities(gctx: &GlobalContext, args: &ArgMatches) -> CliResult { let ws = args.workspace(gctx)?; let reports = OnDiskReports::load(&ws)?; let id = args .value_of_u32("id")? .unwrap_or_else(|| reports.last_id()); let krate = args.get_one::("package").map(String::as_str); let report = reports.get_report(id, krate)?; drop_println!(gctx, "{}", REPORT_PREAMBLE); drop(gctx.shell().print_ansi_stdout(report.as_bytes())); Ok(()) } cargo-0.86.0/src/bin/cargo/commands/run.rs000064400000000000000000000215311046102023000164210ustar 00000000000000use 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::closest; use cargo_util::ProcessError; use itertools::Itertools as _; pub fn cli() -> Command { subcommand("run") // subcommand aliases are handled in aliased_command() // .alias("r") .about("Run a binary or example of the local package") .arg( Arg::new("args") .value_name("ARGS") .help("Arguments for the binary or example to run") .value_parser(value_parser!(OsString)) .num_args(0..) .trailing_var_arg(true), ) .arg_message_format() .arg_silent_suggestion() .arg_package("Package with the target to run") .arg_targets_bin_example( "Name of the bin target to run", "Name of the example target to run", ) .arg_features() .arg_parallel() .arg_release("Build artifacts in release mode, with optimizations") .arg_profile("Build artifacts with the specified profile") .arg_target_triple("Build for the target triple") .arg_target_dir() .arg_manifest_path() .arg_lockfile_path() .arg_ignore_rust_version() .arg_unit_graph() .arg_timings() .after_help(color_print::cstr!( "Run `cargo help run` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let ws = args.workspace(gctx)?; let mut compile_opts = args.compile_options(gctx, CompileMode::Build, Some(&ws), ProfileChecking::Custom)?; // Disallow `spec` to be an glob pattern if let Packages::Packages(opt_in) = &compile_opts.spec { if let Some(pattern) = opt_in.iter().find(|s| is_glob_pattern(s)) { return Err(anyhow::anyhow!( "`cargo run` does not support glob pattern `{}` on package selection", pattern, ) .into()); } } if !args.contains_id("example") && !args.contains_id("bin") { let default_runs: Vec<_> = compile_opts .spec .get_packages(&ws)? .iter() .filter_map(|pkg| pkg.manifest().default_run()) .collect(); if let [bin] = &default_runs[..] { compile_opts.filter = CompileFilter::single_bin(bin.to_string()); } else { // ops::run will take care of errors if len pkgs != 1. compile_opts.filter = CompileFilter::Default { // Force this to false because the code in ops::run is not // able to pre-check features before compilation starts to // enforce that only 1 binary is built. required_features_filterable: false, }; } }; ops::run(&ws, &compile_opts, &values_os(args, "args")).map_err(|err| to_run_error(gctx, 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")) } pub fn exec_manifest_command(gctx: &mut GlobalContext, cmd: &str, args: &[OsString]) -> CliResult { let manifest_path = Path::new(cmd); match (manifest_path.is_file(), gctx.cli_unstable().script) { (true, true) => {} (true, false) => { return Err(anyhow::anyhow!("running the file `{cmd}` requires `-Zscript`").into()); } (false, true) => { let possible_commands = crate::list_commands(gctx); let is_dir = if manifest_path.is_dir() { format!("\n\t`{cmd}` is a directory") } else { "".to_owned() }; let suggested_command = if let Some(suggested_command) = possible_commands .keys() .filter(|c| cmd.starts_with(c.as_str())) .max_by_key(|c| c.len()) { let actual_args = cmd.strip_prefix(suggested_command).unwrap(); let args = if args.is_empty() { "".to_owned() } else { format!( " {}", args.into_iter().map(|os| os.to_string_lossy()).join(" ") ) }; format!("\n\tDid you mean the command `{suggested_command} {actual_args}{args}`") } else { "".to_owned() }; let suggested_script = if let Some(suggested_script) = suggested_script(cmd) { format!("\n\tDid you mean the file `{suggested_script}`") } else { "".to_owned() }; return Err(anyhow::anyhow!( "no such file or subcommand `{cmd}`{is_dir}{suggested_command}{suggested_script}" ) .into()); } (false, false) => { // HACK: duplicating the above for minor tweaks but this will all go away on // stabilization let possible_commands = crate::list_commands(gctx); let suggested_command = if let Some(suggested_command) = possible_commands .keys() .filter(|c| cmd.starts_with(c.as_str())) .max_by_key(|c| c.len()) { let actual_args = cmd.strip_prefix(suggested_command).unwrap(); let args = if args.is_empty() { "".to_owned() } else { format!( " {}", args.into_iter().map(|os| os.to_string_lossy()).join(" ") ) }; format!("\n\tDid you mean the command `{suggested_command} {actual_args}{args}`") } else { "".to_owned() }; let suggested_script = if let Some(suggested_script) = suggested_script(cmd) { format!("\n\tDid you mean the file `{suggested_script}` with `-Zscript`") } else { "".to_owned() }; return Err(anyhow::anyhow!( "no such subcommand `{cmd}`{suggested_command}{suggested_script}" ) .into()); } } let manifest_path = root_manifest(Some(manifest_path), gctx)?; // Reload to cargo home. gctx.reload_rooted_at(gctx.home().clone().into_path_unlocked())?; let mut ws = Workspace::new(&manifest_path, gctx)?; if gctx.cli_unstable().avoid_dev_deps { ws.set_require_optional_deps(false); } let mut compile_opts = cargo::ops::CompileOptions::new(gctx, 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(gctx, err)) } fn suggested_script(cmd: &str) -> Option { let cmd_path = Path::new(cmd); let mut suggestion = Path::new(".").to_owned(); for cmd_part in cmd_path.components() { let exact_match = suggestion.join(cmd_part); suggestion = if exact_match.exists() { exact_match } else { let possible: Vec<_> = std::fs::read_dir(suggestion) .into_iter() .flatten() .filter_map(|e| e.ok()) .map(|e| e.path()) .filter(|p| p.to_str().is_some()) .collect(); if let Some(possible) = closest( cmd_part.as_os_str().to_str().unwrap(), possible.iter(), |p| p.file_name().unwrap().to_str().unwrap(), ) { possible.to_owned() } else { return None; } }; } if suggestion.is_dir() { None } else { suggestion.into_os_string().into_string().ok() } } fn to_run_error(gctx: &GlobalContext, err: anyhow::Error) -> CliError { let proc_err = match err.downcast_ref::() { 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 = gctx.shell().verbosity() == Verbosity::Quiet; if is_quiet { CliError::code(exit_code) } else { CliError::new(err, exit_code) } } cargo-0.86.0/src/bin/cargo/commands/rustc.rs000064400000000000000000000073261046102023000167630ustar 00000000000000use crate::command_prelude::*; use cargo::ops; use cargo::util::interning::InternedString; const PRINT_ARG_NAME: &str = "print"; const CRATE_TYPE_ARG_NAME: &str = "crate-type"; pub fn cli() -> Command { subcommand("rustc") .about("Compile a package, and pass extra options to the compiler") .arg( Arg::new("args") .value_name("ARGS") .num_args(0..) .help("Extra rustc flags") .trailing_var_arg(true), ) .arg( opt( PRINT_ARG_NAME, "Output compiler information without compiling", ) .value_name("INFO"), ) .arg(multi_opt( CRATE_TYPE_ARG_NAME, "CRATE-TYPE", "Comma separated list of types of crates for the compiler to emit", )) .arg_future_incompat_report() .arg_message_format() .arg_silent_suggestion() .arg_package("Package to build") .arg_targets_all( "Build only this package's library", "Build only the specified binary", "Build all binaries", "Build only the specified example", "Build all examples", "Build only the specified test target", "Build all targets that have `test = true` set", "Build only the specified bench target", "Build all targets that have `bench = true` set", "Build all targets", ) .arg_features() .arg_parallel() .arg_release("Build artifacts in release mode, with optimizations") .arg_profile("Build artifacts with the specified profile") .arg_target_triple("Target triple which compiles will be for") .arg_target_dir() .arg_unit_graph() .arg_timings() .arg_manifest_path() .arg_lockfile_path() .arg_ignore_rust_version() .after_help(color_print::cstr!( "Run `cargo help rustc` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let ws = args.workspace(gctx)?; // This is a legacy behavior that changes the behavior based on the profile. // If we want to support this more formally, I think adding a --mode flag // would be warranted. let mode = match args.get_one::("profile").map(String::as_str) { Some("test") => CompileMode::Test, Some("bench") => CompileMode::Bench, Some("check") => CompileMode::Check { test: false }, _ => CompileMode::Build, }; let mut compile_opts = args.compile_options_for_single_package( gctx, mode, Some(&ws), ProfileChecking::LegacyRustc, )?; if compile_opts.build_config.requested_profile == "check" { compile_opts.build_config.requested_profile = InternedString::new("dev"); } let target_args = values(args, "args"); compile_opts.target_rustc_args = if target_args.is_empty() { None } else { Some(target_args) }; if let Some(opt_value) = args.get_one::(PRINT_ARG_NAME) { gctx.cli_unstable() .fail_if_stable_opt(PRINT_ARG_NAME, 9357)?; ops::print(&ws, &compile_opts, opt_value)?; return Ok(()); } let crate_types = args .get_many::(CRATE_TYPE_ARG_NAME) .into_iter() .flatten() .flat_map(|s| s.split(',')) .filter(|s| !s.is_empty()) .map(String::from) .collect::>(); compile_opts.target_rustc_crate_types = if crate_types.is_empty() { None } else { Some(crate_types) }; ops::compile(&ws, &compile_opts)?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/rustdoc.rs000064400000000000000000000054671046102023000173120ustar 00000000000000use cargo::ops::{self, DocOptions, OutputFormat}; use crate::command_prelude::*; pub fn cli() -> Command { subcommand("rustdoc") .about("Build a package's documentation, using specified custom flags.") .arg( Arg::new("args") .value_name("ARGS") .help("Extra rustdoc flags") .num_args(0..) .trailing_var_arg(true), ) .arg(flag( "open", "Opens the docs in a browser after the operation", )) .arg_message_format() .arg_silent_suggestion() .arg_package("Package to document") .arg_targets_all( "Build only this package's library", "Build only the specified binary", "Build all binaries", "Build only the specified example", "Build all examples", "Build only the specified test target", "Build all targets that have `test = true` set", "Build only the specified bench target", "Build all targets that have `bench = true` set", "Build all targets", ) .arg_features() .arg_parallel() .arg_release("Build artifacts in release mode, with optimizations") .arg_profile("Build artifacts with the specified profile") .arg_target_triple("Build for the target triple") .arg_target_dir() .arg( opt("output-format", "The output type to write (unstable)") .value_name("FMT") .value_parser(OutputFormat::POSSIBLE_VALUES), ) .arg_unit_graph() .arg_timings() .arg_manifest_path() .arg_lockfile_path() .arg_ignore_rust_version() .after_help(color_print::cstr!( "Run `cargo help rustdoc` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let ws = args.workspace(gctx)?; let output_format = if let Some(output_format) = args._value_of("output-format") { gctx.cli_unstable() .fail_if_stable_opt("--output-format", 12103)?; output_format.parse()? } else { OutputFormat::Html }; let mut compile_opts = args.compile_options_for_single_package( gctx, CompileMode::Doc { deps: false, json: matches!(output_format, OutputFormat::Json), }, Some(&ws), ProfileChecking::Custom, )?; let target_args = values(args, "args"); compile_opts.target_rustdoc_args = if target_args.is_empty() { None } else { Some(target_args) }; let doc_opts = DocOptions { open_result: args.flag("open"), output_format, compile_opts, }; ops::doc(&ws, &doc_opts)?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/search.rs000064400000000000000000000022771046102023000170700ustar 00000000000000use crate::command_prelude::*; use std::cmp::min; use cargo::ops; pub fn cli() -> Command { subcommand("search") .about("Search packages in the registry. Default registry is crates.io") .arg(Arg::new("query").value_name("QUERY").num_args(0..)) .arg( opt( "limit", "Limit the number of results (default: 10, max: 100)", ) .value_name("LIMIT"), ) .arg_index("Registry index URL to search packages in") .arg_registry("Registry to search packages in") .arg_silent_suggestion() .after_help(color_print::cstr!( "Run `cargo help search` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let reg_or_index = args.registry_or_index(gctx)?; let limit = args.value_of_u32("limit")?; let limit = min(100, limit.unwrap_or(10)); let query: Vec<&str> = args .get_many::("query") .unwrap_or_default() .map(String::as_str) .collect(); let query: String = query.join("+"); ops::search(&query, gctx, reg_or_index, limit)?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/test.rs000064400000000000000000000105701046102023000165750ustar 00000000000000use crate::command_prelude::*; use cargo::ops; pub fn cli() -> Command { subcommand("test") // Subcommand aliases are handled in `aliased_command()`. // .alias("t") .about("Execute all unit and integration tests and build examples of a local package") .arg( Arg::new("TESTNAME") .action(ArgAction::Set) .help("If specified, only run tests containing this string in their names"), ) .arg( Arg::new("args") .value_name("ARGS") .help("Arguments for the test binary") .num_args(0..) .last(true), ) .arg(flag("no-run", "Compile, but don't run tests")) .arg(flag("no-fail-fast", "Run all tests regardless of failure")) .arg_future_incompat_report() .arg_message_format() .arg( flag( "quiet", "Display one character per test instead of one line", ) .short('q'), ) .arg_package_spec( "Package to run tests for", "Test all packages in the workspace", "Exclude packages from the test", ) .arg_targets_all( "Test only this package's library", "Test only the specified binary", "Test all binaries", "Test only the specified example", "Test all examples", "Test only the specified test target", "Test all targets that have `test = true` set", "Test only the specified bench target", "Test all targets that have `bench = true` set", "Test all targets (does not include doctests)", ) .arg( flag("doc", "Test only this library's documentation") .help_heading(heading::TARGET_SELECTION), ) .arg_features() .arg_jobs() .arg_unsupported_keep_going() .arg_release("Build artifacts in release mode, with optimizations") .arg_profile("Build artifacts with the specified profile") .arg_target_triple("Build for the target triple") .arg_target_dir() .arg_unit_graph() .arg_timings() .arg_manifest_path() .arg_lockfile_path() .arg_ignore_rust_version() .after_help(color_print::cstr!( "Run `cargo help test` for more detailed information.\n\ Run `cargo test -- --help` for test binary options.\n", )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let ws = args.workspace(gctx)?; let mut compile_opts = args.compile_options(gctx, CompileMode::Test, Some(&ws), ProfileChecking::Custom)?; compile_opts.build_config.requested_profile = args.get_profile_name("test", ProfileChecking::Custom)?; // `TESTNAME` is actually an argument of the test binary, but it's // important, so we explicitly mention it and reconfigure. let test_name = args.get_one::("TESTNAME"); let test_args = args.get_one::("TESTNAME").into_iter(); let test_args = test_args.chain(args.get_many::("args").unwrap_or_default()); let test_args = test_args.map(String::as_str).collect::>(); let no_run = args.flag("no-run"); let doc = args.flag("doc"); if doc { if compile_opts.filter.is_specific() { return Err( anyhow::format_err!("Can't mix --doc with other target selecting options").into(), ); } if no_run { return Err(anyhow::format_err!("Can't skip running doc tests with --no-run").into()); } compile_opts.build_config.mode = CompileMode::Doctest; compile_opts.filter = ops::CompileFilter::lib_only(); } else if test_name.is_some() && !compile_opts.filter.is_specific() { // If arg `TESTNAME` is provided, assumed that the user knows what // exactly they wants to test, so we use `all_test_targets` to // avoid compiling unnecessary targets such as examples, which are // included by the logic of default target filter. compile_opts.filter = ops::CompileFilter::all_test_targets(); } let ops = ops::TestOptions { no_run, no_fail_fast: args.flag("no-fail-fast"), compile_opts, }; ops::run_tests(&ws, &ops, &test_args) } cargo-0.86.0/src/bin/cargo/commands/tree.rs000064400000000000000000000260601046102023000165560ustar 00000000000000use crate::cli; use crate::command_prelude::*; use anyhow::{bail, format_err}; use cargo::core::dependency::DepKind; use cargo::ops::tree::{self, DisplayDepth, EdgeKind}; use cargo::ops::Packages; use cargo::util::print_available_packages; use cargo::util::CargoResult; use std::collections::HashSet; use std::str::FromStr; pub fn cli() -> Command { subcommand("tree") .about("Display a tree visualization of a dependency graph") .arg( flag("all", "Deprecated, use --no-dedupe instead") .short('a') .hide(true), ) .arg_silent_suggestion() .arg(flag("no-dev-dependencies", "Deprecated, use -e=no-dev instead").hide(true)) .arg( multi_opt( "edges", "KINDS", "The kinds of dependencies to display \ (features, normal, build, dev, all, \ no-normal, no-build, no-dev, no-proc-macro)", ) .short('e'), ) .arg( optional_multi_opt( "invert", "SPEC", "Invert the tree direction and focus on the given package", ) .short('i'), ) .arg(multi_opt( "prune", "SPEC", "Prune the given package from the display of the dependency tree", )) .arg(opt("depth", "Maximum display depth of the dependency tree").value_name("DEPTH")) .arg(flag("no-indent", "Deprecated, use --prefix=none instead").hide(true)) .arg(flag("prefix-depth", "Deprecated, use --prefix=depth instead").hide(true)) .arg( opt( "prefix", "Change the prefix (indentation) of how each entry is displayed", ) .value_name("PREFIX") .value_parser(["depth", "indent", "none"]) .default_value("indent"), ) .arg(flag( "no-dedupe", "Do not de-duplicate (repeats all shared dependencies)", )) .arg( flag( "duplicates", "Show only dependencies which come in multiple versions (implies -i)", ) .short('d') .alias("duplicate"), ) .arg( opt("charset", "Character set to use in output") .value_name("CHARSET") .value_parser(["utf8", "ascii"]), ) .arg( opt("format", "Format string used for printing dependencies") .value_name("FORMAT") .short('f') .default_value("{p}"), ) .arg( // Backwards compatibility with old cargo-tree. flag("version", "Print version info and exit") .short('V') .hide(true), ) .arg_package_spec_no_all( "Package to be used as the root of the tree", "Display the tree for all packages in the workspace", "Exclude specific workspace members", ) .arg_features() .arg(flag("all-targets", "Deprecated, use --target=all instead").hide(true)) .arg_target_triple( "Filter dependencies matching the given target-triple (default host platform). \ Pass `all` to include all targets.", ) .arg_manifest_path() .arg_lockfile_path() .after_help(color_print::cstr!( "Run `cargo help tree` for more detailed information.\n" )) } #[derive(Copy, Clone)] pub enum Charset { Utf8, Ascii, } impl FromStr for Charset { type Err = &'static str; fn from_str(s: &str) -> Result { match s { "utf8" => Ok(Charset::Utf8), "ascii" => Ok(Charset::Ascii), _ => Err("invalid charset"), } } } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { if args.flag("version") { let verbose = args.verbose() > 0; let version = cli::get_version_string(verbose); cargo::drop_print!(gctx, "{}", version); return Ok(()); } let prefix = if args.flag("no-indent") { gctx.shell() .warn("the --no-indent flag has been changed to --prefix=none")?; "none" } else if args.flag("prefix-depth") { gctx.shell() .warn("the --prefix-depth flag has been changed to --prefix=depth")?; "depth" } else { args.get_one::("prefix").unwrap().as_str() }; let prefix = tree::Prefix::from_str(prefix).map_err(|e| anyhow::anyhow!("{}", e))?; let no_dedupe = args.flag("no-dedupe") || args.flag("all"); if args.flag("all") { gctx.shell().warn( "The `cargo tree` --all flag has been changed to --no-dedupe, \ and may be removed in a future version.\n\ If you are looking to display all workspace members, use the --workspace flag.", )?; } let targets = if args.flag("all-targets") { gctx.shell() .warn("the --all-targets flag has been changed to --target=all")?; vec!["all".to_string()] } else { args.targets()? }; let target = tree::Target::from_cli(targets); let (edge_kinds, no_proc_macro) = parse_edge_kinds(gctx, args)?; let graph_features = edge_kinds.contains(&EdgeKind::Feature); let pkgs_to_prune = args._values_of("prune"); let display_depth = args ._value_of("depth") .map(|s| s.parse::()) .transpose()? .unwrap_or(DisplayDepth::MaxDisplayDepth(u32::MAX)); let packages = args.packages_from_flags()?; let mut invert = args .get_many::("invert") .map_or_else(|| Vec::new(), |is| is.map(|s| s.to_string()).collect()); if args.is_present_with_zero_values("invert") { match &packages { Packages::Packages(ps) => { // Backwards compatibility with old syntax of `cargo tree -i -p foo`. invert.extend(ps.clone()); } _ => { return Err(format_err!( "The `-i` flag requires a package name.\n\ \n\ The `-i` flag is used to inspect the reverse dependencies of a specific\n\ package. It will invert the tree and display the packages that depend on the\n\ given package.\n\ \n\ Note that in a workspace, by default it will only display the package's\n\ reverse dependencies inside the tree of the workspace member in the current\n\ directory. The --workspace flag can be used to extend it so that it will show\n\ the package's reverse dependencies across the entire workspace. The -p flag\n\ can be used to display the package's reverse dependencies only with the\n\ subtree of the package given to -p.\n\ " ) .into()); } } } let ws = args.workspace(gctx)?; if args.is_present_with_zero_values("package") { print_available_packages(&ws)?; } let charset = args.get_one::("charset"); if let Some(charset) = charset .map(|c| Charset::from_str(c)) .transpose() .map_err(|e| anyhow::anyhow!("{}", e))? { match charset { Charset::Utf8 => gctx.shell().set_unicode(true)?, Charset::Ascii => gctx.shell().set_unicode(false)?, } } let opts = tree::TreeOptions { cli_features: args.cli_features()?, packages, target, edge_kinds, invert, pkgs_to_prune, prefix, no_dedupe, duplicates: args.flag("duplicates"), format: args.get_one::("format").cloned().unwrap(), graph_features, display_depth, no_proc_macro, }; if opts.graph_features && opts.duplicates { return Err(format_err!("the `-e features` flag does not support `--duplicates`").into()); } tree::build_and_print(&ws, &opts)?; Ok(()) } /// Parses `--edges` option. /// /// Returns a tuple of `EdgeKind` map and `no_proc_marco` flag. fn parse_edge_kinds( gctx: &GlobalContext, args: &ArgMatches, ) -> CargoResult<(HashSet, bool)> { let (kinds, no_proc_macro) = { let mut no_proc_macro = false; let mut kinds = args.get_many::("edges").map_or_else( || Vec::new(), |es| { es.flat_map(|e| e.split(',')) .filter(|e| { no_proc_macro = *e == "no-proc-macro"; !no_proc_macro }) .collect() }, ); if args.flag("no-dev-dependencies") { gctx.shell() .warn("the --no-dev-dependencies flag has changed to -e=no-dev")?; kinds.push("no-dev"); } if kinds.is_empty() { kinds.extend(&["normal", "build", "dev"]); } (kinds, no_proc_macro) }; let mut result = HashSet::new(); let insert_defaults = |result: &mut HashSet| { result.insert(EdgeKind::Dep(DepKind::Normal)); result.insert(EdgeKind::Dep(DepKind::Build)); result.insert(EdgeKind::Dep(DepKind::Development)); }; let unknown = |k| { bail!( "unknown edge kind `{}`, valid values are \ \"normal\", \"build\", \"dev\", \ \"no-normal\", \"no-build\", \"no-dev\", \"no-proc-macro\", \ \"features\", or \"all\"", k ) }; if kinds.iter().any(|k| k.starts_with("no-")) { insert_defaults(&mut result); for kind in &kinds { match *kind { "no-normal" => result.remove(&EdgeKind::Dep(DepKind::Normal)), "no-build" => result.remove(&EdgeKind::Dep(DepKind::Build)), "no-dev" => result.remove(&EdgeKind::Dep(DepKind::Development)), "features" => result.insert(EdgeKind::Feature), "normal" | "build" | "dev" | "all" => { bail!( "`{}` dependency kind cannot be mixed with \ \"no-normal\", \"no-build\", or \"no-dev\" \ dependency kinds", kind ) } k => return unknown(k), }; } return Ok((result, no_proc_macro)); } for kind in &kinds { match *kind { "all" => { insert_defaults(&mut result); result.insert(EdgeKind::Feature); } "features" => { result.insert(EdgeKind::Feature); } "normal" => { result.insert(EdgeKind::Dep(DepKind::Normal)); } "build" => { result.insert(EdgeKind::Dep(DepKind::Build)); } "dev" => { result.insert(EdgeKind::Dep(DepKind::Development)); } k => return unknown(k), } } if kinds.len() == 1 && kinds[0] == "features" { insert_defaults(&mut result); } Ok((result, no_proc_macro)) } cargo-0.86.0/src/bin/cargo/commands/uninstall.rs000064400000000000000000000041631046102023000176300ustar 00000000000000use crate::command_prelude::*; use cargo::ops; pub fn cli() -> Command { subcommand("uninstall") .about("Remove a Rust binary") .arg( Arg::new("spec") .value_name("SPEC") .num_args(0..) .add::(clap_complete::ArgValueCandidates::new( || get_installed_crates(), )), ) .arg(opt("root", "Directory to uninstall packages from").value_name("DIR")) .arg_silent_suggestion() .arg_package_spec_simple("Package to uninstall") .arg( multi_opt("bin", "NAME", "Only uninstall the binary NAME") .help_heading(heading::TARGET_SELECTION), ) .after_help(color_print::cstr!( "Run `cargo help uninstall` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let root = args.get_one::("root").map(String::as_str); if args.is_present_with_zero_values("package") { return Err(anyhow::anyhow!( "\"--package \" requires a SPEC format value.\n\ Run `cargo help pkgid` for more information about SPEC format." ) .into()); } let specs = args .get_many::("spec") .unwrap_or_else(|| args.get_many::("package").unwrap_or_default()) .map(String::as_str) .collect(); ops::uninstall(root, specs, &values(args, "bin"), gctx)?; Ok(()) } fn get_installed_crates() -> Vec { get_installed_crates_().unwrap_or_default() } fn get_installed_crates_() -> Option> { let mut candidates = Vec::new(); let gctx = GlobalContext::default().ok()?; let root = ops::resolve_root(None, &gctx).ok()?; let tracker = ops::InstallTracker::load(&gctx, &root).ok()?; for (_, v) in tracker.all_installed_bins() { for bin in v { candidates.push(clap_complete::CompletionCandidate::new(bin)); } } Some(candidates) } cargo-0.86.0/src/bin/cargo/commands/update.rs000064400000000000000000000070371046102023000171040ustar 00000000000000use crate::command_prelude::*; use anyhow::anyhow; use cargo::ops::{self, UpdateOptions}; use cargo::util::print_available_packages; pub fn cli() -> Command { subcommand("update") .about("Update dependencies as recorded in the local lock file") .args([clap::Arg::new("package2") .action(clap::ArgAction::Append) .num_args(1..) .value_name("SPEC") .help_heading(heading::PACKAGE_SELECTION) .group("package-group") .help("Package to update") .add(clap_complete::ArgValueCandidates::new( get_pkg_id_spec_candidates, ))]) .arg( optional_multi_opt("package", "SPEC", "Package to update") .short('p') .hide(true) .help_heading(heading::PACKAGE_SELECTION) .group("package-group"), ) .arg_dry_run("Don't actually write the lockfile") .arg( flag( "recursive", "Force updating all dependencies of [SPEC]... as well", ) .alias("aggressive") .conflicts_with("precise"), ) .arg( opt("precise", "Update [SPEC] to exactly PRECISE") .value_name("PRECISE") .requires("package-group"), ) .arg( flag( "breaking", "Update [SPEC] to latest SemVer-breaking version (unstable)", ) .short('b'), ) .arg_silent_suggestion() .arg( flag("workspace", "Only update the workspace packages") .short('w') .help_heading(heading::PACKAGE_SELECTION), ) .arg_manifest_path() .arg_lockfile_path() .arg_ignore_rust_version_with_help("Ignore `rust-version` specification in packages") .after_help(color_print::cstr!( "Run `cargo help update` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let mut ws = args.workspace(gctx)?; if args.is_present_with_zero_values("package") { print_available_packages(&ws)?; } let to_update = if args.contains_id("package") { "package" } else { "package2" }; let to_update = values(args, to_update); for crate_name in to_update.iter() { if let Some(toolchain) = crate_name.strip_prefix("+") { return Err(anyhow!( "invalid character `+` in package name: `+{toolchain}` Use `cargo +{toolchain} update` if you meant to use the `{toolchain}` toolchain." ) .into()); } } let update_opts = UpdateOptions { recursive: args.flag("recursive"), precise: args.get_one::("precise").map(String::as_str), to_update, dry_run: args.dry_run(), workspace: args.flag("workspace"), gctx, }; if args.flag("breaking") { gctx.cli_unstable() .fail_if_stable_opt("--breaking", 12425)?; let upgrades = ops::upgrade_manifests(&mut ws, &update_opts.to_update)?; ops::resolve_ws(&ws, update_opts.dry_run)?; ops::write_manifest_upgrades(&ws, &upgrades, update_opts.dry_run)?; if update_opts.dry_run { update_opts .gctx .shell() .warn("aborting update due to dry run")?; } } else { ops::update_lockfile(&ws, &update_opts)?; } Ok(()) } cargo-0.86.0/src/bin/cargo/commands/vendor.rs000064400000000000000000000062571046102023000171220ustar 00000000000000use crate::command_prelude::*; use cargo::ops; use std::path::PathBuf; pub fn cli() -> Command { subcommand("vendor") .about("Vendor all dependencies for a project locally") .arg( Arg::new("path") .action(ArgAction::Set) .value_parser(clap::value_parser!(PathBuf)) .help("Where to vendor crates (`vendor` by default)"), ) .arg(flag( "no-delete", "Don't delete older crates in the vendor directory", )) .arg( Arg::new("tomls") .short('s') .long("sync") .help("Additional `Cargo.toml` to sync and vendor") .value_name("TOML") .value_parser(clap::value_parser!(PathBuf)) .action(clap::ArgAction::Append), ) .arg(flag( "respect-source-config", "Respect `[source]` config in `.cargo/config`", )) .arg(flag( "versioned-dirs", "Always include version in subdir name", )) .arg(unsupported("no-merge-sources")) .arg(unsupported("relative-path")) .arg(unsupported("only-git-deps")) .arg(unsupported("disallow-duplicates")) .arg_manifest_path() .arg_lockfile_path() .after_help(color_print::cstr!( "Run `cargo help vendor` for more detailed information.\n" )) } fn unsupported(name: &'static str) -> Arg { // When we moved `cargo vendor` into Cargo itself we didn't stabilize a few // flags, so try to provide a helpful error message in that case to ensure // that users currently using the flag aren't tripped up. let value_parser = clap::builder::UnknownArgumentValueParser::suggest("the crates.io `cargo vendor` command has been merged into Cargo") .and_suggest(format!("and the flag `--{name}` isn't supported currently")) .and_suggest("to continue using the flag, execute `cargo-vendor vendor ...`") .and_suggest("to suggest this flag supported in Cargo, file an issue at "); flag(name, "").value_parser(value_parser).hide(true) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { // We're doing the vendoring operation ourselves, so we don't actually want // to respect any of the `source` configuration in Cargo itself. That's // intended for other consumers of Cargo, but we want to go straight to the // source, e.g. crates.io, to fetch crates. if !args.flag("respect-source-config") { gctx.values_mut()?.remove("source"); } let ws = args.workspace(gctx)?; let path = args .get_one::("path") .cloned() .unwrap_or_else(|| PathBuf::from("vendor")); ops::vendor( &ws, &ops::VendorOptions { no_delete: args.flag("no-delete"), destination: &path, versioned_dirs: args.flag("versioned-dirs"), extra: args .get_many::("tomls") .unwrap_or_default() .cloned() .collect(), }, )?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/verify_project.rs000064400000000000000000000013201046102023000206410ustar 00000000000000//! Deprecated. use crate::command_prelude::*; use std::collections::HashMap; use std::process; pub fn cli() -> Command { subcommand("verify-project") .hide(true) .about( "\ DEPRECATED: Check correctness of crate manifest. See https://github.com/rust-lang/cargo/issues/14679.", ) .arg_silent_suggestion() .arg_manifest_path() } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { if let Err(e) = args.workspace(gctx) { gctx.shell() .print_json(&HashMap::from([("invalid", e.to_string())]))?; process::exit(1) } gctx.shell() .print_json(&HashMap::from([("success", "true")]))?; Ok(()) } cargo-0.86.0/src/bin/cargo/commands/version.rs000064400000000000000000000010301046102023000172720ustar 00000000000000use crate::cli; use crate::command_prelude::*; pub fn cli() -> Command { subcommand("version") .about("Show version information") .arg_silent_suggestion() .after_help(color_print::cstr!( "Run `cargo help version` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let verbose = args.verbose() > 0; let version = cli::get_version_string(verbose); cargo::drop_print!(gctx, "{}", version); Ok(()) } cargo-0.86.0/src/bin/cargo/commands/yank.rs000064400000000000000000000040561046102023000165620ustar 00000000000000use crate::command_prelude::*; use cargo::ops; use cargo_credential::Secret; pub fn cli() -> Command { subcommand("yank") .about("Remove a pushed crate from the index") .arg(Arg::new("crate").value_name("CRATE").action(ArgAction::Set)) .arg( opt("version", "The version to yank or un-yank") .alias("vers") .value_name("VERSION"), ) .arg(flag( "undo", "Undo a yank, putting a version back into the index", )) .arg_index("Registry index URL to yank from") .arg_registry("Registry to yank from") .arg(opt("token", "API token to use when authenticating").value_name("TOKEN")) .arg_silent_suggestion() .after_help(color_print::cstr!( "Run `cargo help yank` for more detailed information.\n" )) } pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { let (krate, version) = resolve_crate( args.get_one::("crate").map(String::as_str), args.get_one::("version").map(String::as_str), )?; if version.is_none() { return Err(anyhow::format_err!("`--version` is required").into()); } ops::yank( gctx, krate.map(|s| s.to_string()), version.map(|s| s.to_string()), args.get_one::("token").cloned().map(Secret::from), args.registry_or_index(gctx)?, args.flag("undo"), )?; Ok(()) } fn resolve_crate<'k>( mut krate: Option<&'k str>, mut version: Option<&'k str>, ) -> crate::CargoResult<(Option<&'k str>, Option<&'k str>)> { if let Some((k, v)) = krate.and_then(|k| k.split_once('@')) { if version.is_some() { anyhow::bail!("cannot specify both `@{v}` and `--version`"); } if k.is_empty() { // by convention, arguments starting with `@` are response files anyhow::bail!("missing crate name for `@{v}`"); } krate = Some(k); version = Some(v); } Ok((krate, version)) } cargo-0.86.0/src/bin/cargo/main.rs000064400000000000000000000341741046102023000147470ustar 00000000000000#![allow(clippy::self_named_module_files)] // false positive in `commands/build.rs` use cargo::core::features; use cargo::core::shell::Shell; use cargo::util::network::http::http_handle; use cargo::util::network::http::needs_custom_http_transport; use cargo::util::{self, closest_msg, command_prelude, CargoResult}; use cargo_util::{ProcessBuilder, ProcessError}; use cargo_util_schemas::manifest::StringOrVec; use std::collections::BTreeMap; use std::env; use std::ffi::OsStr; use std::fs; use std::path::{Path, PathBuf}; mod cli; mod commands; use crate::command_prelude::*; fn main() { let _guard = setup_logger(); let mut gctx = match GlobalContext::default() { Ok(gctx) => gctx, Err(e) => { let mut shell = Shell::new(); cargo::exit_with_error(e.into(), &mut shell) } }; let nightly_features_allowed = matches!(&*features::channel(), "nightly" | "dev"); if nightly_features_allowed { let _span = tracing::span!(tracing::Level::TRACE, "completions").entered(); let args = std::env::args_os(); let current_dir = std::env::current_dir().ok(); let completer = clap_complete::CompleteEnv::with_factory(|| { let mut gctx = GlobalContext::default().expect("already loaded without errors"); cli::cli(&mut gctx) }) .var("CARGO_COMPLETE"); if completer .try_complete(args, current_dir.as_deref()) .unwrap_or_else(|e| { let mut shell = Shell::new(); cargo::exit_with_error(e.into(), &mut shell) }) { return; } } let result = if let Some(lock_addr) = cargo::ops::fix_get_proxy_lock_addr() { cargo::ops::fix_exec_rustc(&gctx, &lock_addr).map_err(|e| CliError::from(e)) } else { let _token = cargo::util::job::setup(); cli::main(&mut gctx) }; match result { Err(e) => cargo::exit_with_error(e, &mut *gctx.shell()), Ok(()) => {} } } fn setup_logger() -> Option { use tracing_subscriber::prelude::*; let env = tracing_subscriber::EnvFilter::from_env("CARGO_LOG"); let fmt_layer = tracing_subscriber::fmt::layer() .with_timer(tracing_subscriber::fmt::time::Uptime::default()) .with_ansi(std::io::IsTerminal::is_terminal(&std::io::stderr())) .with_writer(std::io::stderr) .with_filter(env); let (profile_layer, profile_guard) = chrome_layer(); let registry = tracing_subscriber::registry() .with(fmt_layer) .with(profile_layer); registry.init(); tracing::trace!(start = humantime::format_rfc3339(std::time::SystemTime::now()).to_string()); profile_guard } #[cfg(target_has_atomic = "64")] type ChromeFlushGuard = tracing_chrome::FlushGuard; #[cfg(target_has_atomic = "64")] fn chrome_layer() -> ( Option>, Option, ) where S: tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span> + Send + Sync, { #![allow(clippy::disallowed_methods)] if env_to_bool(std::env::var_os("CARGO_LOG_PROFILE").as_deref()) { let capture_args = env_to_bool(std::env::var_os("CARGO_LOG_PROFILE_CAPTURE_ARGS").as_deref()); let (layer, guard) = tracing_chrome::ChromeLayerBuilder::new() .include_args(capture_args) .build(); (Some(layer), Some(guard)) } else { (None, None) } } #[cfg(not(target_has_atomic = "64"))] type ChromeFlushGuard = (); #[cfg(not(target_has_atomic = "64"))] fn chrome_layer() -> ( Option, Option, ) { (None, None) } #[cfg(target_has_atomic = "64")] fn env_to_bool(os: Option<&OsStr>) -> bool { match os.and_then(|os| os.to_str()) { Some("1") | Some("true") => true, _ => false, } } /// Table for defining the aliases which come builtin in `Cargo`. /// The contents are structured as: `(alias, aliased_command, description)`. const BUILTIN_ALIASES: [(&str, &str, &str); 6] = [ ("b", "build", "alias: build"), ("c", "check", "alias: check"), ("d", "doc", "alias: doc"), ("r", "run", "alias: run"), ("t", "test", "alias: test"), ("rm", "remove", "alias: remove"), ]; /// Function which contains the list of all of the builtin aliases and it's /// corresponding execs represented as &str. fn builtin_aliases_execs(cmd: &str) -> Option<&(&str, &str, &str)> { BUILTIN_ALIASES.iter().find(|alias| alias.0 == cmd) } /// Resolve the aliased command from the [`GlobalContext`] with a given command string. /// /// The search fallback chain is: /// /// 1. Get the aliased command as a string. /// 2. If an `Err` occurs (missing key, type mismatch, or any possible error), /// try to get it as an array again. /// 3. If still cannot find any, finds one insides [`BUILTIN_ALIASES`]. fn aliased_command(gctx: &GlobalContext, command: &str) -> CargoResult>> { let alias_name = format!("alias.{}", command); let user_alias = match gctx.get_string(&alias_name) { Ok(Some(record)) => Some( record .val .split_whitespace() .map(|s| s.to_string()) .collect(), ), Ok(None) => None, Err(_) => gctx.get::>>(&alias_name)?, }; let result = user_alias.or_else(|| { builtin_aliases_execs(command).map(|command_str| vec![command_str.1.to_string()]) }); if result .as_ref() .map(|alias| alias.is_empty()) .unwrap_or_default() { anyhow::bail!("subcommand is required, but `{alias_name}` is empty"); } Ok(result) } /// List all runnable commands fn list_commands(gctx: &GlobalContext) -> BTreeMap { let prefix = "cargo-"; let suffix = env::consts::EXE_SUFFIX; let mut commands = BTreeMap::new(); for dir in search_directories(gctx) { let entries = match fs::read_dir(dir) { Ok(entries) => entries, _ => continue, }; for entry in entries.filter_map(|e| e.ok()) { let path = entry.path(); let Some(filename) = path.file_name().and_then(|s| s.to_str()) else { continue; }; let Some(name) = filename .strip_prefix(prefix) .and_then(|s| s.strip_suffix(suffix)) else { continue; }; if is_executable(entry.path()) { commands.insert( name.to_string(), CommandInfo::External { path: path.clone() }, ); } } } for cmd in commands::builtin() { commands.insert( cmd.get_name().to_string(), CommandInfo::BuiltIn { about: cmd.get_about().map(|s| s.to_string()), }, ); } // Add the builtin_aliases and them descriptions to the // `commands` `BTreeMap`. for command in &BUILTIN_ALIASES { commands.insert( command.0.to_string(), CommandInfo::BuiltIn { about: Some(command.2.to_string()), }, ); } // Add the user-defined aliases if let Ok(aliases) = gctx.get::>("alias") { for (name, target) in aliases.iter() { commands.insert( name.to_string(), CommandInfo::Alias { target: target.clone(), }, ); } } // `help` is special, so it needs to be inserted separately. commands.insert( "help".to_string(), CommandInfo::BuiltIn { about: Some("Displays help for a cargo subcommand".to_string()), }, ); commands } fn find_external_subcommand(gctx: &GlobalContext, cmd: &str) -> Option { let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX); search_directories(gctx) .iter() .map(|dir| dir.join(&command_exe)) .find(|file| is_executable(file)) } fn execute_external_subcommand(gctx: &GlobalContext, cmd: &str, args: &[&OsStr]) -> CliResult { let path = find_external_subcommand(gctx, cmd); let command = match path { Some(command) => command, None => { let script_suggestion = if gctx.cli_unstable().script && std::path::Path::new(cmd).is_file() { let sep = std::path::MAIN_SEPARATOR; format!("\n\tTo run the file `{cmd}`, provide a relative path like `.{sep}{cmd}`") } else { "".to_owned() }; let err = if cmd.starts_with('+') { anyhow::format_err!( "no such command: `{cmd}`\n\n\t\ Cargo does not handle `+toolchain` directives.\n\t\ Did you mean to invoke `cargo` through `rustup` instead?{script_suggestion}", ) } else { let suggestions = list_commands(gctx); let did_you_mean = closest_msg(cmd, suggestions.keys(), |c| c); anyhow::format_err!( "no such command: `{cmd}`{did_you_mean}\n\n\t\ View all installed commands with `cargo --list`\n\t\ Find a package to install `{cmd}` with `cargo search cargo-{cmd}`{script_suggestion}", ) }; return Err(CliError::new(err, 101)); } }; execute_subcommand(gctx, Some(&command), args) } fn execute_internal_subcommand(gctx: &GlobalContext, args: &[&OsStr]) -> CliResult { execute_subcommand(gctx, None, args) } // This function is used to execute a subcommand. It is used to execute both // internal and external subcommands. // If `cmd_path` is `None`, then the subcommand is an internal subcommand. fn execute_subcommand( gctx: &GlobalContext, cmd_path: Option<&PathBuf>, args: &[&OsStr], ) -> CliResult { let cargo_exe = gctx.cargo_exe()?; let mut cmd = match cmd_path { Some(cmd_path) => ProcessBuilder::new(cmd_path), None => ProcessBuilder::new(&cargo_exe), }; cmd.env(cargo::CARGO_ENV, cargo_exe).args(args); if let Some(client) = gctx.jobserver_from_env() { cmd.inherit_jobserver(client); } let err = match cmd.exec_replace() { Ok(()) => return Ok(()), Err(e) => e, }; if let Some(perr) = err.downcast_ref::() { if let Some(code) = perr.code { return Err(CliError::code(code)); } } Err(CliError::new(err, 101)) } #[cfg(unix)] fn is_executable>(path: P) -> bool { use std::os::unix::prelude::*; fs::metadata(path) .map(|metadata| metadata.is_file() && metadata.permissions().mode() & 0o111 != 0) .unwrap_or(false) } #[cfg(windows)] fn is_executable>(path: P) -> bool { path.as_ref().is_file() } fn search_directories(gctx: &GlobalContext) -> Vec { let mut path_dirs = if let Some(val) = gctx.get_env_os("PATH") { env::split_paths(&val).collect() } else { vec![] }; let home_bin = gctx.home().clone().into_path_unlocked().join("bin"); // If any of that PATH elements contains `home_bin`, do not // add it again. This is so that the users can control priority // of it using PATH, while preserving the historical // behavior of preferring it over system global directories even // when not in PATH at all. // See https://github.com/rust-lang/cargo/issues/11020 for details. // // Note: `p == home_bin` will ignore trailing slash, but we don't // `canonicalize` the paths. if !path_dirs.iter().any(|p| p == &home_bin) { path_dirs.insert(0, home_bin); }; path_dirs } /// Initialize libgit2. #[tracing::instrument(skip_all)] fn init_git(gctx: &GlobalContext) { // Disabling the owner validation in git can, in theory, lead to code execution // vulnerabilities. However, libgit2 does not launch executables, which is the foundation of // the original security issue. Meanwhile, issues with refusing to load git repos in // `CARGO_HOME` for example will likely be very frustrating for users. So, we disable the // validation. // // For further discussion of Cargo's current interactions with git, see // // https://github.com/rust-lang/rfcs/pull/3279 // // and in particular the subsection on "Git support". // // Note that we only disable this when Cargo is run as a binary. If Cargo is used as a library, // this code won't be invoked. Instead, developers will need to explicitly disable the // validation in their code. This is inconvenient, but won't accidentally open consuming // applications up to security issues if they use git2 to open repositories elsewhere in their // code. unsafe { git2::opts::set_verify_owner_validation(false) .expect("set_verify_owner_validation should never fail"); } init_git_transports(gctx); } /// Configure libgit2 to use libcurl if necessary. /// /// If the user has a non-default network configuration, then libgit2 will be /// configured to use libcurl instead of the built-in networking support so /// that those configuration settings can be used. #[tracing::instrument(skip_all)] fn init_git_transports(gctx: &GlobalContext) { match needs_custom_http_transport(gctx) { Ok(true) => {} _ => return, } let handle = match http_handle(gctx) { Ok(handle) => handle, Err(..) => return, }; // The unsafety of the registration function derives from two aspects: // // 1. This call must be synchronized with all other registration calls as // well as construction of new transports. // 2. The argument is leaked. // // We're clear on point (1) because this is only called at the start of this // binary (we know what the state of the world looks like) and we're mostly // clear on point (2) because we'd only free it after everything is done // anyway unsafe { git2_curl::register(handle); } } cargo-0.86.0/src/cargo/core/compiler/artifact.rs000064400000000000000000000124151046102023000176040ustar 00000000000000//! Generate artifact information from unit dependencies for configuring the compiler environment. use crate::core::compiler::unit_graph::UnitDep; use crate::core::compiler::{BuildRunner, CrateType, FileFlavor, Unit}; use crate::core::dependency::ArtifactKind; use crate::core::{Dependency, Target, TargetKind}; use crate::CargoResult; use std::collections::{HashMap, HashSet}; use std::ffi::OsString; /// Return all environment variables for the given unit-dependencies /// if artifacts are present. pub fn get_env( build_runner: &BuildRunner<'_, '_>, dependencies: &[UnitDep], ) -> CargoResult> { let mut env = HashMap::new(); for unit_dep in dependencies.iter().filter(|d| d.unit.artifact.is_true()) { for artifact_path in build_runner .outputs(&unit_dep.unit)? .iter() .filter_map(|f| (f.flavor == FileFlavor::Normal).then(|| &f.path)) { let artifact_type_upper = unit_artifact_type_name_upper(&unit_dep.unit); let dep_name = unit_dep.dep_name.unwrap_or(unit_dep.unit.pkg.name()); let dep_name_upper = dep_name.to_uppercase().replace("-", "_"); let var = format!("CARGO_{}_DIR_{}", artifact_type_upper, dep_name_upper); let path = artifact_path.parent().expect("parent dir for artifacts"); env.insert(var, path.to_owned().into()); let var_file = format!( "CARGO_{}_FILE_{}_{}", artifact_type_upper, dep_name_upper, unit_dep.unit.target.name() ); // In older releases, lib-targets defaulted to the name of the package. Newer releases // use the same name as default, but with dashes replaced. Hence, if the name of the // target was inferred by Cargo, we also set the env-var with the unconverted name for // backwards compatibility. let need_compat = unit_dep.unit.target.is_lib() && unit_dep.unit.target.name_inferred(); if need_compat { let var_compat = format!( "CARGO_{}_FILE_{}_{}", artifact_type_upper, dep_name_upper, unit_dep.unit.pkg.name(), ); if var_compat != var_file { env.insert(var_compat, artifact_path.to_owned().into()); } } env.insert(var_file, artifact_path.to_owned().into()); // If the name of the target matches the name of the dependency, we strip the // repetition and provide the simpler env-var as well. // For backwards-compatibility of inferred names, we compare against the name of the // package as well, since that used to be the default for library targets. if unit_dep.unit.target.name() == dep_name.as_str() || (need_compat && unit_dep.unit.pkg.name() == dep_name.as_str()) { let var = format!("CARGO_{}_FILE_{}", artifact_type_upper, dep_name_upper,); env.insert(var, artifact_path.to_owned().into()); } } } Ok(env) } fn unit_artifact_type_name_upper(unit: &Unit) -> &'static str { match unit.target.kind() { TargetKind::Lib(kinds) => match kinds.as_slice() { &[CrateType::Cdylib] => "CDYLIB", &[CrateType::Staticlib] => "STATICLIB", invalid => unreachable!("BUG: artifacts cannot be of type {:?}", invalid), }, TargetKind::Bin => "BIN", invalid => unreachable!("BUG: artifacts cannot be of type {:?}", invalid), } } /// Given a dependency with an artifact `artifact_dep` and a set of available `targets` /// of its package, find a target for each kind of artifacts that are to be built. /// /// Failure to match any target results in an error mentioning the parent manifests /// `parent_package` name. pub(crate) fn match_artifacts_kind_with_targets<'t, 'd>( artifact_dep: &'d Dependency, targets: &'t [Target], parent_package: &str, ) -> CargoResult> { let mut out = HashSet::new(); let artifact_requirements = artifact_dep.artifact().expect("artifact present"); for artifact_kind in artifact_requirements.kinds() { let mut extend = |kind, filter: &dyn Fn(&&Target) -> bool| { let mut iter = targets.iter().filter(filter).peekable(); let found = iter.peek().is_some(); out.extend(std::iter::repeat(kind).zip(iter)); found }; let found = match artifact_kind { ArtifactKind::Cdylib => extend(artifact_kind, &|t| t.is_cdylib()), ArtifactKind::Staticlib => extend(artifact_kind, &|t| t.is_staticlib()), ArtifactKind::AllBinaries => extend(artifact_kind, &|t| t.is_bin()), ArtifactKind::SelectedBinary(bin_name) => extend(artifact_kind, &|t| { t.is_bin() && t.name() == bin_name.as_str() }), }; if !found { anyhow::bail!( "dependency `{}` in package `{}` requires a `{}` artifact to be present.", artifact_dep.name_in_toml(), parent_package, artifact_kind ); } } Ok(out) } cargo-0.86.0/src/cargo/core/compiler/build_config.rs000064400000000000000000000232001046102023000204250ustar 00000000000000use crate::core::compiler::CompileKind; use crate::util::context::JobsConfig; use crate::util::interning::InternedString; use crate::util::{CargoResult, GlobalContext, RustfixDiagnosticServer}; use anyhow::{bail, Context as _}; use cargo_util::ProcessBuilder; use serde::ser; use std::cell::RefCell; use std::path::PathBuf; use std::rc::Rc; use std::thread::available_parallelism; /// Configuration information for a rustc build. #[derive(Debug, Clone)] pub struct BuildConfig { /// The requested kind of compilation for this session pub requested_kinds: Vec, /// Number of rustc jobs to run in parallel. pub jobs: u32, /// Do not abort the build as soon as there is an error. pub keep_going: bool, /// Build profile pub requested_profile: InternedString, /// The mode we are compiling in. pub mode: CompileMode, /// `true` to print stdout in JSON format (for machine reading). pub message_format: MessageFormat, /// Force Cargo to do a full rebuild and treat each target as changed. pub force_rebuild: bool, /// Output a build plan to stdout instead of actually compiling. pub build_plan: bool, /// Output the unit graph to stdout instead of actually compiling. pub unit_graph: bool, /// `true` to avoid really compiling. pub dry_run: bool, /// An optional override of the rustc process for primary units pub primary_unit_rustc: Option, /// A thread used by `cargo fix` to receive messages on a socket regarding /// the success/failure of applying fixes. pub rustfix_diagnostic_server: Rc>>, /// The directory to copy final artifacts to. Note that even if /// `artifact-dir` is set, a copy of artifacts still can be found at /// `target/(debug\release)` as usual. /// Named `export_dir` to avoid confusion with /// `CompilationFiles::artifact_dir`. pub export_dir: Option, /// `true` to output a future incompatibility report at the end of the build pub future_incompat_report: bool, /// Which kinds of build timings to output (empty if none). pub timing_outputs: Vec, } fn default_parallelism() -> CargoResult { Ok(available_parallelism() .context("failed to determine the amount of parallelism available")? .get() as u32) } impl BuildConfig { /// Parses all config files to learn about build configuration. Currently /// configured options are: /// /// * `build.jobs` /// * `build.target` /// * `target.$target.ar` /// * `target.$target.linker` /// * `target.$target.libfoo.metadata` pub fn new( gctx: &GlobalContext, jobs: Option, keep_going: bool, requested_targets: &[String], mode: CompileMode, ) -> CargoResult { let cfg = gctx.build_config()?; let requested_kinds = CompileKind::from_requested_targets(gctx, requested_targets)?; if jobs.is_some() && gctx.jobserver_from_env().is_some() { gctx.shell().warn( "a `-j` argument was passed to Cargo but Cargo is \ also configured with an external jobserver in \ its environment, ignoring the `-j` parameter", )?; } let jobs = match jobs.or(cfg.jobs.clone()) { None => default_parallelism()?, 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.")) } }, }, }; Ok(BuildConfig { requested_kinds, jobs, keep_going, requested_profile: InternedString::new("dev"), mode, message_format: MessageFormat::Human, force_rebuild: false, build_plan: false, unit_graph: false, dry_run: false, primary_unit_rustc: None, rustfix_diagnostic_server: Rc::new(RefCell::new(None)), export_dir: None, future_incompat_report: false, timing_outputs: Vec::new(), }) } /// Whether or not the *user* wants JSON output. Whether or not rustc /// actually uses JSON is decided in `add_error_format`. pub fn emit_json(&self) -> bool { matches!(self.message_format, MessageFormat::Json { .. }) } pub fn test(&self) -> bool { self.mode == CompileMode::Test || self.mode == CompileMode::Bench } pub fn single_requested_kind(&self) -> CargoResult { match self.requested_kinds.len() { 1 => Ok(self.requested_kinds[0]), _ => bail!("only one `--target` argument is supported"), } } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum MessageFormat { Human, Json { /// Whether rustc diagnostics are rendered by cargo or included into the /// output stream. render_diagnostics: bool, /// Whether the `rendered` field of rustc diagnostics are using the /// "short" rendering. short: bool, /// Whether the `rendered` field of rustc diagnostics embed ansi color /// codes. ansi: bool, }, Short, } /// The general "mode" for what to do. /// /// This is used for two purposes. The commands themselves pass this in to /// `compile_ws` to tell it the general execution strategy. This influences /// the default targets selected. The other use is in the `Unit` struct /// to indicate what is being done with a specific target. #[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)] pub enum CompileMode { /// A target being built for a test. Test, /// Building a target with `rustc` (lib or bin). Build, /// Building a target with `rustc` to emit `rmeta` metadata only. If /// `test` is true, then it is also compiled with `--test` to check it like /// a test. Check { test: bool }, /// Used to indicate benchmarks should be built. This is not used in /// `Unit`, because it is essentially the same as `Test` (indicating /// `--test` should be passed to rustc) and by using `Test` instead it /// allows some de-duping of Units to occur. Bench, /// A target that will be documented with `rustdoc`. /// If `deps` is true, then it will also document all dependencies. /// if `json` is true, the documentation output is in json format. Doc { deps: bool, json: bool }, /// A target that will be tested with `rustdoc`. Doctest, /// An example or library that will be scraped for function calls by `rustdoc`. Docscrape, /// A marker for Units that represent the execution of a `build.rs` script. RunCustomBuild, } impl ser::Serialize for CompileMode { fn serialize(&self, s: S) -> Result where S: ser::Serializer, { use self::CompileMode::*; match *self { Test => "test".serialize(s), Build => "build".serialize(s), Check { .. } => "check".serialize(s), Bench => "bench".serialize(s), Doc { .. } => "doc".serialize(s), Doctest => "doctest".serialize(s), Docscrape => "docscrape".serialize(s), RunCustomBuild => "run-custom-build".serialize(s), } } } impl CompileMode { /// Returns `true` if the unit is being checked. pub fn is_check(self) -> bool { matches!(self, CompileMode::Check { .. }) } /// Returns `true` if this is generating documentation. pub fn is_doc(self) -> bool { matches!(self, CompileMode::Doc { .. }) } /// Returns `true` if this a doc test. pub fn is_doc_test(self) -> bool { self == CompileMode::Doctest } /// Returns `true` if this is scraping examples for documentation. pub fn is_doc_scrape(self) -> bool { self == CompileMode::Docscrape } /// Returns `true` if this is any type of test (test, benchmark, doc test, or /// check test). pub fn is_any_test(self) -> bool { matches!( self, CompileMode::Test | CompileMode::Bench | CompileMode::Check { test: true } | CompileMode::Doctest ) } /// Returns `true` if this is something that passes `--test` to rustc. pub fn is_rustc_test(self) -> bool { matches!( self, CompileMode::Test | CompileMode::Bench | CompileMode::Check { test: true } ) } /// Returns `true` if this is the *execution* of a `build.rs` script. pub fn is_run_custom_build(self) -> bool { self == CompileMode::RunCustomBuild } /// Returns `true` if this mode may generate an executable. /// /// Note that this also returns `true` for building libraries, so you also /// have to check the target. pub fn generates_executable(self) -> bool { matches!( self, CompileMode::Test | CompileMode::Bench | CompileMode::Build ) } } /// Kinds of build timings we can output. #[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)] pub enum TimingOutput { /// Human-readable HTML report Html, /// Machine-readable JSON (unstable) Json, } cargo-0.86.0/src/cargo/core/compiler/build_context/mod.rs000064400000000000000000000112411046102023000214250ustar 00000000000000//! [`BuildContext`] is a (mostly) static information about a build task. use crate::core::compiler::unit_graph::UnitGraph; use crate::core::compiler::{BuildConfig, CompileKind, Unit}; use crate::core::profiles::Profiles; use crate::core::PackageSet; use crate::core::Workspace; use crate::util::context::GlobalContext; use crate::util::errors::CargoResult; use crate::util::interning::InternedString; use crate::util::Rustc; use std::collections::{HashMap, HashSet}; mod target_info; pub use self::target_info::{ FileFlavor, FileType, RustDocFingerprint, RustcTargetData, TargetInfo, }; /// The build context, containing complete information needed for a build task /// before it gets started. /// /// It is intended that this is mostly static information. Stuff that mutates /// during the build can be found in the parent [`BuildRunner`]. (I say mostly, /// because this has internal caching, but nothing that should be observable /// or require &mut.) /// /// As a result, almost every field on `BuildContext` is public, including /// /// * a resolved [`UnitGraph`] of your dependencies, /// * a [`Profiles`] containing compiler flags presets, /// * a [`RustcTargetData`] containing host and target platform information, /// * and a [`PackageSet`] for further package downloads, /// /// just to name a few. Learn more on each own documentation. /// /// # How to use /// /// To prepare a build task, you may not want to use [`BuildContext::new`] directly, /// since it is often too lower-level. /// Instead, [`ops::create_bcx`] is usually what you are looking for. /// /// After a `BuildContext` is built, the next stage of building is handled in [`BuildRunner`]. /// /// [`BuildRunner`]: crate::core::compiler::BuildRunner /// [`ops::create_bcx`]: crate::ops::create_bcx pub struct BuildContext<'a, 'gctx> { /// The workspace the build is for. pub ws: &'a Workspace<'gctx>, /// The cargo context. pub gctx: &'gctx GlobalContext, /// This contains a collection of compiler flags presets. pub profiles: Profiles, /// Configuration information for a rustc build. pub build_config: &'a BuildConfig, /// Extra compiler args for either `rustc` or `rustdoc`. pub extra_compiler_args: HashMap>, /// Package downloader. /// /// This holds ownership of the `Package` objects. pub packages: PackageSet<'gctx>, /// Information about rustc and the target platform. pub target_data: RustcTargetData<'gctx>, /// The root units of `unit_graph` (units requested on the command-line). pub roots: Vec, /// The dependency graph of units to compile. pub unit_graph: UnitGraph, /// Reverse-dependencies of documented units, used by the `rustdoc --scrape-examples` flag. pub scrape_units: Vec, /// The list of all kinds that are involved in this build pub all_kinds: HashSet, } impl<'a, 'gctx> BuildContext<'a, 'gctx> { pub fn new( ws: &'a Workspace<'gctx>, packages: PackageSet<'gctx>, build_config: &'a BuildConfig, profiles: Profiles, extra_compiler_args: HashMap>, target_data: RustcTargetData<'gctx>, roots: Vec, unit_graph: UnitGraph, scrape_units: Vec, ) -> CargoResult> { let all_kinds = unit_graph .keys() .map(|u| u.kind) .chain(build_config.requested_kinds.iter().copied()) .chain(std::iter::once(CompileKind::Host)) .collect(); Ok(BuildContext { ws, gctx: ws.gctx(), packages, build_config, profiles, extra_compiler_args, target_data, roots, unit_graph, scrape_units, all_kinds, }) } /// Information of the `rustc` this build task will use. pub fn rustc(&self) -> &Rustc { &self.target_data.rustc } /// Gets the host architecture triple. /// /// For example, `x86_64-unknown-linux-gnu`, would be /// - machine: `x86_64`, /// - hardware-platform: `unknown`, /// - operating system: `linux-gnu`. pub fn host_triple(&self) -> InternedString { self.target_data.rustc.host } /// Gets the number of jobs specified for this build. pub fn jobs(&self) -> u32 { self.build_config.jobs } /// Extra compiler args for either `rustc` or `rustdoc`. /// /// As of now, these flags come from the trailing args of either /// `cargo rustc` or `cargo rustdoc`. pub fn extra_args_for(&self, unit: &Unit) -> Option<&Vec> { self.extra_compiler_args.get(unit) } } cargo-0.86.0/src/cargo/core/compiler/build_context/target_info.rs000064400000000000000000001324351046102023000231600ustar 00000000000000//! This modules contains types storing information of target platforms. //! //! Normally, call [`RustcTargetData::new`] to construct all the target //! platform once, and then query info on your demand. For example, //! //! * [`RustcTargetData::dep_platform_activated`] to check if platform is activated. //! * [`RustcTargetData::info`] to get a [`TargetInfo`] for an in-depth query. //! * [`TargetInfo::rustc_outputs`] to get a list of supported file types. use crate::core::compiler::apply_env_config; use crate::core::compiler::{BuildRunner, CompileKind, CompileMode, CompileTarget, CrateType}; use crate::core::{Dependency, Package, Target, TargetKind, Workspace}; use crate::util::context::{GlobalContext, StringList, TargetConfig}; use crate::util::interning::InternedString; use crate::util::{CargoResult, Rustc}; use anyhow::Context as _; use cargo_platform::{Cfg, CfgExpr}; use cargo_util::{paths, ProcessBuilder}; use serde::{Deserialize, Serialize}; use std::cell::RefCell; use std::collections::hash_map::{Entry, HashMap}; use std::path::{Path, PathBuf}; use std::rc::Rc; use std::str::{self, FromStr}; /// Information about the platform target gleaned from querying rustc. /// /// [`RustcTargetData`] keeps several of these, one for the host and the others /// for other specified targets. If no target is specified, it uses a clone from /// the host. #[derive(Clone)] pub struct TargetInfo { /// A base process builder for discovering crate type information. In /// particular, this is used to determine the output filename prefix and /// suffix for a crate type. crate_type_process: ProcessBuilder, /// Cache of output filename prefixes and suffixes. /// /// The key is the crate type name (like `cdylib`) and the value is /// `Some((prefix, suffix))`, for example `libcargo.so` would be /// `Some(("lib", ".so"))`. The value is `None` if the crate type is not /// supported. crate_types: RefCell>>, /// `cfg` information extracted from `rustc --print=cfg`. cfg: Vec, /// `supports_std` information extracted from `rustc --print=target-spec-json` pub supports_std: Option, /// Supported values for `-Csplit-debuginfo=` flag, queried from rustc support_split_debuginfo: Vec, /// Path to the sysroot. pub sysroot: PathBuf, /// Path to the "lib" directory in the sysroot which rustc uses for linking /// target libraries. pub sysroot_target_libdir: PathBuf, /// Extra flags to pass to `rustc`, see [`extra_args`]. pub rustflags: Rc<[String]>, /// Extra flags to pass to `rustdoc`, see [`extra_args`]. pub rustdocflags: Rc<[String]>, } /// Kind of each file generated by a Unit, part of `FileType`. #[derive(Clone, PartialEq, Eq, Debug)] pub enum FileFlavor { /// Not a special file type. Normal, /// Like `Normal`, but not directly executable. /// For example, a `.wasm` file paired with the "normal" `.js` file. Auxiliary, /// Something you can link against (e.g., a library). Linkable, /// An `.rmeta` Rust metadata file. Rmeta, /// Piece of external debug information (e.g., `.dSYM`/`.pdb` file). DebugInfo, } /// Type of each file generated by a Unit. #[derive(Debug)] pub struct FileType { /// The kind of file. pub flavor: FileFlavor, /// The crate-type that generates this file. /// /// `None` for things that aren't associated with a specific crate type, /// for example `rmeta` files. pub crate_type: Option, /// The suffix for the file (for example, `.rlib`). /// This is an empty string for executables on Unix-like platforms. suffix: String, /// The prefix for the file (for example, `lib`). /// This is an empty string for things like executables. prefix: String, /// Flag to convert hyphen to underscore when uplifting. should_replace_hyphens: bool, } impl FileType { /// The filename for this `FileType` crated by rustc. pub fn output_filename(&self, target: &Target, metadata: Option<&str>) -> String { match metadata { Some(metadata) => format!( "{}{}-{}{}", self.prefix, target.crate_name(), metadata, self.suffix ), None => format!("{}{}{}", self.prefix, target.crate_name(), self.suffix), } } /// The filename for this `FileType` that Cargo should use when "uplifting" /// it to the destination directory. pub fn uplift_filename(&self, target: &Target) -> String { let name = match target.binary_filename() { Some(name) => name, None => { // For binary crate type, `should_replace_hyphens` will always be false. if self.should_replace_hyphens { target.crate_name() } else { target.name().to_string() } } }; format!("{}{}{}", self.prefix, name, self.suffix) } /// Creates a new instance representing a `.rmeta` file. pub fn new_rmeta() -> FileType { // Note that even binaries use the `lib` prefix. FileType { flavor: FileFlavor::Rmeta, crate_type: None, suffix: ".rmeta".to_string(), prefix: "lib".to_string(), should_replace_hyphens: true, } } } impl TargetInfo { /// Learns the information of target platform from `rustc` invocation(s). /// /// Generally, the first time calling this function is expensive, as it may /// query `rustc` several times. To reduce the cost, output of each `rustc` /// invocation is cached by [`Rustc::cached_output`]. /// /// Search `Tricky` to learn why querying `rustc` several times is needed. #[tracing::instrument(skip_all)] pub fn new( gctx: &GlobalContext, requested_kinds: &[CompileKind], rustc: &Rustc, kind: CompileKind, ) -> CargoResult { let mut rustflags = extra_args(gctx, requested_kinds, &rustc.host, None, kind, Flags::Rust)?; let mut turn = 0; loop { let extra_fingerprint = kind.fingerprint_hash(); // Query rustc for several kinds of info from each line of output: // 0) file-names (to determine output file prefix/suffix for given crate type) // 1) sysroot // 2) split-debuginfo // 3) cfg // // Search `--print` to see what we query so far. let mut process = rustc.workspace_process(); apply_env_config(gctx, &mut process)?; process .arg("-") .arg("--crate-name") .arg("___") .arg("--print=file-names") .args(&rustflags) .env_remove("RUSTC_LOG"); // Removes `FD_CLOEXEC` set by `jobserver::Client` to pass jobserver // as environment variables specify. if let Some(client) = gctx.jobserver_from_env() { process.inherit_jobserver(client); } if let CompileKind::Target(target) = kind { process.arg("--target").arg(target.rustc_target()); } let crate_type_process = process.clone(); const KNOWN_CRATE_TYPES: &[CrateType] = &[ CrateType::Bin, CrateType::Rlib, CrateType::Dylib, CrateType::Cdylib, CrateType::Staticlib, CrateType::ProcMacro, ]; for crate_type in KNOWN_CRATE_TYPES.iter() { process.arg("--crate-type").arg(crate_type.as_str()); } process.arg("--print=sysroot"); process.arg("--print=split-debuginfo"); process.arg("--print=crate-name"); // `___` as a delimiter. process.arg("--print=cfg"); let (output, error) = rustc .cached_output(&process, extra_fingerprint) .with_context(|| { "failed to run `rustc` to learn about target-specific information" })?; let mut lines = output.lines(); let mut map = HashMap::new(); for crate_type in KNOWN_CRATE_TYPES { let out = parse_crate_type(crate_type, &process, &output, &error, &mut lines)?; map.insert(crate_type.clone(), out); } let Some(line) = lines.next() else { return error_missing_print_output("sysroot", &process, &output, &error); }; let sysroot = PathBuf::from(line); let sysroot_target_libdir = { let mut libdir = sysroot.clone(); libdir.push("lib"); libdir.push("rustlib"); libdir.push(match &kind { CompileKind::Host => rustc.host.as_str(), CompileKind::Target(target) => target.short_name(), }); libdir.push("lib"); libdir }; let support_split_debuginfo = { // HACK: abuse `--print=crate-name` to use `___` as a delimiter. let mut res = Vec::new(); loop { match lines.next() { Some(line) if line == "___" => break, Some(line) => res.push(line.into()), None => { return error_missing_print_output( "split-debuginfo", &process, &output, &error, ) } } } res }; let cfg = lines .map(|line| Ok(Cfg::from_str(line)?)) .filter(TargetInfo::not_user_specific_cfg) .collect::>>() .with_context(|| { format!( "failed to parse the cfg from `rustc --print=cfg`, got:\n{}", output ) })?; // recalculate `rustflags` from above now that we have `cfg` // information let new_flags = extra_args( gctx, requested_kinds, &rustc.host, Some(&cfg), kind, Flags::Rust, )?; // Tricky: `RUSTFLAGS` defines the set of active `cfg` flags, active // `cfg` flags define which `.cargo/config` sections apply, and they // in turn can affect `RUSTFLAGS`! This is a bona fide mutual // dependency, and it can even diverge (see `cfg_paradox` test). // // So what we do here is running at most *two* iterations of // fixed-point iteration, which should be enough to cover // practically useful cases, and warn if that's not enough for // convergence. let reached_fixed_point = new_flags == rustflags; if !reached_fixed_point && turn == 0 { turn += 1; rustflags = new_flags; continue; } if !reached_fixed_point { gctx.shell().warn("non-trivial mutual dependency between target-specific configuration and RUSTFLAGS")?; } let mut supports_std: Option = None; // The '--print=target-spec-json' is an unstable option of rustc, therefore only // try to fetch this information if rustc allows nightly features. Additionally, // to avoid making two rustc queries when not required, only try to fetch the // target-spec when the '-Zbuild-std' option is passed. if gctx.cli_unstable().build_std.is_some() { let mut target_spec_process = rustc.workspace_process(); apply_env_config(gctx, &mut target_spec_process)?; target_spec_process .arg("--print=target-spec-json") .arg("-Zunstable-options") .args(&rustflags) .env_remove("RUSTC_LOG"); if let CompileKind::Target(target) = kind { target_spec_process .arg("--target") .arg(target.rustc_target()); } #[derive(Deserialize)] struct Metadata { pub std: Option, } #[derive(Deserialize)] struct TargetSpec { pub metadata: Metadata, } if let Ok(output) = target_spec_process.output() { if let Ok(spec) = serde_json::from_slice::(&output.stdout) { supports_std = spec.metadata.std; } } } return Ok(TargetInfo { crate_type_process, crate_types: RefCell::new(map), sysroot, sysroot_target_libdir, rustflags: rustflags.into(), rustdocflags: extra_args( gctx, requested_kinds, &rustc.host, Some(&cfg), kind, Flags::Rustdoc, )? .into(), cfg, supports_std, support_split_debuginfo, }); } } fn not_user_specific_cfg(cfg: &CargoResult) -> bool { if let Ok(Cfg::Name(cfg_name)) = cfg { // This should also include "debug_assertions", but it causes // regressions. Maybe some day in the distant future it can be // added (and possibly change the warning to an error). if cfg_name == "proc_macro" { return false; } } true } /// All the target [`Cfg`] settings. pub fn cfg(&self) -> &[Cfg] { &self.cfg } /// Returns the list of file types generated by the given crate type. /// /// Returns `None` if the target does not support the given crate type. fn file_types( &self, crate_type: &CrateType, flavor: FileFlavor, target_triple: &str, ) -> CargoResult>> { let crate_type = if *crate_type == CrateType::Lib { CrateType::Rlib } else { crate_type.clone() }; let mut crate_types = self.crate_types.borrow_mut(); let entry = crate_types.entry(crate_type.clone()); let crate_type_info = match entry { Entry::Occupied(o) => &*o.into_mut(), Entry::Vacant(v) => { let value = self.discover_crate_type(v.key())?; &*v.insert(value) } }; let Some((prefix, suffix)) = crate_type_info else { return Ok(None); }; let mut ret = vec![FileType { suffix: suffix.clone(), prefix: prefix.clone(), flavor, crate_type: Some(crate_type.clone()), should_replace_hyphens: crate_type != CrateType::Bin, }]; // Window shared library import/export files. if crate_type.is_dynamic() { // Note: Custom JSON specs can alter the suffix. For now, we'll // just ignore non-DLL suffixes. if target_triple.ends_with("-windows-msvc") && suffix == ".dll" { // See https://docs.microsoft.com/en-us/cpp/build/reference/working-with-import-libraries-and-export-files // for more information about DLL import/export files. ret.push(FileType { suffix: ".dll.lib".to_string(), prefix: prefix.clone(), flavor: FileFlavor::Auxiliary, crate_type: Some(crate_type.clone()), should_replace_hyphens: true, }); // NOTE: lld does not produce these ret.push(FileType { suffix: ".dll.exp".to_string(), prefix: prefix.clone(), flavor: FileFlavor::Auxiliary, crate_type: Some(crate_type.clone()), should_replace_hyphens: true, }); } else if suffix == ".dll" && (target_triple.ends_with("windows-gnu") || target_triple.ends_with("windows-gnullvm")) { // See https://cygwin.com/cygwin-ug-net/dll.html for more // information about GNU import libraries. // LD can link DLL directly, but LLD requires the import library. ret.push(FileType { suffix: ".dll.a".to_string(), prefix: "lib".to_string(), flavor: FileFlavor::Auxiliary, crate_type: Some(crate_type.clone()), should_replace_hyphens: true, }) } } if target_triple.starts_with("wasm32-") && crate_type == CrateType::Bin && suffix == ".js" { // emscripten binaries generate a .js file, which loads a .wasm // file. ret.push(FileType { suffix: ".wasm".to_string(), prefix: prefix.clone(), flavor: FileFlavor::Auxiliary, crate_type: Some(crate_type.clone()), // Name `foo-bar` will generate a `foo_bar.js` and // `foo_bar.wasm`. Cargo will translate the underscore and // copy `foo_bar.js` to `foo-bar.js`. However, the wasm // filename is embedded in the .js file with an underscore, so // it should not contain hyphens. should_replace_hyphens: true, }); // And a map file for debugging. This is only emitted with debug=2 // (-g4 for emcc). ret.push(FileType { suffix: ".wasm.map".to_string(), prefix: prefix.clone(), flavor: FileFlavor::DebugInfo, crate_type: Some(crate_type.clone()), should_replace_hyphens: true, }); } // Handle separate debug files. let is_apple = target_triple.contains("-apple-"); if matches!( crate_type, CrateType::Bin | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro ) { if is_apple { let suffix = if crate_type == CrateType::Bin { ".dSYM".to_string() } else { ".dylib.dSYM".to_string() }; ret.push(FileType { suffix, prefix: prefix.clone(), flavor: FileFlavor::DebugInfo, crate_type: Some(crate_type), // macOS tools like lldb use all sorts of magic to locate // dSYM files. See https://lldb.llvm.org/use/symbols.html // for some details. It seems like a `.dSYM` located next // to the executable with the same name is one method. The // dSYM should have the same hyphens as the executable for // the names to match. should_replace_hyphens: false, }) } else if target_triple.ends_with("-msvc") || target_triple.ends_with("-uefi") { ret.push(FileType { suffix: ".pdb".to_string(), prefix: prefix.clone(), flavor: FileFlavor::DebugInfo, crate_type: Some(crate_type), // The absolute path to the pdb file is embedded in the // executable. If the exe/pdb pair is moved to another // machine, then debuggers will look in the same directory // of the exe with the original pdb filename. Since the // original name contains underscores, they need to be // preserved. should_replace_hyphens: true, }) } else { // Because DWARF Package (dwp) files are produced after the // fact by another tool, there is nothing in the binary that // provides a means to locate them. By convention, debuggers // take the binary filename and append ".dwp" (including to // binaries that already have an extension such as shared libs) // to find the dwp. ret.push(FileType { // It is important to preserve the existing suffix for // e.g. shared libraries, where the dwp for libfoo.so is // expected to be at libfoo.so.dwp. suffix: format!("{suffix}.dwp"), prefix: prefix.clone(), flavor: FileFlavor::DebugInfo, crate_type: Some(crate_type.clone()), // Likewise, the dwp needs to match the primary artifact's // hyphenation exactly. should_replace_hyphens: crate_type != CrateType::Bin, }) } } Ok(Some(ret)) } fn discover_crate_type(&self, crate_type: &CrateType) -> CargoResult> { let mut process = self.crate_type_process.clone(); process.arg("--crate-type").arg(crate_type.as_str()); let output = process.exec_with_output().with_context(|| { format!( "failed to run `rustc` to learn about crate-type {} information", crate_type ) })?; let error = str::from_utf8(&output.stderr).unwrap(); let output = str::from_utf8(&output.stdout).unwrap(); parse_crate_type(crate_type, &process, output, error, &mut output.lines()) } /// Returns all the file types generated by rustc for the given `mode`/`target_kind`. /// /// The first value is a Vec of file types generated, the second value is /// a list of `CrateTypes` that are not supported by the given target. pub fn rustc_outputs( &self, mode: CompileMode, target_kind: &TargetKind, target_triple: &str, ) -> CargoResult<(Vec, Vec)> { match mode { CompileMode::Build => self.calc_rustc_outputs(target_kind, target_triple), CompileMode::Test | CompileMode::Bench => { match self.file_types(&CrateType::Bin, FileFlavor::Normal, target_triple)? { Some(fts) => Ok((fts, Vec::new())), None => Ok((Vec::new(), vec![CrateType::Bin])), } } CompileMode::Check { .. } => Ok((vec![FileType::new_rmeta()], Vec::new())), CompileMode::Doc { .. } | CompileMode::Doctest | CompileMode::Docscrape | CompileMode::RunCustomBuild => { panic!("asked for rustc output for non-rustc mode") } } } fn calc_rustc_outputs( &self, target_kind: &TargetKind, target_triple: &str, ) -> CargoResult<(Vec, Vec)> { let mut unsupported = Vec::new(); let mut result = Vec::new(); let crate_types = target_kind.rustc_crate_types(); for crate_type in &crate_types { let flavor = if crate_type.is_linkable() { FileFlavor::Linkable } else { FileFlavor::Normal }; let file_types = self.file_types(crate_type, flavor, target_triple)?; match file_types { Some(types) => { result.extend(types); } None => { unsupported.push(crate_type.clone()); } } } if !result.is_empty() && !crate_types.iter().any(|ct| ct.requires_upstream_objects()) { // Only add rmeta if pipelining. result.push(FileType::new_rmeta()); } Ok((result, unsupported)) } /// Checks if the debuginfo-split value is supported by this target pub fn supports_debuginfo_split(&self, split: InternedString) -> bool { self.support_split_debuginfo .iter() .any(|sup| sup.as_str() == split.as_str()) } /// Checks if a target maybe support std. /// /// If no explictly stated in target spec json, we treat it as "maybe support". /// /// This is only useful for `-Zbuild-std` to determine the default set of /// crates it is going to build. pub fn maybe_support_std(&self) -> bool { matches!(self.supports_std, Some(true) | None) } } /// Takes rustc output (using specialized command line args), and calculates the file prefix and /// suffix for the given crate type, or returns `None` if the type is not supported. (e.g., for a /// Rust library like `libcargo.rlib`, we have prefix "lib" and suffix "rlib"). /// /// The caller needs to ensure that the lines object is at the correct line for the given crate /// type: this is not checked. /// /// This function can not handle more than one file per type (with wasm32-unknown-emscripten, there /// are two files for bin (`.wasm` and `.js`)). fn parse_crate_type( crate_type: &CrateType, cmd: &ProcessBuilder, output: &str, error: &str, lines: &mut str::Lines<'_>, ) -> CargoResult> { let not_supported = error.lines().any(|line| { (line.contains("unsupported crate type") || line.contains("unknown crate type")) && line.contains(&format!("crate type `{}`", crate_type)) }); if not_supported { return Ok(None); } let Some(line) = lines.next() else { anyhow::bail!( "malformed output when learning about crate-type {} information\n{}", crate_type, output_err_info(cmd, output, error) ) }; let mut parts = line.trim().split("___"); let prefix = parts.next().unwrap(); let Some(suffix) = parts.next() else { return error_missing_print_output("file-names", cmd, output, error); }; Ok(Some((prefix.to_string(), suffix.to_string()))) } /// Helper for creating an error message for missing output from a certain `--print` request. fn error_missing_print_output( request: &str, cmd: &ProcessBuilder, stdout: &str, stderr: &str, ) -> CargoResult { let err_info = output_err_info(cmd, stdout, stderr); anyhow::bail!( "output of --print={request} missing when learning about \ target-specific information from rustc\n{err_info}", ) } /// Helper for creating an error message when parsing rustc output fails. fn output_err_info(cmd: &ProcessBuilder, stdout: &str, stderr: &str) -> String { let mut result = format!("command was: {}\n", cmd); if !stdout.is_empty() { result.push_str("\n--- stdout\n"); result.push_str(stdout); } if !stderr.is_empty() { result.push_str("\n--- stderr\n"); result.push_str(stderr); } if stdout.is_empty() && stderr.is_empty() { result.push_str("(no output received)"); } result } /// Compiler flags for either rustc or rustdoc. #[derive(Debug, Copy, Clone)] enum Flags { Rust, Rustdoc, } impl Flags { fn as_key(self) -> &'static str { match self { Flags::Rust => "rustflags", Flags::Rustdoc => "rustdocflags", } } fn as_env(self) -> &'static str { match self { Flags::Rust => "RUSTFLAGS", Flags::Rustdoc => "RUSTDOCFLAGS", } } } /// Acquire extra flags to pass to the compiler from various locations. /// /// The locations are: /// /// - the `CARGO_ENCODED_RUSTFLAGS` environment variable /// - the `RUSTFLAGS` environment variable /// /// then if none of those were found /// /// - `target.*.rustflags` from the config (.cargo/config) /// - `target.cfg(..).rustflags` from the config /// - `host.*.rustflags` from the config if compiling a host artifact or without `--target` /// (requires `-Zhost-config`) /// /// then if none of those were found /// /// - `build.rustflags` from the config /// /// The behavior differs slightly when cross-compiling (or, specifically, when `--target` is /// provided) for artifacts that are always built for the host (plugins, build scripts, ...). /// For those artifacts, _only_ `host.*.rustflags` is respected, and no other configuration /// sources, _regardless of the value of `target-applies-to-host`_. This is counterintuitive, but /// necessary to retain backwards compatibility with older versions of Cargo. /// /// Rules above also applies to rustdoc. Just the key would be `rustdocflags`/`RUSTDOCFLAGS`. fn extra_args( gctx: &GlobalContext, requested_kinds: &[CompileKind], host_triple: &str, target_cfg: Option<&[Cfg]>, kind: CompileKind, flags: Flags, ) -> CargoResult> { let target_applies_to_host = gctx.target_applies_to_host()?; // Host artifacts should not generally pick up rustflags from anywhere except [host]. // // The one exception to this is if `target-applies-to-host = true`, which opts into a // particular (inconsistent) past Cargo behavior where host artifacts _do_ pick up rustflags // set elsewhere when `--target` isn't passed. if kind.is_host() { if target_applies_to_host && requested_kinds == [CompileKind::Host] { // This is the past Cargo behavior where we fall back to the same logic as for other // artifacts without --target. } else { // In all other cases, host artifacts just get flags from [host], regardless of // --target. Or, phrased differently, no `--target` behaves the same as `--target // `, and host artifacts are always "special" (they don't pick up `RUSTFLAGS` for // example). return Ok(rustflags_from_host(gctx, flags, host_triple)?.unwrap_or_else(Vec::new)); } } // All other artifacts pick up the RUSTFLAGS, [target.*], and [build], in that order. // NOTE: It is impossible to have a [host] section and reach this logic with kind.is_host(), // since [host] implies `target-applies-to-host = false`, which always early-returns above. if let Some(rustflags) = rustflags_from_env(gctx, flags) { Ok(rustflags) } else if let Some(rustflags) = rustflags_from_target(gctx, host_triple, target_cfg, kind, flags)? { Ok(rustflags) } else if let Some(rustflags) = rustflags_from_build(gctx, flags)? { Ok(rustflags) } else { Ok(Vec::new()) } } /// Gets compiler flags from environment variables. /// See [`extra_args`] for more. fn rustflags_from_env(gctx: &GlobalContext, flags: Flags) -> Option> { // First try CARGO_ENCODED_RUSTFLAGS from the environment. // Prefer this over RUSTFLAGS since it's less prone to encoding errors. if let Ok(a) = gctx.get_env(format!("CARGO_ENCODED_{}", flags.as_env())) { if a.is_empty() { return Some(Vec::new()); } return Some(a.split('\x1f').map(str::to_string).collect()); } // Then try RUSTFLAGS from the environment if let Ok(a) = gctx.get_env(flags.as_env()) { let args = a .split(' ') .map(str::trim) .filter(|s| !s.is_empty()) .map(str::to_string); return Some(args.collect()); } // No rustflags to be collected from the environment None } /// Gets compiler flags from `[target]` section in the config. /// See [`extra_args`] for more. fn rustflags_from_target( gctx: &GlobalContext, host_triple: &str, target_cfg: Option<&[Cfg]>, kind: CompileKind, flag: Flags, ) -> CargoResult>> { let mut rustflags = Vec::new(); // Then the target.*.rustflags value... let target = match &kind { CompileKind::Host => host_triple, CompileKind::Target(target) => target.short_name(), }; let key = format!("target.{}.{}", target, flag.as_key()); if let Some(args) = gctx.get::>(&key)? { rustflags.extend(args.as_slice().iter().cloned()); } // ...including target.'cfg(...)'.rustflags if let Some(target_cfg) = target_cfg { gctx.target_cfgs()? .iter() .filter_map(|(key, cfg)| { match flag { Flags::Rust => cfg .rustflags .as_ref() .map(|rustflags| (key, &rustflags.val)), // `target.cfg(…).rustdocflags` is currently not supported. Flags::Rustdoc => None, } }) .filter(|(key, _rustflags)| CfgExpr::matches_key(key, target_cfg)) .for_each(|(_key, cfg_rustflags)| { rustflags.extend(cfg_rustflags.as_slice().iter().cloned()); }); } if rustflags.is_empty() { Ok(None) } else { Ok(Some(rustflags)) } } /// Gets compiler flags from `[host]` section in the config. /// See [`extra_args`] for more. fn rustflags_from_host( gctx: &GlobalContext, flag: Flags, host_triple: &str, ) -> CargoResult>> { let target_cfg = gctx.host_cfg_triple(host_triple)?; let list = match flag { Flags::Rust => &target_cfg.rustflags, Flags::Rustdoc => { // host.rustdocflags is not a thing, since it does not make sense return Ok(None); } }; Ok(list.as_ref().map(|l| l.val.as_slice().to_vec())) } /// Gets compiler flags from `[build]` section in the config. /// See [`extra_args`] for more. fn rustflags_from_build(gctx: &GlobalContext, flag: Flags) -> CargoResult>> { // Then the `build.rustflags` value. let build = gctx.build_config()?; let list = match flag { Flags::Rust => &build.rustflags, Flags::Rustdoc => &build.rustdocflags, }; Ok(list.as_ref().map(|l| l.as_slice().to_vec())) } /// Collection of information about `rustc` and the host and target. pub struct RustcTargetData<'gctx> { /// Information about `rustc` itself. pub rustc: Rustc, /// Config pub gctx: &'gctx GlobalContext, requested_kinds: Vec, /// Build information for the "host", which is information about when /// `rustc` is invoked without a `--target` flag. This is used for /// selecting a linker, and applying link overrides. /// /// The configuration read into this depends on whether or not /// `target-applies-to-host=true`. host_config: TargetConfig, /// Information about the host platform. host_info: TargetInfo, /// Build information for targets that we're building for. target_config: HashMap, /// Information about the target platform that we're building for. target_info: HashMap, } impl<'gctx> RustcTargetData<'gctx> { #[tracing::instrument(skip_all)] pub fn new( ws: &Workspace<'gctx>, requested_kinds: &[CompileKind], ) -> CargoResult> { let gctx = ws.gctx(); let rustc = gctx.load_global_rustc(Some(ws))?; let mut target_config = HashMap::new(); let mut target_info = HashMap::new(); let target_applies_to_host = gctx.target_applies_to_host()?; let host_target = CompileTarget::new(&rustc.host)?; let host_info = TargetInfo::new(gctx, requested_kinds, &rustc, CompileKind::Host)?; // This config is used for link overrides and choosing a linker. let host_config = if target_applies_to_host { gctx.target_cfg_triple(&rustc.host)? } else { gctx.host_cfg_triple(&rustc.host)? }; // This is a hack. The unit_dependency graph builder "pretends" that // `CompileKind::Host` is `CompileKind::Target(host)` if the // `--target` flag is not specified. Since the unit_dependency code // needs access to the target config data, create a copy so that it // can be found. See `rebuild_unit_graph_shared` for why this is done. if requested_kinds.iter().any(CompileKind::is_host) { target_config.insert(host_target, gctx.target_cfg_triple(&rustc.host)?); // If target_applies_to_host is true, the host_info is the target info, // otherwise we need to build target info for the target. if target_applies_to_host { target_info.insert(host_target, host_info.clone()); } else { let host_target_info = TargetInfo::new( gctx, requested_kinds, &rustc, CompileKind::Target(host_target), )?; target_info.insert(host_target, host_target_info); } }; let mut res = RustcTargetData { rustc, gctx, requested_kinds: requested_kinds.into(), host_config, host_info, target_config, target_info, }; // Get all kinds we currently know about. // // For now, targets can only ever come from the root workspace // units and artifact dependencies, so this // correctly represents all the kinds that can happen. When we have // other ways for targets to appear at places that are not the root units, // we may have to revisit this. fn artifact_targets(package: &Package) -> impl Iterator + '_ { package .manifest() .dependencies() .iter() .filter_map(|d| d.artifact()?.target()?.to_compile_kind()) } let all_kinds = requested_kinds .iter() .copied() .chain(ws.members().flat_map(|p| { p.manifest() .default_kind() .into_iter() .chain(p.manifest().forced_kind()) .chain(artifact_targets(p)) })); for kind in all_kinds { res.merge_compile_kind(kind)?; } Ok(res) } /// Insert `kind` into our `target_info` and `target_config` members if it isn't present yet. pub fn merge_compile_kind(&mut self, kind: CompileKind) -> CargoResult<()> { if let CompileKind::Target(target) = kind { if !self.target_config.contains_key(&target) { self.target_config .insert(target, self.gctx.target_cfg_triple(target.short_name())?); } if !self.target_info.contains_key(&target) { self.target_info.insert( target, TargetInfo::new(self.gctx, &self.requested_kinds, &self.rustc, kind)?, ); } } Ok(()) } /// Returns a "short" name for the given kind, suitable for keying off /// configuration in Cargo or presenting to users. pub fn short_name<'a>(&'a self, kind: &'a CompileKind) -> &'a str { match kind { CompileKind::Host => &self.rustc.host, CompileKind::Target(target) => target.short_name(), } } /// Whether a dependency should be compiled for the host or target platform, /// specified by `CompileKind`. pub fn dep_platform_activated(&self, dep: &Dependency, kind: CompileKind) -> bool { // If this dependency is only available for certain platforms, // make sure we're only enabling it for that platform. let Some(platform) = dep.platform() else { return true; }; let name = self.short_name(&kind); platform.matches(name, self.cfg(kind)) } /// Gets the list of `cfg`s printed out from the compiler for the specified kind. pub fn cfg(&self, kind: CompileKind) -> &[Cfg] { self.info(kind).cfg() } /// Information about the given target platform, learned by querying rustc. /// /// # Panics /// /// Panics, if the target platform described by `kind` can't be found. /// See [`get_info`](Self::get_info) for a non-panicking alternative. pub fn info(&self, kind: CompileKind) -> &TargetInfo { self.get_info(kind).unwrap() } /// Information about the given target platform, learned by querying rustc. /// /// Returns `None` if the target platform described by `kind` can't be found. pub fn get_info(&self, kind: CompileKind) -> Option<&TargetInfo> { match kind { CompileKind::Host => Some(&self.host_info), CompileKind::Target(s) => self.target_info.get(&s), } } /// Gets the target configuration for a particular host or target. pub fn target_config(&self, kind: CompileKind) -> &TargetConfig { match kind { CompileKind::Host => &self.host_config, CompileKind::Target(s) => &self.target_config[&s], } } pub fn get_unsupported_std_targets(&self) -> Vec<&str> { let mut unsupported = Vec::new(); for (target, target_info) in &self.target_info { if target_info.supports_std == Some(false) { unsupported.push(target.short_name()); } } unsupported } } /// Structure used to deal with Rustdoc fingerprinting #[derive(Debug, Serialize, Deserialize)] pub struct RustDocFingerprint { pub rustc_vv: String, } impl RustDocFingerprint { /// This function checks whether the latest version of `Rustc` used to compile this /// `Workspace`'s docs was the same as the one is currently being used in this `cargo doc` /// call. /// /// In case it's not, it takes care of removing the `doc/` folder as well as overwriting /// the rustdoc fingerprint info in order to guarantee that we won't end up with mixed /// versions of the `js/html/css` files that `rustdoc` autogenerates which do not have /// any versioning. pub fn check_rustdoc_fingerprint(build_runner: &BuildRunner<'_, '_>) -> CargoResult<()> { if build_runner .bcx .gctx .cli_unstable() .skip_rustdoc_fingerprint { return Ok(()); } let actual_rustdoc_target_data = RustDocFingerprint { rustc_vv: build_runner.bcx.rustc().verbose_version.clone(), }; let fingerprint_path = build_runner .files() .host_root() .join(".rustdoc_fingerprint.json"); let write_fingerprint = || -> CargoResult<()> { paths::write( &fingerprint_path, serde_json::to_string(&actual_rustdoc_target_data)?, ) }; let Ok(rustdoc_data) = paths::read(&fingerprint_path) else { // If the fingerprint does not exist, do not clear out the doc // directories. Otherwise this ran into problems where projects // like bootstrap were creating the doc directory before running // `cargo doc` in a way that deleting it would break it. return write_fingerprint(); }; match serde_json::from_str::(&rustdoc_data) { Ok(fingerprint) => { if fingerprint.rustc_vv == actual_rustdoc_target_data.rustc_vv { return Ok(()); } else { tracing::debug!( "doc fingerprint changed:\noriginal:\n{}\nnew:\n{}", fingerprint.rustc_vv, actual_rustdoc_target_data.rustc_vv ); } } Err(e) => { tracing::debug!("could not deserialize {:?}: {}", fingerprint_path, e); } }; // Fingerprint does not match, delete the doc directories and write a new fingerprint. tracing::debug!( "fingerprint {:?} mismatch, clearing doc directories", fingerprint_path ); build_runner .bcx .all_kinds .iter() .map(|kind| build_runner.files().layout(*kind).doc()) .filter(|path| path.exists()) .try_for_each(|path| clean_doc(path))?; write_fingerprint()?; return Ok(()); fn clean_doc(path: &Path) -> CargoResult<()> { let entries = path .read_dir() .with_context(|| format!("failed to read directory `{}`", path.display()))?; for entry in entries { let entry = entry?; // Don't remove hidden files. Rustdoc does not create them, // but the user might have. if entry .file_name() .to_str() .map_or(false, |name| name.starts_with('.')) { continue; } let path = entry.path(); if entry.file_type()?.is_dir() { paths::remove_dir_all(path)?; } else { paths::remove_file(path)?; } } Ok(()) } } } cargo-0.86.0/src/cargo/core/compiler/build_plan.rs000064400000000000000000000114431046102023000201200ustar 00000000000000//! A graph-like structure used to represent the rustc commands to build the package and the //! interdependencies between them. //! //! The `BuildPlan` structure is used to store the dependency graph of a dry run so that it can be //! shared with an external build system. Each Invocation in the `BuildPlan` comprises a single //! subprocess and defines the build environment, the outputs produced by the subprocess, and the //! dependencies on other Invocations. use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use serde::Serialize; use super::build_runner::OutputFile; use super::{BuildRunner, CompileKind, CompileMode, Unit}; use crate::core::TargetKind; use crate::util::{internal, CargoResult, GlobalContext}; use cargo_util::ProcessBuilder; #[derive(Debug, Serialize)] struct Invocation { package_name: String, package_version: semver::Version, target_kind: TargetKind, kind: CompileKind, compile_mode: CompileMode, deps: Vec, outputs: Vec, links: BTreeMap, program: String, args: Vec, env: BTreeMap, cwd: Option, } #[derive(Debug)] pub struct BuildPlan { invocation_map: BTreeMap, plan: SerializedBuildPlan, } #[derive(Debug, Serialize)] struct SerializedBuildPlan { invocations: Vec, inputs: Vec, } impl Invocation { pub fn new(unit: &Unit, deps: Vec) -> Invocation { let id = unit.pkg.package_id(); Invocation { package_name: id.name().to_string(), package_version: id.version().clone(), kind: unit.kind, target_kind: unit.target.kind().clone(), compile_mode: unit.mode, deps, outputs: Vec::new(), links: BTreeMap::new(), program: String::new(), args: Vec::new(), env: BTreeMap::new(), cwd: None, } } pub fn add_output(&mut self, path: &Path, link: &Option) { self.outputs.push(path.to_path_buf()); if let Some(ref link) = *link { self.links.insert(link.clone(), path.to_path_buf()); } } pub fn update_cmd(&mut self, cmd: &ProcessBuilder) -> CargoResult<()> { self.program = cmd .get_program() .to_str() .ok_or_else(|| anyhow::format_err!("unicode program string required"))? .to_string(); self.cwd = Some(cmd.get_cwd().unwrap().to_path_buf()); for arg in cmd.get_args() { self.args.push( arg.to_str() .ok_or_else(|| anyhow::format_err!("unicode argument string required"))? .to_string(), ); } for (var, value) in cmd.get_envs() { let Some(value) = value else { continue }; self.env.insert( var.clone(), value .to_str() .ok_or_else(|| anyhow::format_err!("unicode environment value required"))? .to_string(), ); } Ok(()) } } impl BuildPlan { pub fn new() -> BuildPlan { BuildPlan { invocation_map: BTreeMap::new(), plan: SerializedBuildPlan::new(), } } pub fn add(&mut self, build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<()> { let id = self.plan.invocations.len(); self.invocation_map.insert(unit.buildkey(), id); let deps = build_runner .unit_deps(unit) .iter() .map(|dep| self.invocation_map[&dep.unit.buildkey()]) .collect(); let invocation = Invocation::new(unit, deps); self.plan.invocations.push(invocation); Ok(()) } pub fn update( &mut self, invocation_name: &str, cmd: &ProcessBuilder, outputs: &[OutputFile], ) -> CargoResult<()> { let id = self.invocation_map[invocation_name]; let invocation = self.plan.invocations.get_mut(id).ok_or_else(|| { internal(format!("couldn't find invocation for {}", invocation_name)) })?; invocation.update_cmd(cmd)?; for output in outputs.iter() { invocation.add_output(&output.path, &output.hardlink); } Ok(()) } pub fn set_inputs(&mut self, inputs: Vec) { self.plan.inputs = inputs; } pub fn output_plan(self, gctx: &GlobalContext) { let encoded = serde_json::to_string(&self.plan).unwrap(); crate::drop_println!(gctx, "{}", encoded); } } impl SerializedBuildPlan { pub fn new() -> SerializedBuildPlan { SerializedBuildPlan { invocations: Vec::new(), inputs: Vec::new(), } } } cargo-0.86.0/src/cargo/core/compiler/build_runner/compilation_files.rs000064400000000000000000001027401046102023000242000ustar 00000000000000//! See [`CompilationFiles`]. use std::collections::HashMap; use std::fmt; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; use std::sync::Arc; use lazycell::LazyCell; use tracing::debug; use super::{BuildContext, BuildRunner, CompileKind, FileFlavor, Layout}; use crate::core::compiler::{CompileMode, CompileTarget, CrateType, FileType, Unit}; use crate::core::{Target, TargetKind, Workspace}; use crate::util::{self, CargoResult, StableHasher}; /// This is a generic version number that can be changed to make /// backwards-incompatible changes to any file structures in the output /// directory. For example, the fingerprint files or the build-script /// output files. /// /// Normally cargo updates ship with rustc updates which will /// cause a new hash due to the rustc version changing, but this allows /// cargo to be extra careful to deal with different versions of cargo that /// use the same rustc version. const METADATA_VERSION: u8 = 2; /// Uniquely identify a [`Unit`] under specific circumstances, see [`Metadata`] for more. #[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct UnitHash(u64); impl fmt::Display for UnitHash { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:016x}", self.0) } } impl fmt::Debug for UnitHash { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "UnitHash({:016x})", self.0) } } /// [`Metadata`] tracks several [`UnitHash`]s, including /// [`Metadata::unit_id`], [`Metadata::c_metadata`], and [`Metadata::c_extra_filename`]. /// /// We use a hash because it is an easy way to guarantee /// that all the inputs can be converted to a valid path. /// /// [`Metadata::unit_id`] is used to uniquely identify a unit in the build graph. /// This serves as a similar role as [`Metadata::c_extra_filename`] in that it uniquely identifies output /// on the filesystem except that its always present. /// /// [`Metadata::c_extra_filename`] is needed for cases like: /// - A project may depend on crate `A` and crate `B`, so the package name must be in the file name. /// - Similarly a project may depend on two versions of `A`, so the version must be in the file name. /// /// This also acts as the main layer of caching provided by Cargo /// so this must include all things that need to be distinguished in different parts of /// the same build. This is absolutely required or we override things before /// we get chance to use them. /// /// For example, we want to cache `cargo build` and `cargo doc` separately, so that running one /// does not invalidate the artifacts for the other. We do this by including [`CompileMode`] in the /// hash, thus the artifacts go in different folders and do not override each other. /// If we don't add something that we should have, for this reason, we get the /// correct output but rebuild more than is needed. /// /// Some things that need to be tracked to ensure the correct output should definitely *not* /// go in the `Metadata`. For example, the modification time of a file, should be tracked to make a /// rebuild when the file changes. However, it would be wasteful to include in the `Metadata`. The /// old artifacts are never going to be needed again. We can save space by just overwriting them. /// If we add something that we should not have, for this reason, we get the correct output but take /// more space than needed. This makes not including something in `Metadata` /// a form of cache invalidation. /// /// Note that the `Fingerprint` is in charge of tracking everything needed to determine if a /// rebuild is needed. /// /// [`Metadata::c_metadata`] is used for symbol mangling, because if you have two versions of /// the same crate linked together, their symbols need to be differentiated. /// /// You should avoid anything that would interfere with reproducible /// builds. For example, *any* absolute path should be avoided. This is one /// reason that `RUSTFLAGS` is not in [`Metadata::c_metadata`], because it often has /// absolute paths (like `--remap-path-prefix` which is fundamentally used for /// reproducible builds and has absolute paths in it). Also, in some cases the /// mangled symbols need to be stable between different builds with different /// settings. For example, profile-guided optimizations need to swap /// `RUSTFLAGS` between runs, but needs to keep the same symbol names. #[derive(Copy, Clone, Debug)] pub struct Metadata { unit_id: UnitHash, c_metadata: UnitHash, c_extra_filename: Option, } impl Metadata { /// A hash to identify a given [`Unit`] in the build graph pub fn unit_id(&self) -> UnitHash { self.unit_id } /// A hash to add to symbol naming through `-C metadata` pub fn c_metadata(&self) -> UnitHash { self.c_metadata } /// A hash to add to file names through `-C extra-filename` pub fn c_extra_filename(&self) -> Option { self.c_extra_filename } } /// Collection of information about the files emitted by the compiler, and the /// output directory structure. pub struct CompilationFiles<'a, 'gctx> { /// The target directory layout for the host (and target if it is the same as host). pub(super) host: Layout, /// The target directory layout for the target (if different from then host). pub(super) target: HashMap, /// Additional directory to include a copy of the outputs. export_dir: Option, /// The root targets requested by the user on the command line (does not /// include dependencies). roots: Vec, ws: &'a Workspace<'gctx>, /// Metadata hash to use for each unit. metas: HashMap, /// For each Unit, a list all files produced. outputs: HashMap>>>, } /// Info about a single file emitted by the compiler. #[derive(Debug)] pub struct OutputFile { /// Absolute path to the file that will be produced by the build process. pub path: PathBuf, /// If it should be linked into `target`, and what it should be called /// (e.g., without metadata). pub hardlink: Option, /// If `--artifact-dir` is specified, the absolute path to the exported file. pub export_path: Option, /// Type of the file (library / debug symbol / else). pub flavor: FileFlavor, } impl OutputFile { /// Gets the hard link if present; otherwise, returns the path. pub fn bin_dst(&self) -> &PathBuf { match self.hardlink { Some(ref link_dst) => link_dst, None => &self.path, } } } impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> { pub(super) fn new( build_runner: &BuildRunner<'a, 'gctx>, host: Layout, target: HashMap, ) -> CompilationFiles<'a, 'gctx> { let mut metas = HashMap::new(); for unit in &build_runner.bcx.roots { metadata_of(unit, build_runner, &mut metas); } let outputs = metas .keys() .cloned() .map(|unit| (unit, LazyCell::new())) .collect(); CompilationFiles { ws: build_runner.bcx.ws, host, target, export_dir: build_runner.bcx.build_config.export_dir.clone(), roots: build_runner.bcx.roots.clone(), metas, outputs, } } /// Returns the appropriate directory layout for either a plugin or not. pub fn layout(&self, kind: CompileKind) -> &Layout { match kind { CompileKind::Host => &self.host, CompileKind::Target(target) => &self.target[&target], } } /// Gets the metadata for the given unit. /// /// See [`Metadata`] and [`fingerprint`] module for more. /// /// [`fingerprint`]: super::super::fingerprint#fingerprints-and-metadata pub fn metadata(&self, unit: &Unit) -> Metadata { self.metas[unit] } /// Gets the short hash based only on the `PackageId`. /// Used for the metadata when `metadata` returns `None`. pub fn target_short_hash(&self, unit: &Unit) -> String { let hashable = unit.pkg.package_id().stable_hash(self.ws.root()); util::short_hash(&(METADATA_VERSION, hashable)) } /// Returns the directory where the artifacts for the given unit are /// initially created. pub fn out_dir(&self, unit: &Unit) -> PathBuf { // Docscrape units need to have doc/ set as the out_dir so sources for reverse-dependencies // will be put into doc/ and not into deps/ where the *.examples files are stored. if unit.mode.is_doc() || unit.mode.is_doc_scrape() { self.layout(unit.kind).doc().to_path_buf() } else if unit.mode.is_doc_test() { panic!("doc tests do not have an out dir"); } else if unit.target.is_custom_build() { self.build_script_dir(unit) } else if unit.target.is_example() { self.layout(unit.kind).examples().to_path_buf() } else if unit.artifact.is_true() { self.artifact_dir(unit) } else { self.deps_dir(unit).to_path_buf() } } /// Additional export directory from `--artifact-dir`. pub fn export_dir(&self) -> Option { self.export_dir.clone() } /// Directory name to use for a package in the form `NAME-HASH`. /// /// Note that some units may share the same directory, so care should be /// taken in those cases! fn pkg_dir(&self, unit: &Unit) -> String { let name = unit.pkg.package_id().name(); let meta = self.metas[unit]; if let Some(c_extra_filename) = meta.c_extra_filename() { format!("{}-{}", name, c_extra_filename) } else { format!("{}-{}", name, self.target_short_hash(unit)) } } /// Returns the final artifact path for the host (`/…/target/debug`) pub fn host_dest(&self) -> &Path { self.host.dest() } /// Returns the root of the build output tree for the host (`/…/target`) pub fn host_root(&self) -> &Path { self.host.root() } /// Returns the host `deps` directory path. pub fn host_deps(&self) -> &Path { self.host.deps() } /// Returns the directories where Rust crate dependencies are found for the /// specified unit. pub fn deps_dir(&self, unit: &Unit) -> &Path { self.layout(unit.kind).deps() } /// Directory where the fingerprint for the given unit should go. pub fn fingerprint_dir(&self, unit: &Unit) -> PathBuf { let dir = self.pkg_dir(unit); self.layout(unit.kind).fingerprint().join(dir) } /// Returns the path for a file in the fingerprint directory. /// /// The "prefix" should be something to distinguish the file from other /// files in the fingerprint directory. pub fn fingerprint_file_path(&self, unit: &Unit, prefix: &str) -> PathBuf { // Different targets need to be distinguished in the let kind = unit.target.kind().description(); let flavor = if unit.mode.is_any_test() { "test-" } else if unit.mode.is_doc() { "doc-" } else if unit.mode.is_run_custom_build() { "run-" } else { "" }; let name = format!("{}{}{}-{}", prefix, flavor, kind, unit.target.name()); self.fingerprint_dir(unit).join(name) } /// Path where compiler output is cached. pub fn message_cache_path(&self, unit: &Unit) -> PathBuf { self.fingerprint_file_path(unit, "output-") } /// Returns the directory where a compiled build script is stored. /// `/path/to/target/{debug,release}/build/PKG-HASH` pub fn build_script_dir(&self, unit: &Unit) -> PathBuf { assert!(unit.target.is_custom_build()); assert!(!unit.mode.is_run_custom_build()); assert!(self.metas.contains_key(unit)); let dir = self.pkg_dir(unit); self.layout(CompileKind::Host).build().join(dir) } /// Returns the directory for compiled artifacts files. /// `/path/to/target/{debug,release}/deps/artifact/KIND/PKG-HASH` fn artifact_dir(&self, unit: &Unit) -> PathBuf { assert!(self.metas.contains_key(unit)); assert!(unit.artifact.is_true()); let dir = self.pkg_dir(unit); let kind = match unit.target.kind() { TargetKind::Bin => "bin", TargetKind::Lib(lib_kinds) => match lib_kinds.as_slice() { &[CrateType::Cdylib] => "cdylib", &[CrateType::Staticlib] => "staticlib", invalid => unreachable!( "BUG: unexpected artifact library type(s): {:?} - these should have been split", invalid ), }, invalid => unreachable!( "BUG: {:?} are not supposed to be used as artifacts", invalid ), }; self.layout(unit.kind).artifact().join(dir).join(kind) } /// Returns the directory where information about running a build script /// is stored. /// `/path/to/target/{debug,release}/build/PKG-HASH` pub fn build_script_run_dir(&self, unit: &Unit) -> PathBuf { assert!(unit.target.is_custom_build()); assert!(unit.mode.is_run_custom_build()); let dir = self.pkg_dir(unit); self.layout(unit.kind).build().join(dir) } /// Returns the "`OUT_DIR`" directory for running a build script. /// `/path/to/target/{debug,release}/build/PKG-HASH/out` pub fn build_script_out_dir(&self, unit: &Unit) -> PathBuf { self.build_script_run_dir(unit).join("out") } /// Returns the path to the executable binary for the given bin target. /// /// This should only to be used when a `Unit` is not available. pub fn bin_link_for_target( &self, target: &Target, kind: CompileKind, bcx: &BuildContext<'_, '_>, ) -> CargoResult { assert!(target.is_bin()); let dest = self.layout(kind).dest(); let info = bcx.target_data.info(kind); let (file_types, _) = info .rustc_outputs( CompileMode::Build, &TargetKind::Bin, bcx.target_data.short_name(&kind), ) .expect("target must support `bin`"); let file_type = file_types .iter() .find(|file_type| file_type.flavor == FileFlavor::Normal) .expect("target must support `bin`"); Ok(dest.join(file_type.uplift_filename(target))) } /// Returns the filenames that the given unit will generate. /// /// Note: It is not guaranteed that all of the files will be generated. pub(super) fn outputs( &self, unit: &Unit, bcx: &BuildContext<'a, 'gctx>, ) -> CargoResult>> { self.outputs[unit] .try_borrow_with(|| self.calc_outputs(unit, bcx)) .map(Arc::clone) } /// Returns the path where the output for the given unit and `FileType` /// should be uplifted to. /// /// Returns `None` if the unit shouldn't be uplifted (for example, a /// dependent rlib). fn uplift_to(&self, unit: &Unit, file_type: &FileType, from_path: &Path) -> Option { // Tests, check, doc, etc. should not be uplifted. if unit.mode != CompileMode::Build || file_type.flavor == FileFlavor::Rmeta { return None; } // Artifact dependencies are never uplifted. if unit.artifact.is_true() { return None; } // - Binaries: The user always wants to see these, even if they are // implicitly built (for example for integration tests). // - dylibs: This ensures that the dynamic linker pulls in all the // latest copies (even if the dylib was built from a previous cargo // build). There are complex reasons for this, see #8139, #6167, #6162. // - Things directly requested from the command-line (the "roots"). // This one is a little questionable for rlibs (see #6131), but is // historically how Cargo has operated. This is primarily useful to // give the user access to staticlibs and cdylibs. if !unit.target.is_bin() && !unit.target.is_custom_build() && file_type.crate_type != Some(CrateType::Dylib) && !self.roots.contains(unit) { return None; } let filename = file_type.uplift_filename(&unit.target); let uplift_path = if unit.target.is_example() { // Examples live in their own little world. self.layout(unit.kind).examples().join(filename) } else if unit.target.is_custom_build() { self.build_script_dir(unit).join(filename) } else { self.layout(unit.kind).dest().join(filename) }; if from_path == uplift_path { // This can happen with things like examples that reside in the // same directory, do not have a metadata hash (like on Windows), // and do not have hyphens. return None; } Some(uplift_path) } /// Calculates the filenames that the given unit will generate. /// Should use [`CompilationFiles::outputs`] instead /// as it caches the result of this function. fn calc_outputs( &self, unit: &Unit, bcx: &BuildContext<'a, 'gctx>, ) -> CargoResult>> { let ret = match unit.mode { CompileMode::Doc { json, .. } => { let path = if json { self.out_dir(unit) .join(format!("{}.json", unit.target.crate_name())) } else { self.out_dir(unit) .join(unit.target.crate_name()) .join("index.html") }; vec![OutputFile { path, hardlink: None, export_path: None, flavor: FileFlavor::Normal, }] } CompileMode::RunCustomBuild => { // At this time, this code path does not handle build script // outputs. vec![] } CompileMode::Doctest => { // Doctests are built in a temporary directory and then // deleted. There is the `--persist-doctests` unstable flag, // but Cargo does not know about that. vec![] } CompileMode::Docscrape => { // The file name needs to be stable across Cargo sessions. // This originally used unit.buildkey(), but that isn't stable, // so we use metadata instead (prefixed with name for debugging). let file_name = format!( "{}-{}.examples", unit.pkg.name(), self.metadata(unit).unit_id() ); let path = self.deps_dir(unit).join(file_name); vec![OutputFile { path, hardlink: None, export_path: None, flavor: FileFlavor::Normal, }] } CompileMode::Test | CompileMode::Build | CompileMode::Bench | CompileMode::Check { .. } => self.calc_outputs_rustc(unit, bcx)?, }; debug!("Target filenames: {:?}", ret); Ok(Arc::new(ret)) } /// Computes the actual, full pathnames for all the files generated by rustc. /// /// The `OutputFile` also contains the paths where those files should be /// "uplifted" to. fn calc_outputs_rustc( &self, unit: &Unit, bcx: &BuildContext<'a, 'gctx>, ) -> CargoResult> { let out_dir = self.out_dir(unit); let info = bcx.target_data.info(unit.kind); let triple = bcx.target_data.short_name(&unit.kind); let (file_types, unsupported) = info.rustc_outputs(unit.mode, unit.target.kind(), triple)?; if file_types.is_empty() { if !unsupported.is_empty() { let unsupported_strs: Vec<_> = unsupported.iter().map(|ct| ct.as_str()).collect(); anyhow::bail!( "cannot produce {} for `{}` as the target `{}` \ does not support these crate types", unsupported_strs.join(", "), unit.pkg, triple, ) } anyhow::bail!( "cannot compile `{}` as the target `{}` does not \ support any of the output crate types", unit.pkg, triple, ); } // Convert FileType to OutputFile. let mut outputs = Vec::new(); for file_type in file_types { let meta = self.metas[unit]; let meta_opt = meta.c_extra_filename().map(|h| h.to_string()); let path = out_dir.join(file_type.output_filename(&unit.target, meta_opt.as_deref())); // If, the `different_binary_name` feature is enabled, the name of the hardlink will // be the name of the binary provided by the user in `Cargo.toml`. let hardlink = self.uplift_to(unit, &file_type, &path); let export_path = if unit.target.is_custom_build() { None } else { self.export_dir.as_ref().and_then(|export_dir| { hardlink .as_ref() .map(|hardlink| export_dir.join(hardlink.file_name().unwrap())) }) }; outputs.push(OutputFile { path, hardlink, export_path, flavor: file_type.flavor, }); } Ok(outputs) } } /// Gets the metadata hash for the given [`Unit`]. /// /// When a metadata hash doesn't exist for the given unit, /// this calls itself recursively to compute metadata hashes of all its dependencies. /// See [`compute_metadata`] for how a single metadata hash is computed. fn metadata_of<'a>( unit: &Unit, build_runner: &BuildRunner<'_, '_>, metas: &'a mut HashMap, ) -> &'a Metadata { if !metas.contains_key(unit) { let meta = compute_metadata(unit, build_runner, metas); metas.insert(unit.clone(), meta); for dep in build_runner.unit_deps(unit) { metadata_of(&dep.unit, build_runner, metas); } } &metas[unit] } /// Computes the metadata hash for the given [`Unit`]. fn compute_metadata( unit: &Unit, build_runner: &BuildRunner<'_, '_>, metas: &mut HashMap, ) -> Metadata { let bcx = &build_runner.bcx; let deps_metadata = build_runner .unit_deps(unit) .iter() .map(|dep| *metadata_of(&dep.unit, build_runner, metas)) .collect::>(); let use_extra_filename = use_extra_filename(bcx, unit); let mut shared_hasher = StableHasher::new(); METADATA_VERSION.hash(&mut shared_hasher); let ws_root = if unit.is_std { // SourceId for stdlib crates is an absolute path inside the sysroot. // Pass the sysroot as workspace root so that we hash a relative path. // This avoids the metadata hash changing depending on where the user installed rustc. &bcx.target_data.get_info(unit.kind).unwrap().sysroot } else { bcx.ws.root() }; // Unique metadata per (name, source, version) triple. This'll allow us // to pull crates from anywhere without worrying about conflicts. unit.pkg .package_id() .stable_hash(ws_root) .hash(&mut shared_hasher); // Also mix in enabled features to our metadata. This'll ensure that // when changing feature sets each lib is separately cached. unit.features.hash(&mut shared_hasher); // Throw in the profile we're compiling with. This helps caching // `panic=abort` and `panic=unwind` artifacts, additionally with various // settings like debuginfo and whatnot. unit.profile.hash(&mut shared_hasher); unit.mode.hash(&mut shared_hasher); build_runner.lto[unit].hash(&mut shared_hasher); // Artifacts compiled for the host should have a different // metadata piece than those compiled for the target, so make sure // we throw in the unit's `kind` as well. Use `fingerprint_hash` // so that the StableHash doesn't change based on the pathnames // of the custom target JSON spec files. unit.kind.fingerprint_hash().hash(&mut shared_hasher); // Finally throw in the target name/kind. This ensures that concurrent // compiles of targets in the same crate don't collide. unit.target.name().hash(&mut shared_hasher); unit.target.kind().hash(&mut shared_hasher); hash_rustc_version(bcx, &mut shared_hasher, unit); if build_runner.bcx.ws.is_member(&unit.pkg) { // This is primarily here for clippy. This ensures that the clippy // artifacts are separate from the `check` ones. if let Some(path) = &build_runner.bcx.rustc().workspace_wrapper { path.hash(&mut shared_hasher); } } // Seed the contents of `__CARGO_DEFAULT_LIB_METADATA` to the hasher if present. // This should be the release channel, to get a different hash for each channel. if let Ok(ref channel) = build_runner .bcx .gctx .get_env("__CARGO_DEFAULT_LIB_METADATA") { channel.hash(&mut shared_hasher); } // std units need to be kept separate from user dependencies. std crates // are differentiated in the Unit with `is_std` (for things like // `-Zforce-unstable-if-unmarked`), so they are always built separately. // This isn't strictly necessary for build dependencies which probably // don't need unstable support. A future experiment might be to set // `is_std` to false for build dependencies so that they can be shared // with user dependencies. unit.is_std.hash(&mut shared_hasher); // While we don't hash RUSTFLAGS because it may contain absolute paths that // hurts reproducibility, we track whether a unit's RUSTFLAGS is from host // config, so that we can generate a different metadata hash for runtime // and compile-time units. // // HACK: This is a temporary hack for fixing rust-lang/cargo#14253 // Need to find a long-term solution to replace this fragile workaround. // See https://github.com/rust-lang/cargo/pull/14432#discussion_r1725065350 if unit.kind.is_host() && !bcx.gctx.target_applies_to_host().unwrap_or_default() { let host_info = bcx.target_data.info(CompileKind::Host); let target_configs_are_different = unit.rustflags != host_info.rustflags || unit.rustdocflags != host_info.rustdocflags || bcx .target_data .target_config(CompileKind::Host) .links_overrides != unit.links_overrides; target_configs_are_different.hash(&mut shared_hasher); } let mut c_metadata_hasher = shared_hasher.clone(); // Mix in the target-metadata of all the dependencies of this target. let mut dep_c_metadata_hashes = deps_metadata .iter() .map(|m| m.c_metadata) .collect::>(); dep_c_metadata_hashes.sort(); dep_c_metadata_hashes.hash(&mut c_metadata_hasher); let mut c_extra_filename_hasher = shared_hasher.clone(); // Mix in the target-metadata of all the dependencies of this target. let mut dep_c_extra_filename_hashes = deps_metadata .iter() .map(|m| m.c_extra_filename) .collect::>(); dep_c_extra_filename_hashes.sort(); dep_c_extra_filename_hashes.hash(&mut c_extra_filename_hasher); // Avoid trashing the caches on RUSTFLAGS changing via `c_extra_filename` // // Limited to `c_extra_filename` to help with reproducible build / PGO issues. let default = Vec::new(); let extra_args = build_runner.bcx.extra_args_for(unit).unwrap_or(&default); if !has_remap_path_prefix(&extra_args) { extra_args.hash(&mut c_extra_filename_hasher); } if unit.mode.is_doc() || unit.mode.is_doc_scrape() { if !has_remap_path_prefix(&unit.rustdocflags) { unit.rustdocflags.hash(&mut c_extra_filename_hasher); } } else { if !has_remap_path_prefix(&unit.rustflags) { unit.rustflags.hash(&mut c_extra_filename_hasher); } } let c_metadata = UnitHash(Hasher::finish(&c_metadata_hasher)); let c_extra_filename = UnitHash(Hasher::finish(&c_extra_filename_hasher)); let unit_id = c_extra_filename; let c_extra_filename = use_extra_filename.then_some(c_extra_filename); Metadata { unit_id, c_metadata, c_extra_filename, } } /// HACK: Detect the *potential* presence of `--remap-path-prefix` /// /// As CLI parsing is contextual and dependent on the CLI definition to understand the context, we /// can't say for sure whether `--remap-path-prefix` is present, so we guess if anything looks like /// it. /// If we could, we'd strip it out for hashing. /// Instead, we use this to avoid hashing rustflags if it might be present to avoid the risk of taking /// a flag that is trying to make things reproducible and making things less reproducible by the /// `-Cextra-filename` showing up in the rlib, even with `split-debuginfo`. fn has_remap_path_prefix(args: &[String]) -> bool { args.iter() .any(|s| s.starts_with("--remap-path-prefix=") || s == "--remap-path-prefix") } /// Hash the version of rustc being used during the build process. fn hash_rustc_version(bcx: &BuildContext<'_, '_>, hasher: &mut StableHasher, unit: &Unit) { let vers = &bcx.rustc().version; if vers.pre.is_empty() || bcx.gctx.cli_unstable().separate_nightlies { // For stable, keep the artifacts separate. This helps if someone is // testing multiple versions, to avoid recompiles. Note though that for // cross-compiled builds the `host:` line of `verbose_version` is // omitted since rustc should produce the same output for each target // regardless of the host. for line in bcx.rustc().verbose_version.lines() { if unit.kind.is_host() || !line.starts_with("host: ") { line.hash(hasher); } } return; } // On "nightly"/"beta"/"dev"/etc, keep each "channel" separate. Don't hash // the date/git information, so that whenever someone updates "nightly", // they won't have a bunch of stale artifacts in the target directory. // // This assumes that the first segment is the important bit ("nightly", // "beta", "dev", etc.). Skip other parts like the `.3` in `-beta.3`. vers.pre.split('.').next().hash(hasher); // Keep "host" since some people switch hosts to implicitly change // targets, (like gnu vs musl or gnu vs msvc). In the future, we may want // to consider hashing `unit.kind.short_name()` instead. if unit.kind.is_host() { bcx.rustc().host.hash(hasher); } // None of the other lines are important. Currently they are: // binary: rustc <-- or "rustdoc" // commit-hash: 38114ff16e7856f98b2b4be7ab4cd29b38bed59a // commit-date: 2020-03-21 // host: x86_64-apple-darwin // release: 1.44.0-nightly // LLVM version: 9.0 // // The backend version ("LLVM version") might become more relevant in // the future when cranelift sees more use, and people want to switch // between different backends without recompiling. } /// Returns whether or not this unit should use a hash in the filename to make it unique. fn use_extra_filename(bcx: &BuildContext<'_, '_>, unit: &Unit) -> bool { if unit.mode.is_doc_test() || unit.mode.is_doc() { // Doc tests do not have metadata. return false; } if unit.mode.is_any_test() || unit.mode.is_check() { // These always use metadata. return true; } // No metadata in these cases: // // - dylibs: // - if any dylib names are encoded in executables, so they can't be renamed. // - TODO: Maybe use `-install-name` on macOS or `-soname` on other UNIX systems // to specify the dylib name to be used by the linker instead of the filename. // - Windows MSVC executables: The path to the PDB is embedded in the // executable, and we don't want the PDB path to include the hash in it. // - wasm32-unknown-emscripten executables: When using emscripten, the path to the // .wasm file is embedded in the .js file, so we don't want the hash in there. // // This is only done for local packages, as we don't expect to export // dependencies. // // The __CARGO_DEFAULT_LIB_METADATA env var is used to override this to // force metadata in the hash. This is only used for building libstd. For // example, if libstd is placed in a common location, we don't want a file // named /usr/lib/libstd.so which could conflict with other rustc // installs. In addition it prevents accidentally loading a libstd of a // different compiler at runtime. // See https://github.com/rust-lang/cargo/issues/3005 let short_name = bcx.target_data.short_name(&unit.kind); if (unit.target.is_dylib() || unit.target.is_cdylib() || (unit.target.is_executable() && short_name == "wasm32-unknown-emscripten") || (unit.target.is_executable() && short_name.contains("msvc"))) && unit.pkg.package_id().source_id().is_path() && bcx.gctx.get_env("__CARGO_DEFAULT_LIB_METADATA").is_err() { return false; } true } cargo-0.86.0/src/cargo/core/compiler/build_runner/mod.rs000064400000000000000000000711771046102023000212700ustar 00000000000000//! [`BuildRunner`] is the mutable state used during the build process. use std::collections::{BTreeSet, HashMap, HashSet}; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; use crate::core::compiler::compilation::{self, UnitOutput}; use crate::core::compiler::{self, artifact, Unit}; use crate::core::PackageId; use crate::util::cache_lock::CacheLockMode; use crate::util::errors::CargoResult; use anyhow::{bail, Context as _}; use filetime::FileTime; use itertools::Itertools; use jobserver::Client; use super::build_plan::BuildPlan; use super::custom_build::{self, BuildDeps, BuildScriptOutputs, BuildScripts}; use super::fingerprint::{Checksum, Fingerprint}; use super::job_queue::JobQueue; use super::layout::Layout; use super::lto::Lto; use super::unit_graph::UnitDep; use super::{ BuildContext, Compilation, CompileKind, CompileMode, Executor, FileFlavor, RustDocFingerprint, }; mod compilation_files; use self::compilation_files::CompilationFiles; pub use self::compilation_files::{Metadata, OutputFile, UnitHash}; /// Collection of all the stuff that is needed to perform a build. /// /// Different from the [`BuildContext`], `Context` is a _mutable_ state used /// throughout the entire build process. Everything is coordinated through this. /// /// [`BuildContext`]: crate::core::compiler::BuildContext pub struct BuildRunner<'a, 'gctx> { /// Mostly static information about the build task. pub bcx: &'a BuildContext<'a, 'gctx>, /// A large collection of information about the result of the entire compilation. pub compilation: Compilation<'gctx>, /// Output from build scripts, updated after each build script runs. pub build_script_outputs: Arc>, /// Dependencies (like rerun-if-changed) declared by a build script. /// This is *only* populated from the output from previous runs. /// If the build script hasn't ever been run, then it must be run. pub build_explicit_deps: HashMap, /// Fingerprints used to detect if a unit is out-of-date. pub fingerprints: HashMap>, /// Cache of file mtimes to reduce filesystem hits. pub mtime_cache: HashMap, /// Cache of file checksums to reduce filesystem reads. pub checksum_cache: HashMap, /// A set used to track which units have been compiled. /// A unit may appear in the job graph multiple times as a dependency of /// multiple packages, but it only needs to run once. pub compiled: HashSet, /// Linking information for each `Unit`. /// See `build_map` for details. pub build_scripts: HashMap>, /// Job server client to manage concurrency with other processes. pub jobserver: Client, /// "Primary" packages are the ones the user selected on the command-line /// with `-p` flags. If no flags are specified, then it is the defaults /// based on the current directory and the default workspace members. primary_packages: HashSet, /// An abstraction of the files and directories that will be generated by /// the compilation. This is `None` until after `unit_dependencies` has /// been computed. files: Option>, /// A set of units which are compiling rlibs and are expected to produce /// metadata files in addition to the rlib itself. rmeta_required: HashSet, /// Map of the LTO-status of each unit. This indicates what sort of /// compilation is happening (only object, only bitcode, both, etc), and is /// precalculated early on. pub lto: HashMap, /// Map of Doc/Docscrape units to metadata for their -Cmetadata flag. /// See `Context::find_metadata_units` for more details. pub metadata_for_doc_units: HashMap, /// Set of metadata of Docscrape units that fail before completion, e.g. /// because the target has a type error. This is in an Arc> /// because it is continuously updated as the job progresses. pub failed_scrape_units: Arc>>, } impl<'a, 'gctx> BuildRunner<'a, 'gctx> { pub fn new(bcx: &'a BuildContext<'a, 'gctx>) -> CargoResult { // Load up the jobserver that we'll use to manage our parallelism. This // is the same as the GNU make implementation of a jobserver, and // intentionally so! It's hoped that we can interact with GNU make and // all share the same jobserver. // // Note that if we don't have a jobserver in our environment then we // create our own, and we create it with `n` tokens, but immediately // acquire one, because one token is ourself, a running process. let jobserver = match bcx.gctx.jobserver_from_env() { Some(c) => c.clone(), None => { let client = Client::new(bcx.jobs() as usize).context("failed to create jobserver")?; client.acquire_raw()?; client } }; Ok(Self { bcx, compilation: Compilation::new(bcx)?, build_script_outputs: Arc::new(Mutex::new(BuildScriptOutputs::default())), fingerprints: HashMap::new(), mtime_cache: HashMap::new(), checksum_cache: HashMap::new(), compiled: HashSet::new(), build_scripts: HashMap::new(), build_explicit_deps: HashMap::new(), jobserver, primary_packages: HashSet::new(), files: None, rmeta_required: HashSet::new(), lto: HashMap::new(), metadata_for_doc_units: HashMap::new(), failed_scrape_units: Arc::new(Mutex::new(HashSet::new())), }) } /// Dry-run the compilation without actually running it. /// /// This is expected to collect information like the location of output artifacts. /// Please keep in sync with non-compilation part in [`BuildRunner::compile`]. pub fn dry_run(mut self) -> CargoResult> { let _lock = self .bcx .gctx .acquire_package_cache_lock(CacheLockMode::Shared)?; self.lto = super::lto::generate(self.bcx)?; self.prepare_units()?; self.prepare()?; self.check_collisions()?; for unit in &self.bcx.roots { self.collect_tests_and_executables(unit)?; } Ok(self.compilation) } /// Starts compilation, waits for it to finish, and returns information /// about the result of compilation. /// /// See [`ops::cargo_compile`] for a higher-level view of the compile process. /// /// [`ops::cargo_compile`]: crate::ops::cargo_compile #[tracing::instrument(skip_all)] pub fn compile(mut self, exec: &Arc) -> CargoResult> { // A shared lock is held during the duration of the build since rustc // needs to read from the `src` cache, and we don't want other // commands modifying the `src` cache while it is running. let _lock = self .bcx .gctx .acquire_package_cache_lock(CacheLockMode::Shared)?; let mut queue = JobQueue::new(self.bcx); let mut plan = BuildPlan::new(); let build_plan = self.bcx.build_config.build_plan; self.lto = super::lto::generate(self.bcx)?; self.prepare_units()?; self.prepare()?; custom_build::build_map(&mut self)?; self.check_collisions()?; self.compute_metadata_for_doc_units(); // We need to make sure that if there were any previous docs // already compiled, they were compiled with the same Rustc version that we're currently // using. Otherwise we must remove the `doc/` folder and compile again forcing a rebuild. // // This is important because the `.js`/`.html` & `.css` files that are generated by Rustc don't have // any versioning (See https://github.com/rust-lang/cargo/issues/8461). // Therefore, we can end up with weird bugs and behaviours if we mix different // versions of these files. if self.bcx.build_config.mode.is_doc() { RustDocFingerprint::check_rustdoc_fingerprint(&self)? } for unit in &self.bcx.roots { let force_rebuild = self.bcx.build_config.force_rebuild; super::compile(&mut self, &mut queue, &mut plan, unit, exec, force_rebuild)?; } // Now that we've got the full job queue and we've done all our // fingerprint analysis to determine what to run, bust all the memoized // fingerprint hashes to ensure that during the build they all get the // most up-to-date values. In theory we only need to bust hashes that // transitively depend on a dirty build script, but it shouldn't matter // that much for performance anyway. for fingerprint in self.fingerprints.values() { fingerprint.clear_memoized(); } // Now that we've figured out everything that we're going to do, do it! queue.execute(&mut self, &mut plan)?; if build_plan { plan.set_inputs(self.build_plan_inputs()?); plan.output_plan(self.bcx.gctx); } // Add `OUT_DIR` to env vars if unit has a build script. let units_with_build_script = &self .bcx .roots .iter() .filter(|unit| self.build_scripts.contains_key(unit)) .dedup_by(|x, y| x.pkg.package_id() == y.pkg.package_id()) .collect::>(); for unit in units_with_build_script { for dep in &self.bcx.unit_graph[unit] { if dep.unit.mode.is_run_custom_build() { let out_dir = self .files() .build_script_out_dir(&dep.unit) .display() .to_string(); let script_meta = self.get_run_build_script_metadata(&dep.unit); self.compilation .extra_env .entry(script_meta) .or_insert_with(Vec::new) .push(("OUT_DIR".to_string(), out_dir)); } } } // Collect the result of the build into `self.compilation`. for unit in &self.bcx.roots { self.collect_tests_and_executables(unit)?; // Collect information for `rustdoc --test`. if unit.mode.is_doc_test() { let mut unstable_opts = false; let mut args = compiler::extern_args(&self, unit, &mut unstable_opts)?; args.extend(compiler::lto_args(&self, unit)); args.extend(compiler::features_args(unit)); args.extend(compiler::check_cfg_args(unit)); let script_meta = self.find_build_script_metadata(unit); if let Some(meta) = script_meta { if let Some(output) = self.build_script_outputs.lock().unwrap().get(meta) { for cfg in &output.cfgs { args.push("--cfg".into()); args.push(cfg.into()); } for check_cfg in &output.check_cfgs { args.push("--check-cfg".into()); args.push(check_cfg.into()); } for (lt, arg) in &output.linker_args { if lt.applies_to(&unit.target) { args.push("-C".into()); args.push(format!("link-arg={}", arg).into()); } } } } args.extend(unit.rustdocflags.iter().map(Into::into)); use super::MessageFormat; let format = match self.bcx.build_config.message_format { MessageFormat::Short => "short", MessageFormat::Human => "human", MessageFormat::Json { .. } => "json", }; args.push("--error-format".into()); args.push(format.into()); self.compilation.to_doc_test.push(compilation::Doctest { unit: unit.clone(), args, unstable_opts, linker: self.compilation.target_linker(unit.kind).clone(), script_meta, env: artifact::get_env(&self, self.unit_deps(unit))?, }); } super::output_depinfo(&mut self, unit)?; } for (script_meta, output) in self.build_script_outputs.lock().unwrap().iter() { self.compilation .extra_env .entry(*script_meta) .or_insert_with(Vec::new) .extend(output.env.iter().cloned()); for dir in output.library_paths.iter() { self.compilation.native_dirs.insert(dir.clone()); } } Ok(self.compilation) } fn collect_tests_and_executables(&mut self, unit: &Unit) -> CargoResult<()> { for output in self.outputs(unit)?.iter() { if output.flavor == FileFlavor::DebugInfo || output.flavor == FileFlavor::Auxiliary { continue; } let bindst = output.bin_dst(); if unit.mode == CompileMode::Test { self.compilation .tests .push(self.unit_output(unit, &output.path)); } else if unit.target.is_executable() { self.compilation .binaries .push(self.unit_output(unit, bindst)); } else if unit.target.is_cdylib() && !self.compilation.cdylibs.iter().any(|uo| uo.unit == *unit) { self.compilation .cdylibs .push(self.unit_output(unit, bindst)); } } Ok(()) } /// Returns the executable for the specified unit (if any). pub fn get_executable(&mut self, unit: &Unit) -> CargoResult> { let is_binary = unit.target.is_executable(); let is_test = unit.mode.is_any_test(); if !unit.mode.generates_executable() || !(is_binary || is_test) { return Ok(None); } Ok(self .outputs(unit)? .iter() .find(|o| o.flavor == FileFlavor::Normal) .map(|output| output.bin_dst().clone())) } #[tracing::instrument(skip_all)] pub fn prepare_units(&mut self) -> CargoResult<()> { let dest = self.bcx.profiles.get_dir_name(); let host_layout = Layout::new(self.bcx.ws, None, &dest)?; let mut targets = HashMap::new(); for kind in self.bcx.all_kinds.iter() { if let CompileKind::Target(target) = *kind { let layout = Layout::new(self.bcx.ws, Some(target), &dest)?; targets.insert(target, layout); } } self.primary_packages .extend(self.bcx.roots.iter().map(|u| u.pkg.package_id())); self.compilation .root_crate_names .extend(self.bcx.roots.iter().map(|u| u.target.crate_name())); self.record_units_requiring_metadata(); let files = CompilationFiles::new(self, host_layout, targets); self.files = Some(files); Ok(()) } /// Prepare this context, ensuring that all filesystem directories are in /// place. #[tracing::instrument(skip_all)] pub fn prepare(&mut self) -> CargoResult<()> { self.files .as_mut() .unwrap() .host .prepare() .context("couldn't prepare build directories")?; for target in self.files.as_mut().unwrap().target.values_mut() { target .prepare() .context("couldn't prepare build directories")?; } let files = self.files.as_ref().unwrap(); for &kind in self.bcx.all_kinds.iter() { let layout = files.layout(kind); self.compilation .root_output .insert(kind, layout.dest().to_path_buf()); self.compilation .deps_output .insert(kind, layout.deps().to_path_buf()); } Ok(()) } pub fn files(&self) -> &CompilationFiles<'a, 'gctx> { self.files.as_ref().unwrap() } /// Returns the filenames that the given unit will generate. pub fn outputs(&self, unit: &Unit) -> CargoResult>> { self.files.as_ref().unwrap().outputs(unit, self.bcx) } /// Direct dependencies for the given unit. pub fn unit_deps(&self, unit: &Unit) -> &[UnitDep] { &self.bcx.unit_graph[unit] } /// Returns the `RunCustomBuild` Unit associated with the given Unit. /// /// If the package does not have a build script, this returns None. pub fn find_build_script_unit(&self, unit: &Unit) -> Option { if unit.mode.is_run_custom_build() { return Some(unit.clone()); } self.bcx.unit_graph[unit] .iter() .find(|unit_dep| { unit_dep.unit.mode.is_run_custom_build() && unit_dep.unit.pkg.package_id() == unit.pkg.package_id() }) .map(|unit_dep| unit_dep.unit.clone()) } /// Returns the metadata hash for the `RunCustomBuild` Unit associated with /// the given unit. /// /// If the package does not have a build script, this returns None. pub fn find_build_script_metadata(&self, unit: &Unit) -> Option { let script_unit = self.find_build_script_unit(unit)?; Some(self.get_run_build_script_metadata(&script_unit)) } /// Returns the metadata hash for a `RunCustomBuild` unit. pub fn get_run_build_script_metadata(&self, unit: &Unit) -> UnitHash { assert!(unit.mode.is_run_custom_build()); self.files().metadata(unit).unit_id() } pub fn is_primary_package(&self, unit: &Unit) -> bool { self.primary_packages.contains(&unit.pkg.package_id()) } /// Returns the list of filenames read by cargo to generate the [`BuildContext`] /// (all `Cargo.toml`, etc.). pub fn build_plan_inputs(&self) -> CargoResult> { // Keep sorted for consistency. let mut inputs = BTreeSet::new(); // Note: dev-deps are skipped if they are not present in the unit graph. for unit in self.bcx.unit_graph.keys() { inputs.insert(unit.pkg.manifest_path().to_path_buf()); } Ok(inputs.into_iter().collect()) } /// Returns a [`UnitOutput`] which represents some information about the /// output of a unit. pub fn unit_output(&self, unit: &Unit, path: &Path) -> UnitOutput { let script_meta = self.find_build_script_metadata(unit); UnitOutput { unit: unit.clone(), path: path.to_path_buf(), script_meta, } } /// Check if any output file name collision happens. /// See for more. #[tracing::instrument(skip_all)] fn check_collisions(&self) -> CargoResult<()> { let mut output_collisions = HashMap::new(); let describe_collision = |unit: &Unit, other_unit: &Unit, path: &PathBuf| -> String { format!( "The {} target `{}` in package `{}` has the same output \ filename as the {} target `{}` in package `{}`.\n\ Colliding filename is: {}\n", unit.target.kind().description(), unit.target.name(), unit.pkg.package_id(), other_unit.target.kind().description(), other_unit.target.name(), other_unit.pkg.package_id(), path.display() ) }; let suggestion = "Consider changing their names to be unique or compiling them separately.\n\ This may become a hard error in the future; see \ ."; let rustdoc_suggestion = "This is a known bug where multiple crates with the same name use\n\ the same path; see ."; let report_collision = |unit: &Unit, other_unit: &Unit, path: &PathBuf, suggestion: &str| -> CargoResult<()> { if unit.target.name() == other_unit.target.name() { self.bcx.gctx.shell().warn(format!( "output filename collision.\n\ {}\ The targets should have unique names.\n\ {}", describe_collision(unit, other_unit, path), suggestion )) } else { self.bcx.gctx.shell().warn(format!( "output filename collision.\n\ {}\ The output filenames should be unique.\n\ {}\n\ If this looks unexpected, it may be a bug in Cargo. Please file a bug report at\n\ https://github.com/rust-lang/cargo/issues/ with as much information as you\n\ can provide.\n\ cargo {} running on `{}` target `{}`\n\ First unit: {:?}\n\ Second unit: {:?}", describe_collision(unit, other_unit, path), suggestion, crate::version(), self.bcx.host_triple(), self.bcx.target_data.short_name(&unit.kind), unit, other_unit)) } }; fn doc_collision_error(unit: &Unit, other_unit: &Unit) -> CargoResult<()> { bail!( "document output filename collision\n\ The {} `{}` in package `{}` has the same name as the {} `{}` in package `{}`.\n\ Only one may be documented at once since they output to the same path.\n\ Consider documenting only one, renaming one, \ or marking one with `doc = false` in Cargo.toml.", unit.target.kind().description(), unit.target.name(), unit.pkg, other_unit.target.kind().description(), other_unit.target.name(), other_unit.pkg, ); } let mut keys = self .bcx .unit_graph .keys() .filter(|unit| !unit.mode.is_run_custom_build()) .collect::>(); // Sort for consistent error messages. keys.sort_unstable(); // These are kept separate to retain compatibility with older // versions, which generated an error when there was a duplicate lib // or bin (but the old code did not check bin<->lib collisions). To // retain backwards compatibility, this only generates an error for // duplicate libs or duplicate bins (but not both). Ideally this // shouldn't be here, but since there isn't a complete workaround, // yet, this retains the old behavior. let mut doc_libs = HashMap::new(); let mut doc_bins = HashMap::new(); for unit in keys { if unit.mode.is_doc() && self.is_primary_package(unit) { // These situations have been an error since before 1.0, so it // is not a warning like the other situations. if unit.target.is_lib() { if let Some(prev) = doc_libs.insert((unit.target.crate_name(), unit.kind), unit) { doc_collision_error(unit, prev)?; } } else if let Some(prev) = doc_bins.insert((unit.target.crate_name(), unit.kind), unit) { doc_collision_error(unit, prev)?; } } for output in self.outputs(unit)?.iter() { if let Some(other_unit) = output_collisions.insert(output.path.clone(), unit) { if unit.mode.is_doc() { // See https://github.com/rust-lang/rust/issues/56169 // and https://github.com/rust-lang/rust/issues/61378 report_collision(unit, other_unit, &output.path, rustdoc_suggestion)?; } else { report_collision(unit, other_unit, &output.path, suggestion)?; } } if let Some(hardlink) = output.hardlink.as_ref() { if let Some(other_unit) = output_collisions.insert(hardlink.clone(), unit) { report_collision(unit, other_unit, hardlink, suggestion)?; } } if let Some(ref export_path) = output.export_path { if let Some(other_unit) = output_collisions.insert(export_path.clone(), unit) { self.bcx.gctx.shell().warn(format!( "`--artifact-dir` filename collision.\n\ {}\ The exported filenames should be unique.\n\ {}", describe_collision(unit, other_unit, export_path), suggestion ))?; } } } } Ok(()) } /// Records the list of units which are required to emit metadata. /// /// Units which depend only on the metadata of others requires the others to /// actually produce metadata, so we'll record that here. fn record_units_requiring_metadata(&mut self) { for (key, deps) in self.bcx.unit_graph.iter() { for dep in deps { if self.only_requires_rmeta(key, &dep.unit) { self.rmeta_required.insert(dep.unit.clone()); } } } } /// Returns whether when `parent` depends on `dep` if it only requires the /// metadata file from `dep`. pub fn only_requires_rmeta(&self, parent: &Unit, dep: &Unit) -> bool { // We're only a candidate for requiring an `rmeta` file if we // ourselves are building an rlib, !parent.requires_upstream_objects() && parent.mode == CompileMode::Build // Our dependency must also be built as an rlib, otherwise the // object code must be useful in some fashion && !dep.requires_upstream_objects() && dep.mode == CompileMode::Build } /// Returns whether when `unit` is built whether it should emit metadata as /// well because some compilations rely on that. pub fn rmeta_required(&self, unit: &Unit) -> bool { self.rmeta_required.contains(unit) } /// Finds metadata for Doc/Docscrape units. /// /// rustdoc needs a -Cmetadata flag in order to recognize StableCrateIds that refer to /// items in the crate being documented. The -Cmetadata flag used by reverse-dependencies /// will be the metadata of the Cargo unit that generated the current library's rmeta file, /// which should be a Check unit. /// /// If the current crate has reverse-dependencies, such a Check unit should exist, and so /// we use that crate's metadata. If not, we use the crate's Doc unit so at least examples /// scraped from the current crate can be used when documenting the current crate. #[tracing::instrument(skip_all)] pub fn compute_metadata_for_doc_units(&mut self) { for unit in self.bcx.unit_graph.keys() { if !unit.mode.is_doc() && !unit.mode.is_doc_scrape() { continue; } let matching_units = self .bcx .unit_graph .keys() .filter(|other| { unit.pkg == other.pkg && unit.target == other.target && !other.mode.is_doc_scrape() }) .collect::>(); let metadata_unit = matching_units .iter() .find(|other| other.mode.is_check()) .or_else(|| matching_units.iter().find(|other| other.mode.is_doc())) .unwrap_or(&unit); self.metadata_for_doc_units .insert(unit.clone(), self.files().metadata(metadata_unit)); } } } cargo-0.86.0/src/cargo/core/compiler/compilation.rs000064400000000000000000000440451046102023000203310ustar 00000000000000//! Type definitions for the result of a compilation. use std::collections::{BTreeSet, HashMap}; use std::ffi::{OsStr, OsString}; use std::path::PathBuf; use cargo_platform::CfgExpr; use cargo_util::{paths, ProcessBuilder}; use crate::core::compiler::apply_env_config; use crate::core::compiler::BuildContext; use crate::core::compiler::{CompileKind, Unit, UnitHash}; use crate::core::Package; use crate::util::{context, CargoResult, GlobalContext}; /// Represents the kind of process we are creating. #[derive(Debug)] enum ToolKind { /// See [`Compilation::rustc_process`]. Rustc, /// See [`Compilation::rustdoc_process`]. Rustdoc, /// See [`Compilation::host_process`]. HostProcess, /// See [`Compilation::target_process`]. TargetProcess, } impl ToolKind { fn is_rustc_tool(&self) -> bool { matches!(self, ToolKind::Rustc | ToolKind::Rustdoc) } } /// Structure with enough information to run `rustdoc --test`. pub struct Doctest { /// What's being doctested pub unit: Unit, /// Arguments needed to pass to rustdoc to run this test. pub args: Vec, /// Whether or not -Zunstable-options is needed. pub unstable_opts: bool, /// The -Clinker value to use. pub linker: Option, /// The script metadata, if this unit's package has a build script. /// /// This is used for indexing [`Compilation::extra_env`]. pub script_meta: Option, /// Environment variables to set in the rustdoc process. pub env: HashMap, } /// Information about the output of a unit. #[derive(Ord, PartialOrd, Eq, PartialEq)] pub struct UnitOutput { /// The unit that generated this output. pub unit: Unit, /// Path to the unit's primary output (an executable or cdylib). pub path: PathBuf, /// The script metadata, if this unit's package has a build script. /// /// This is used for indexing [`Compilation::extra_env`]. pub script_meta: Option, } /// A structure returning the result of a compilation. pub struct Compilation<'gctx> { /// An array of all tests created during this compilation. pub tests: Vec, /// An array of all binaries created. pub binaries: Vec, /// An array of all cdylibs created. pub cdylibs: Vec, /// The crate names of the root units specified on the command-line. pub root_crate_names: Vec, /// All directories for the output of native build commands. /// /// This is currently used to drive some entries which are added to the /// `LD_LIBRARY_PATH` as appropriate. /// /// The order should be deterministic. pub native_dirs: BTreeSet, /// Root output directory (for the local package's artifacts) pub root_output: HashMap, /// Output directory for rust dependencies. /// May be for the host or for a specific target. pub deps_output: HashMap, /// The path to libstd for each target sysroot_target_libdir: HashMap, /// Extra environment variables that were passed to compilations and should /// be passed to future invocations of programs. /// /// The key is the build script metadata for uniquely identifying the /// `RunCustomBuild` unit that generated these env vars. pub extra_env: HashMap>, /// Libraries to test with rustdoc. pub to_doc_test: Vec, /// The target host triple. pub host: String, gctx: &'gctx GlobalContext, /// Rustc process to be used by default rustc_process: ProcessBuilder, /// Rustc process to be used for workspace crates instead of `rustc_process` rustc_workspace_wrapper_process: ProcessBuilder, /// Optional rustc process to be used for primary crates instead of either `rustc_process` or /// `rustc_workspace_wrapper_process` primary_rustc_process: Option, target_runners: HashMap)>>, /// The linker to use for each host or target. target_linkers: HashMap>, /// The total number of warnings emitted by the compilation. pub warning_count: usize, } impl<'gctx> Compilation<'gctx> { pub fn new<'a>(bcx: &BuildContext<'a, 'gctx>) -> CargoResult> { let rustc_process = bcx.rustc().process(); let primary_rustc_process = bcx.build_config.primary_unit_rustc.clone(); let rustc_workspace_wrapper_process = bcx.rustc().workspace_process(); Ok(Compilation { native_dirs: BTreeSet::new(), root_output: HashMap::new(), deps_output: HashMap::new(), sysroot_target_libdir: get_sysroot_target_libdir(bcx)?, tests: Vec::new(), binaries: Vec::new(), cdylibs: Vec::new(), root_crate_names: Vec::new(), extra_env: HashMap::new(), to_doc_test: Vec::new(), gctx: bcx.gctx, host: bcx.host_triple().to_string(), rustc_process, rustc_workspace_wrapper_process, primary_rustc_process, target_runners: bcx .build_config .requested_kinds .iter() .chain(Some(&CompileKind::Host)) .map(|kind| Ok((*kind, target_runner(bcx, *kind)?))) .collect::>>()?, target_linkers: bcx .build_config .requested_kinds .iter() .chain(Some(&CompileKind::Host)) .map(|kind| Ok((*kind, target_linker(bcx, *kind)?))) .collect::>>()?, warning_count: 0, }) } /// Returns a [`ProcessBuilder`] for running `rustc`. /// /// `is_primary` is true if this is a "primary package", which means it /// was selected by the user on the command-line (such as with a `-p` /// flag), see [`crate::core::compiler::BuildRunner::primary_packages`]. /// /// `is_workspace` is true if this is a workspace member. pub fn rustc_process( &self, unit: &Unit, is_primary: bool, is_workspace: bool, ) -> CargoResult { let mut rustc = if is_primary && self.primary_rustc_process.is_some() { self.primary_rustc_process.clone().unwrap() } else if is_workspace { self.rustc_workspace_wrapper_process.clone() } else { self.rustc_process.clone() }; if self.gctx.extra_verbose() { rustc.display_env_vars(); } let cmd = fill_rustc_tool_env(rustc, unit); self.fill_env(cmd, &unit.pkg, None, unit.kind, ToolKind::Rustc) } /// Returns a [`ProcessBuilder`] for running `rustdoc`. pub fn rustdoc_process( &self, unit: &Unit, script_meta: Option, ) -> CargoResult { let mut rustdoc = ProcessBuilder::new(&*self.gctx.rustdoc()?); if self.gctx.extra_verbose() { rustdoc.display_env_vars(); } let cmd = fill_rustc_tool_env(rustdoc, unit); let mut cmd = self.fill_env(cmd, &unit.pkg, script_meta, unit.kind, ToolKind::Rustdoc)?; cmd.retry_with_argfile(true); unit.target.edition().cmd_edition_arg(&mut cmd); for crate_type in unit.target.rustc_crate_types() { cmd.arg("--crate-type").arg(crate_type.as_str()); } Ok(cmd) } /// Returns a [`ProcessBuilder`] appropriate for running a process for the /// host platform. /// /// This is currently only used for running build scripts. If you use this /// for anything else, please be extra careful on how environment /// variables are set! pub fn host_process>( &self, cmd: T, pkg: &Package, ) -> CargoResult { self.fill_env( ProcessBuilder::new(cmd), pkg, None, CompileKind::Host, ToolKind::HostProcess, ) } pub fn target_runner(&self, kind: CompileKind) -> Option<&(PathBuf, Vec)> { self.target_runners.get(&kind).and_then(|x| x.as_ref()) } /// Gets the user-specified linker for a particular host or target. pub fn target_linker(&self, kind: CompileKind) -> Option { self.target_linkers.get(&kind).and_then(|x| x.clone()) } /// Returns a [`ProcessBuilder`] appropriate for running a process for the /// target platform. This is typically used for `cargo run` and `cargo /// test`. /// /// `script_meta` is the metadata for the `RunCustomBuild` unit that this /// unit used for its build script. Use `None` if the package did not have /// a build script. pub fn target_process>( &self, cmd: T, kind: CompileKind, pkg: &Package, script_meta: Option, ) -> CargoResult { let builder = if let Some((runner, args)) = self.target_runner(kind) { let mut builder = ProcessBuilder::new(runner); builder.args(args); builder.arg(cmd); builder } else { ProcessBuilder::new(cmd) }; let tool_kind = ToolKind::TargetProcess; let mut builder = self.fill_env(builder, pkg, script_meta, kind, tool_kind)?; if let Some(client) = self.gctx.jobserver_from_env() { builder.inherit_jobserver(client); } Ok(builder) } /// Prepares a new process with an appropriate environment to run against /// the artifacts produced by the build process. /// /// The package argument is also used to configure environment variables as /// well as the working directory of the child process. fn fill_env( &self, mut cmd: ProcessBuilder, pkg: &Package, script_meta: Option, kind: CompileKind, tool_kind: ToolKind, ) -> CargoResult { let mut search_path = Vec::new(); if tool_kind.is_rustc_tool() { if matches!(tool_kind, ToolKind::Rustdoc) { // HACK: `rustdoc --test` not only compiles but executes doctests. // Ideally only execution phase should have search paths appended, // so the executions can find native libs just like other tests. // However, there is no way to separate these two phase, so this // hack is added for both phases. // TODO: handle doctest-xcompile search_path.extend(super::filter_dynamic_search_path( self.native_dirs.iter(), &self.root_output[&CompileKind::Host], )); } search_path.push(self.deps_output[&CompileKind::Host].clone()); } else { search_path.extend(super::filter_dynamic_search_path( self.native_dirs.iter(), &self.root_output[&kind], )); search_path.push(self.deps_output[&kind].clone()); search_path.push(self.root_output[&kind].clone()); // For build-std, we don't want to accidentally pull in any shared // libs from the sysroot that ships with rustc. This may not be // required (at least I cannot craft a situation where it // matters), but is here to be safe. if self.gctx.cli_unstable().build_std.is_none() || // Proc macros dynamically link to std, so set it anyway. pkg.proc_macro() { search_path.push(self.sysroot_target_libdir[&kind].clone()); } } let dylib_path = paths::dylib_path(); let dylib_path_is_empty = dylib_path.is_empty(); if dylib_path.starts_with(&search_path) { search_path = dylib_path; } else { search_path.extend(dylib_path.into_iter()); } if cfg!(target_os = "macos") && dylib_path_is_empty { // These are the defaults when DYLD_FALLBACK_LIBRARY_PATH isn't // set or set to an empty string. Since Cargo is explicitly setting // the value, make sure the defaults still work. if let Some(home) = self.gctx.get_env_os("HOME") { search_path.push(PathBuf::from(home).join("lib")); } search_path.push(PathBuf::from("/usr/local/lib")); search_path.push(PathBuf::from("/usr/lib")); } let search_path = paths::join_paths(&search_path, paths::dylib_path_envvar())?; cmd.env(paths::dylib_path_envvar(), &search_path); if let Some(meta) = script_meta { if let Some(env) = self.extra_env.get(&meta) { for (k, v) in env { cmd.env(k, v); } } } let cargo_exe = self.gctx.cargo_exe()?; cmd.env(crate::CARGO_ENV, cargo_exe); // When adding new environment variables depending on // crate properties which might require rebuild upon change // consider adding the corresponding properties to the hash // in BuildContext::target_metadata() cmd.env("CARGO_MANIFEST_DIR", pkg.root()) .env("CARGO_MANIFEST_PATH", pkg.manifest_path()) .env("CARGO_PKG_VERSION_MAJOR", &pkg.version().major.to_string()) .env("CARGO_PKG_VERSION_MINOR", &pkg.version().minor.to_string()) .env("CARGO_PKG_VERSION_PATCH", &pkg.version().patch.to_string()) .env("CARGO_PKG_VERSION_PRE", pkg.version().pre.as_str()) .env("CARGO_PKG_VERSION", &pkg.version().to_string()) .env("CARGO_PKG_NAME", &*pkg.name()); for (key, value) in pkg.manifest().metadata().env_vars() { cmd.env(key, value.as_ref()); } cmd.cwd(pkg.root()); apply_env_config(self.gctx, &mut cmd)?; Ok(cmd) } } /// Prepares a `rustc_tool` process with additional environment variables /// that are only relevant in a context that has a unit fn fill_rustc_tool_env(mut cmd: ProcessBuilder, unit: &Unit) -> ProcessBuilder { if unit.target.is_executable() { let name = unit .target .binary_filename() .unwrap_or(unit.target.name().to_string()); cmd.env("CARGO_BIN_NAME", name); } cmd.env("CARGO_CRATE_NAME", unit.target.crate_name()); cmd } fn get_sysroot_target_libdir( bcx: &BuildContext<'_, '_>, ) -> CargoResult> { bcx.all_kinds .iter() .map(|&kind| { let Some(info) = bcx.target_data.get_info(kind) else { let target = match kind { CompileKind::Host => "host".to_owned(), CompileKind::Target(s) => s.short_name().to_owned(), }; let dependency = bcx .unit_graph .iter() .find_map(|(u, _)| (u.kind == kind).then_some(u.pkg.summary().package_id())) .unwrap(); anyhow::bail!( "could not find specification for target `{target}`.\n \ Dependency `{dependency}` requires to build for target `{target}`." ) }; Ok((kind, info.sysroot_target_libdir.clone())) }) .collect() } fn target_runner( bcx: &BuildContext<'_, '_>, kind: CompileKind, ) -> CargoResult)>> { let target = bcx.target_data.short_name(&kind); // try target.{}.runner let key = format!("target.{}.runner", target); if let Some(v) = bcx.gctx.get::>(&key)? { let path = v.path.resolve_program(bcx.gctx); return Ok(Some((path, v.args))); } // try target.'cfg(...)'.runner let target_cfg = bcx.target_data.info(kind).cfg(); let mut cfgs = bcx .gctx .target_cfgs()? .iter() .filter_map(|(key, cfg)| cfg.runner.as_ref().map(|runner| (key, runner))) .filter(|(key, _runner)| CfgExpr::matches_key(key, target_cfg)); let matching_runner = cfgs.next(); if let Some((key, runner)) = cfgs.next() { anyhow::bail!( "several matching instances of `target.'cfg(..)'.runner` in configurations\n\ first match `{}` located in {}\n\ second match `{}` located in {}", matching_runner.unwrap().0, matching_runner.unwrap().1.definition, key, runner.definition ); } Ok(matching_runner.map(|(_k, runner)| { ( runner.val.path.clone().resolve_program(bcx.gctx), runner.val.args.clone(), ) })) } /// Gets the user-specified linker for a particular host or target from the configuration. fn target_linker(bcx: &BuildContext<'_, '_>, kind: CompileKind) -> CargoResult> { // Try host.linker and target.{}.linker. if let Some(path) = bcx .target_data .target_config(kind) .linker .as_ref() .map(|l| l.val.clone().resolve_program(bcx.gctx)) { return Ok(Some(path)); } // Try target.'cfg(...)'.linker. let target_cfg = bcx.target_data.info(kind).cfg(); let mut cfgs = bcx .gctx .target_cfgs()? .iter() .filter_map(|(key, cfg)| cfg.linker.as_ref().map(|linker| (key, linker))) .filter(|(key, _linker)| CfgExpr::matches_key(key, target_cfg)); let matching_linker = cfgs.next(); if let Some((key, linker)) = cfgs.next() { anyhow::bail!( "several matching instances of `target.'cfg(..)'.linker` in configurations\n\ first match `{}` located in {}\n\ second match `{}` located in {}", matching_linker.unwrap().0, matching_linker.unwrap().1.definition, key, linker.definition ); } Ok(matching_linker.map(|(_k, linker)| linker.val.clone().resolve_program(bcx.gctx))) } cargo-0.86.0/src/cargo/core/compiler/compile_kind.rs000064400000000000000000000166051046102023000204510ustar 00000000000000//! Type definitions for cross-compilation. use crate::core::Target; use crate::util::errors::CargoResult; use crate::util::interning::InternedString; use crate::util::{try_canonicalize, GlobalContext, StableHasher}; use anyhow::Context as _; use serde::Serialize; use std::collections::BTreeSet; use std::fs; use std::hash::{Hash, Hasher}; use std::path::Path; /// Indicator for how a unit is being compiled. /// /// This is used primarily for organizing cross compilations vs host /// compilations, where cross compilations happen at the request of `--target` /// and host compilations happen for things like build scripts and procedural /// macros. #[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, PartialOrd, Ord)] pub enum CompileKind { /// Attached to a unit that is compiled for the "host" system or otherwise /// is compiled without a `--target` flag. This is used for procedural /// macros and build scripts, or if the `--target` flag isn't passed. Host, /// Attached to a unit to be compiled for a particular target. This is used /// for units when the `--target` flag is passed. Target(CompileTarget), } impl CompileKind { pub fn is_host(&self) -> bool { matches!(self, CompileKind::Host) } pub fn for_target(self, target: &Target) -> CompileKind { // Once we start compiling for the `Host` kind we continue doing so, but // if we are a `Target` kind and then we start compiling for a target // that needs to be on the host we lift ourselves up to `Host`. match self { CompileKind::Host => CompileKind::Host, CompileKind::Target(_) if target.for_host() => CompileKind::Host, CompileKind::Target(n) => CompileKind::Target(n), } } /// Creates a new list of `CompileKind` based on the requested list of /// targets. /// /// If no targets are given then this returns a single-element vector with /// `CompileKind::Host`. pub fn from_requested_targets( gctx: &GlobalContext, targets: &[String], ) -> CargoResult> { let dedup = |targets: &[String]| { Ok(targets .iter() .map(|value| Ok(CompileKind::Target(CompileTarget::new(value)?))) // First collect into a set to deduplicate any `--target` passed // more than once... .collect::>>()? // ... then generate a flat list for everything else to use. .into_iter() .collect()) }; if !targets.is_empty() { return dedup(targets); } let kinds = match &gctx.build_config()?.target { None => Ok(vec![CompileKind::Host]), Some(build_target_config) => dedup(&build_target_config.values(gctx)?), }; kinds } /// Hash used for fingerprinting. /// /// Metadata hashing uses the normal Hash trait, which does not /// differentiate on `.json` file contents. The fingerprint hash does /// check the contents. pub fn fingerprint_hash(&self) -> u64 { match self { CompileKind::Host => 0, CompileKind::Target(target) => target.fingerprint_hash(), } } } impl serde::ser::Serialize for CompileKind { fn serialize(&self, s: S) -> Result where S: serde::ser::Serializer, { match self { CompileKind::Host => None::<&str>.serialize(s), CompileKind::Target(t) => Some(t.name).serialize(s), } } } /// Abstraction for the representation of a compilation target that Cargo has. /// /// Compilation targets are one of two things right now: /// /// 1. A raw target string, like `x86_64-unknown-linux-gnu`. /// 2. The path to a JSON file, such as `/path/to/my-target.json`. /// /// Raw target strings are typically dictated by `rustc` itself and represent /// built-in targets. Custom JSON files are somewhat unstable, but supported /// here in Cargo. Note that for JSON target files this `CompileTarget` stores a /// full canonicalized path to the target. /// /// The main reason for this existence is to handle JSON target files where when /// we call rustc we pass full paths but when we use it for Cargo's purposes /// like naming directories or looking up configuration keys we only check the /// file stem of JSON target files. For built-in rustc targets this is just an /// uninterpreted string basically. #[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, PartialOrd, Ord, Serialize)] pub struct CompileTarget { name: InternedString, } impl CompileTarget { pub fn new(name: &str) -> CargoResult { let name = name.trim(); if name.is_empty() { anyhow::bail!("target was empty"); } if !name.ends_with(".json") { return Ok(CompileTarget { name: name.into() }); } // If `name` ends in `.json` then it's likely a custom target // specification. Canonicalize the path to ensure that different builds // with different paths always produce the same result. let path = try_canonicalize(Path::new(name)) .with_context(|| format!("target path {:?} is not a valid file", name))?; let name = path .into_os_string() .into_string() .map_err(|_| anyhow::format_err!("target path is not valid unicode"))?; Ok(CompileTarget { name: name.into() }) } /// Returns the full unqualified name of this target, suitable for passing /// to `rustc` directly. /// /// Typically this is pretty much the same as `short_name`, but for the case /// of JSON target files this will be a full canonicalized path name for the /// current filesystem. pub fn rustc_target(&self) -> InternedString { self.name } /// Returns a "short" version of the target name suitable for usage within /// Cargo for configuration and such. /// /// This is typically the same as `rustc_target`, or the full name, but for /// JSON target files this returns just the file stem (e.g. `foo` out of /// `foo.json`) instead of the full path. pub fn short_name(&self) -> &str { // Flexible target specifications often point at json files, so if it // looks like we've got one of those just use the file stem (the file // name without ".json") as a short name for this target. Note that the // `unwrap()` here should never trigger since we have a nonempty name // and it starts as utf-8 so it's always utf-8 if self.name.ends_with(".json") { Path::new(&self.name).file_stem().unwrap().to_str().unwrap() } else { &self.name } } /// See [`CompileKind::fingerprint_hash`]. pub fn fingerprint_hash(&self) -> u64 { let mut hasher = StableHasher::new(); match self .name .ends_with(".json") .then(|| fs::read_to_string(self.name)) { Some(Ok(contents)) => { // This may have some performance concerns, since it is called // fairly often. If that ever seems worth fixing, consider // embedding this in `CompileTarget`. contents.hash(&mut hasher); } _ => { self.name.hash(&mut hasher); } } Hasher::finish(&hasher) } } cargo-0.86.0/src/cargo/core/compiler/crate_type.rs000064400000000000000000000066331046102023000201530ustar 00000000000000use std::fmt; /// Types of the output artifact that the compiler emits. /// Usually distributable or linkable either statically or dynamically. /// /// See . #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum CrateType { Bin, Lib, Rlib, Dylib, Cdylib, Staticlib, ProcMacro, Other(String), } impl CrateType { pub fn as_str(&self) -> &str { match self { CrateType::Bin => "bin", CrateType::Lib => "lib", CrateType::Rlib => "rlib", CrateType::Dylib => "dylib", CrateType::Cdylib => "cdylib", CrateType::Staticlib => "staticlib", CrateType::ProcMacro => "proc-macro", CrateType::Other(s) => s, } } pub fn can_lto(&self) -> bool { match self { CrateType::Bin | CrateType::Staticlib | CrateType::Cdylib => true, CrateType::Lib | CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro | CrateType::Other(..) => false, } } pub fn is_linkable(&self) -> bool { match self { CrateType::Lib | CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true, CrateType::Bin | CrateType::Cdylib | CrateType::Staticlib | CrateType::Other(..) => { false } } } pub fn is_dynamic(&self) -> bool { match self { CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => true, CrateType::Lib | CrateType::Rlib | CrateType::Bin | CrateType::Staticlib | CrateType::Other(..) => false, } } /// Returns whether production of this crate type requires the object files /// from dependencies to be available. /// /// See also [`TargetKind::requires_upstream_objects`]. /// /// [`TargetKind::requires_upstream_objects`]: crate::core::manifest::TargetKind::requires_upstream_objects pub fn requires_upstream_objects(&self) -> bool { // "lib" == "rlib" and is a compilation that doesn't actually // require upstream object files to exist, only upstream metadata // files. As a result, it doesn't require upstream artifacts !matches!(self, CrateType::Lib | CrateType::Rlib) // Everything else, however, is some form of "linkable output" or // something that requires upstream object files. } } impl fmt::Display for CrateType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.as_str().fmt(f) } } impl<'a> From<&'a String> for CrateType { fn from(s: &'a String) -> Self { match s.as_str() { "bin" => CrateType::Bin, "lib" => CrateType::Lib, "rlib" => CrateType::Rlib, "dylib" => CrateType::Dylib, "cdylib" => CrateType::Cdylib, "staticlib" => CrateType::Staticlib, "procmacro" => CrateType::ProcMacro, _ => CrateType::Other(s.clone()), } } } impl fmt::Debug for CrateType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.to_string().fmt(f) } } impl serde::Serialize for CrateType { fn serialize(&self, s: S) -> Result where S: serde::ser::Serializer, { self.to_string().serialize(s) } } cargo-0.86.0/src/cargo/core/compiler/custom_build.rs000064400000000000000000001542241046102023000205050ustar 00000000000000//! How to execute a build script and parse its output. //! //! ## Preparing a build script run //! //! A [build script] is an optional Rust script Cargo will run before building //! your package. As of this writing, two kinds of special [`Unit`]s will be //! constructed when there is a build script in a package. //! //! * Build script compilation --- This unit is generally the same as units //! that would compile other Cargo targets. It will recursively creates units //! of its dependencies. One biggest difference is that the [`Unit`] of //! compiling a build script is flagged as [`TargetKind::CustomBuild`]. //! * Build script execution --- During the construction of the [`UnitGraph`], //! Cargo inserts a [`Unit`] with [`CompileMode::RunCustomBuild`]. This unit //! depends on the unit of compiling the associated build script, to ensure //! the executable is available before running. The [`Work`] of running the //! build script is prepared in the function [`prepare`]. //! //! ## Running a build script //! //! When running a build script, Cargo is aware of the progress and the result //! of a build script. Standard output is the chosen interprocess communication //! between Cargo and build script processes. A set of strings is defined for //! that purpose. These strings, a.k.a. instructions, are interpreted by //! [`BuildOutput::parse`] and stored in [`BuildRunner::build_script_outputs`]. //! The entire execution work is constructed by [`build_work`]. //! //! [build script]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html //! [`TargetKind::CustomBuild`]: crate::core::manifest::TargetKind::CustomBuild //! [`UnitGraph`]: super::unit_graph::UnitGraph //! [`CompileMode::RunCustomBuild`]: super::CompileMode //! [instructions]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script use super::{fingerprint, BuildRunner, Job, Unit, Work}; use crate::core::compiler::artifact; use crate::core::compiler::build_runner::UnitHash; use crate::core::compiler::fingerprint::DirtyReason; use crate::core::compiler::job_queue::JobState; use crate::core::{profiles::ProfileRoot, PackageId, Target}; use crate::util::errors::CargoResult; use crate::util::internal; use crate::util::machine_message::{self, Message}; use anyhow::{bail, Context as _}; use cargo_platform::Cfg; use cargo_util::paths; use cargo_util_schemas::manifest::RustVersion; use std::collections::hash_map::{Entry, HashMap}; use std::collections::{BTreeSet, HashSet}; use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; use std::sync::{Arc, Mutex}; /// A build script instruction that tells Cargo to display an error after the /// build script has finished running. Read [the doc] for more. /// /// [the doc]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#cargo-error const CARGO_ERROR_SYNTAX: &str = "cargo::error="; /// Deprecated: A build script instruction that tells Cargo to display a warning after the /// build script has finished running. Read [the doc] for more. /// /// [the doc]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#cargo-warning const OLD_CARGO_WARNING_SYNTAX: &str = "cargo:warning="; /// A build script instruction that tells Cargo to display a warning after the /// build script has finished running. Read [the doc] for more. /// /// [the doc]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#cargo-warning const NEW_CARGO_WARNING_SYNTAX: &str = "cargo::warning="; #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum Severity { Error, Warning, } pub type LogMessage = (Severity, String); /// Contains the parsed output of a custom build script. #[derive(Clone, Debug, Hash, Default, PartialEq, Eq, PartialOrd, Ord)] pub struct BuildOutput { /// Paths to pass to rustc with the `-L` flag. pub library_paths: Vec, /// Names and link kinds of libraries, suitable for the `-l` flag. pub library_links: Vec, /// Linker arguments suitable to be passed to `-C link-arg=` pub linker_args: Vec<(LinkArgTarget, String)>, /// Various `--cfg` flags to pass to the compiler. pub cfgs: Vec, /// Various `--check-cfg` flags to pass to the compiler. pub check_cfgs: Vec, /// Additional environment variables to run the compiler with. pub env: Vec<(String, String)>, /// Metadata to pass to the immediate dependencies. pub metadata: Vec<(String, String)>, /// Paths to trigger a rerun of this build script. /// May be absolute or relative paths (relative to package root). pub rerun_if_changed: Vec, /// Environment variables which, when changed, will cause a rebuild. pub rerun_if_env_changed: Vec, /// Errors and warnings generated by this build. /// /// These are only displayed if this is a "local" package, `-vv` is used, or /// there is a build error for any target in this package. Note that any log /// message of severity `Error` will by itself cause a build error, and will /// cause all log messages to be displayed. pub log_messages: Vec, } /// Map of packages to build script output. /// /// This initially starts out as empty. Overridden build scripts get /// inserted during `build_map`. The rest of the entries are added /// immediately after each build script runs. /// /// The [`UnitHash`] is the unique metadata hash for the `RunCustomBuild` Unit of /// the package. It needs a unique key, since the build script can be run /// multiple times with different profiles or features. We can't embed a /// `Unit` because this structure needs to be shareable between threads. #[derive(Default)] pub struct BuildScriptOutputs { outputs: HashMap, } /// Linking information for a `Unit`. /// /// See [`build_map`] for more details. #[derive(Default)] pub struct BuildScripts { /// List of build script outputs this Unit needs to include for linking. Each /// element is an index into `BuildScriptOutputs`. /// /// Cargo will use this `to_link` vector to add `-L` flags to compiles as we /// propagate them upwards towards the final build. Note, however, that we /// need to preserve the ordering of `to_link` to be topologically sorted. /// This will ensure that build scripts which print their paths properly will /// correctly pick up the files they generated (if there are duplicates /// elsewhere). /// /// To preserve this ordering, the (id, metadata) is stored in two places, once /// in the `Vec` and once in `seen_to_link` for a fast lookup. We maintain /// this as we're building interactively below to ensure that the memory /// usage here doesn't blow up too much. /// /// For more information, see #2354. pub to_link: Vec<(PackageId, UnitHash)>, /// This is only used while constructing `to_link` to avoid duplicates. seen_to_link: HashSet<(PackageId, UnitHash)>, /// Host-only dependencies that have build scripts. Each element is an /// index into `BuildScriptOutputs`. /// /// This is the set of transitive dependencies that are host-only /// (proc-macro, plugin, build-dependency) that contain a build script. /// Any `BuildOutput::library_paths` path relative to `target` will be /// added to `LD_LIBRARY_PATH` so that the compiler can find any dynamic /// libraries a build script may have generated. pub plugins: BTreeSet<(PackageId, UnitHash)>, } /// Dependency information as declared by a build script that might trigger /// a recompile of itself. #[derive(Debug)] pub struct BuildDeps { /// Absolute path to the file in the target directory that stores the /// output of the build script. pub build_script_output: PathBuf, /// Files that trigger a rebuild if they change. pub rerun_if_changed: Vec, /// Environment variables that trigger a rebuild if they change. pub rerun_if_env_changed: Vec, } /// 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, PartialOrd, Ord)] 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. #[tracing::instrument(skip_all)] pub fn prepare(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult { let metadata = build_runner.get_run_build_script_metadata(unit); if build_runner .build_script_outputs .lock() .unwrap() .contains_key(metadata) { // The output is already set, thus the build script is overridden. fingerprint::prepare_target(build_runner, unit, false) } else { build_work(build_runner, unit) } } /// Emits the output of a build script as a [`machine_message::BuildScript`] /// JSON string to standard output. fn emit_build_output( state: &JobState<'_, '_>, output: &BuildOutput, out_dir: &Path, package_id: PackageId, ) -> CargoResult<()> { let library_paths = output .library_paths .iter() .map(|l| l.display().to_string()) .collect::>(); let msg = machine_message::BuildScript { package_id: package_id.to_spec(), linked_libs: &output.library_links, linked_paths: &library_paths, cfgs: &output.cfgs, env: &output.env, out_dir, } .to_json_string(); state.stdout(msg)?; Ok(()) } /// Constructs the unit of work of running a build script. /// /// The construction includes: /// /// * Set environment variables for the build script run. /// * Create the output dir (`OUT_DIR`) for the build script output. /// * Determine if the build script needs a re-run. /// * Run the build script and store its output. fn build_work(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult { assert!(unit.mode.is_run_custom_build()); let bcx = &build_runner.bcx; let dependencies = build_runner.unit_deps(unit); let build_script_unit = dependencies .iter() .find(|d| !d.unit.mode.is_run_custom_build() && d.unit.target.is_custom_build()) .map(|d| &d.unit) .expect("running a script not depending on an actual script"); let script_dir = build_runner.files().build_script_dir(build_script_unit); let script_out_dir = build_runner.files().build_script_out_dir(unit); let script_run_dir = build_runner.files().build_script_run_dir(unit); let build_plan = bcx.build_config.build_plan; let invocation_name = unit.buildkey(); if let Some(deps) = unit.pkg.manifest().metabuild() { prepare_metabuild(build_runner, build_script_unit, deps)?; } // Building the command to execute let to_exec = script_dir.join(unit.target.name()); // Start preparing the process to execute, starting out with some // environment variables. Note that the profile-related environment // variables are not set with this the build script's profile but rather the // package's library profile. // NOTE: if you add any profile flags, be sure to update // `Profiles::get_profile_run_custom_build` so that those flags get // carried over. let to_exec = to_exec.into_os_string(); let mut cmd = build_runner.compilation.host_process(to_exec, &unit.pkg)?; let debug = unit.profile.debuginfo.is_turned_on(); cmd.env("OUT_DIR", &script_out_dir) .env("CARGO_MANIFEST_DIR", unit.pkg.root()) .env("CARGO_MANIFEST_PATH", unit.pkg.manifest_path()) .env("NUM_JOBS", &bcx.jobs().to_string()) .env("TARGET", bcx.target_data.short_name(&unit.kind)) .env("DEBUG", debug.to_string()) .env("OPT_LEVEL", &unit.profile.opt_level) .env( "PROFILE", match unit.profile.root { ProfileRoot::Release => "release", ProfileRoot::Debug => "debug", }, ) .env("HOST", &bcx.host_triple()) .env("RUSTC", &bcx.rustc().path) .env("RUSTDOC", &*bcx.gctx.rustdoc()?) .inherit_jobserver(&build_runner.jobserver); // Find all artifact dependencies and make their file and containing directory discoverable using environment variables. for (var, value) in artifact::get_env(build_runner, dependencies)? { cmd.env(&var, value); } if let Some(linker) = &build_runner.compilation.target_linker(unit.kind) { cmd.env("RUSTC_LINKER", linker); } if let Some(links) = unit.pkg.manifest().links() { cmd.env("CARGO_MANIFEST_LINKS", links); } if let Some(trim_paths) = unit.profile.trim_paths.as_ref() { cmd.env("CARGO_TRIM_PATHS", trim_paths.to_string()); } // Be sure to pass along all enabled features for this package, this is the // last piece of statically known information that we have. for feat in &unit.features { cmd.env(&format!("CARGO_FEATURE_{}", super::envify(feat)), "1"); } let mut cfg_map = HashMap::new(); cfg_map.insert( "feature", unit.features.iter().map(|s| s.as_str()).collect::>(), ); for cfg in bcx.target_data.cfg(unit.kind) { match *cfg { Cfg::Name(ref n) => { cfg_map.insert(n.as_str(), Vec::new()); } Cfg::KeyPair(ref k, ref v) => { let values = cfg_map.entry(k.as_str()).or_default(); values.push(v.as_str()); } } } for (k, v) in cfg_map { if k == "debug_assertions" { // This cfg is always true and misleading, so avoid setting it. // That is because Cargo queries rustc without any profile settings. continue; } // FIXME: We should handle raw-idents somehow instead of predenting they // don't exist here let k = format!("CARGO_CFG_{}", super::envify(k)); cmd.env(&k, v.join(",")); } // Also inform the build script of the rustc compiler context. if let Some(wrapper) = bcx.rustc().wrapper.as_ref() { cmd.env("RUSTC_WRAPPER", wrapper); } else { cmd.env_remove("RUSTC_WRAPPER"); } cmd.env_remove("RUSTC_WORKSPACE_WRAPPER"); if build_runner.bcx.ws.is_member(&unit.pkg) { if let Some(wrapper) = bcx.rustc().workspace_wrapper.as_ref() { cmd.env("RUSTC_WORKSPACE_WRAPPER", wrapper); } } cmd.env("CARGO_ENCODED_RUSTFLAGS", unit.rustflags.join("\x1f")); cmd.env_remove("RUSTFLAGS"); if build_runner.bcx.ws.gctx().extra_verbose() { cmd.display_env_vars(); } // Gather the set of native dependencies that this package has along with // some other variables to close over. // // This information will be used at build-time later on to figure out which // sorts of variables need to be discovered at that time. let lib_deps = dependencies .iter() .filter_map(|dep| { if dep.unit.mode.is_run_custom_build() { let dep_metadata = build_runner.get_run_build_script_metadata(&dep.unit); Some(( dep.unit.pkg.manifest().links().unwrap().to_string(), dep.unit.pkg.package_id(), dep_metadata, )) } else { None } }) .collect::>(); let library_name = unit.pkg.library().map(|t| t.crate_name()); let pkg_descr = unit.pkg.to_string(); let build_script_outputs = Arc::clone(&build_runner.build_script_outputs); let id = unit.pkg.package_id(); let output_file = script_run_dir.join("output"); let err_file = script_run_dir.join("stderr"); let root_output_file = script_run_dir.join("root-output"); let host_target_root = build_runner.files().host_dest().to_path_buf(); let all = ( id, library_name.clone(), pkg_descr.clone(), Arc::clone(&build_script_outputs), output_file.clone(), script_out_dir.clone(), ); let build_scripts = build_runner.build_scripts.get(unit).cloned(); let json_messages = bcx.build_config.emit_json(); let extra_verbose = bcx.gctx.extra_verbose(); let (prev_output, prev_script_out_dir) = prev_build_output(build_runner, unit); let metadata_hash = build_runner.get_run_build_script_metadata(unit); paths::create_dir_all(&script_dir)?; paths::create_dir_all(&script_out_dir)?; let nightly_features_allowed = build_runner.bcx.gctx.nightly_features_allowed; let targets: Vec = unit.pkg.targets().to_vec(); let msrv = unit.pkg.rust_version().cloned(); // Need a separate copy for the fresh closure. let targets_fresh = targets.clone(); let msrv_fresh = msrv.clone(); let env_profile_name = unit.profile.name.to_uppercase(); let built_with_debuginfo = build_runner .bcx .unit_graph .get(unit) .and_then(|deps| deps.iter().find(|dep| dep.unit.target == unit.target)) .map(|dep| dep.unit.profile.debuginfo.is_turned_on()) .unwrap_or(false); // Prepare the unit of "dirty work" which will actually run the custom build // command. // // Note that this has to do some extra work just before running the command // to determine extra environment variables and such. let dirty = Work::new(move |state| { // Make sure that OUT_DIR exists. // // If we have an old build directory, then just move it into place, // otherwise create it! paths::create_dir_all(&script_out_dir) .context("failed to create script output directory for build command")?; // For all our native lib dependencies, pick up their metadata to pass // along to this custom build command. We're also careful to augment our // dynamic library search path in case the build script depended on any // native dynamic libraries. if !build_plan { let build_script_outputs = build_script_outputs.lock().unwrap(); for (name, dep_id, dep_metadata) in lib_deps { let script_output = build_script_outputs.get(dep_metadata).ok_or_else(|| { internal(format!( "failed to locate build state for env vars: {}/{}", dep_id, dep_metadata )) })?; let data = &script_output.metadata; for (key, value) in data.iter() { cmd.env( &format!("DEP_{}_{}", super::envify(&name), super::envify(key)), value, ); } } if let Some(build_scripts) = build_scripts { super::add_plugin_deps( &mut cmd, &build_script_outputs, &build_scripts, &host_target_root, )?; } } if build_plan { state.build_plan(invocation_name, cmd.clone(), Arc::new(Vec::new())); return Ok(()); } // And now finally, run the build command itself! state.running(&cmd); let timestamp = paths::set_invocation_time(&script_run_dir)?; let prefix = format!("[{} {}] ", id.name(), id.version()); let mut log_messages_in_case_of_panic = Vec::new(); let output = cmd .exec_with_streaming( &mut |stdout| { if let Some(error) = stdout.strip_prefix(CARGO_ERROR_SYNTAX) { log_messages_in_case_of_panic.push((Severity::Error, error.to_owned())); } if let Some(warning) = stdout .strip_prefix(OLD_CARGO_WARNING_SYNTAX) .or(stdout.strip_prefix(NEW_CARGO_WARNING_SYNTAX)) { log_messages_in_case_of_panic.push((Severity::Warning, warning.to_owned())); } if extra_verbose { state.stdout(format!("{}{}", prefix, stdout))?; } Ok(()) }, &mut |stderr| { if extra_verbose { state.stderr(format!("{}{}", prefix, stderr))?; } Ok(()) }, true, ) .with_context(|| { let mut build_error_context = format!("failed to run custom build command for `{}`", pkg_descr); // If we're opting into backtraces, mention that build dependencies' backtraces can // be improved by requesting debuginfo to be built, if we're not building with // debuginfo already. // // ALLOWED: Other tools like `rustc` might read it directly // through `std::env`. We should make their behavior consistent. #[allow(clippy::disallowed_methods)] if let Ok(show_backtraces) = std::env::var("RUST_BACKTRACE") { if !built_with_debuginfo && show_backtraces != "0" { build_error_context.push_str(&format!( "\n\ note: To improve backtraces for build dependencies, set the \ CARGO_PROFILE_{env_profile_name}_BUILD_OVERRIDE_DEBUG=true environment \ variable to enable debug information generation.", )); } } build_error_context }); // If the build failed if let Err(error) = output { insert_log_messages_in_build_outputs( build_script_outputs, id, metadata_hash, log_messages_in_case_of_panic, ); return Err(error); } // ... or it logged any errors else if log_messages_in_case_of_panic .iter() .any(|(severity, _)| *severity == Severity::Error) { insert_log_messages_in_build_outputs( build_script_outputs, id, metadata_hash, log_messages_in_case_of_panic, ); anyhow::bail!("build script logged errors"); } let output = output.unwrap(); // After the build command has finished running, we need to be sure to // remember all of its output so we can later discover precisely what it // was, even if we don't run the build command again (due to freshness). // // This is also the location where we provide feedback into the build // state informing what variables were discovered via our script as // well. paths::write(&output_file, &output.stdout)?; // This mtime shift allows Cargo to detect if a source file was // modified in the middle of the build. paths::set_file_time_no_err(output_file, timestamp); paths::write(&err_file, &output.stderr)?; paths::write(&root_output_file, paths::path2bytes(&script_out_dir)?)?; let parsed_output = BuildOutput::parse( &output.stdout, library_name, &pkg_descr, &script_out_dir, &script_out_dir, nightly_features_allowed, &targets, &msrv, )?; if json_messages { emit_build_output(state, &parsed_output, script_out_dir.as_path(), id)?; } build_script_outputs .lock() .unwrap() .insert(id, metadata_hash, parsed_output); Ok(()) }); // Now that we've prepared our work-to-do, we need to prepare the fresh work // itself to run when we actually end up just discarding what we calculated // above. let fresh = Work::new(move |state| { let (id, library_name, pkg_descr, build_script_outputs, output_file, script_out_dir) = all; let output = match prev_output { Some(output) => output, None => BuildOutput::parse_file( &output_file, library_name, &pkg_descr, &prev_script_out_dir, &script_out_dir, nightly_features_allowed, &targets_fresh, &msrv_fresh, )?, }; if json_messages { emit_build_output(state, &output, script_out_dir.as_path(), id)?; } build_script_outputs .lock() .unwrap() .insert(id, metadata_hash, output); Ok(()) }); let mut job = if build_runner.bcx.build_config.build_plan { Job::new_dirty(Work::noop(), DirtyReason::FreshBuild) } else { fingerprint::prepare_target(build_runner, unit, false)? }; if job.freshness().is_dirty() { job.before(dirty); } else { job.before(fresh); } Ok(job) } /// When a build script run fails, store only log messages, and nuke other /// outputs, as they are likely broken. fn insert_log_messages_in_build_outputs( build_script_outputs: Arc>, id: PackageId, metadata_hash: UnitHash, log_messages: Vec, ) { let build_output_with_only_log_messages = BuildOutput { log_messages, ..BuildOutput::default() }; build_script_outputs.lock().unwrap().insert( id, metadata_hash, build_output_with_only_log_messages, ); } impl BuildOutput { /// Like [`BuildOutput::parse`] but from a file path. pub fn parse_file( path: &Path, library_name: Option, pkg_descr: &str, script_out_dir_when_generated: &Path, script_out_dir: &Path, nightly_features_allowed: bool, targets: &[Target], msrv: &Option, ) -> CargoResult { let contents = paths::read_bytes(path)?; BuildOutput::parse( &contents, library_name, pkg_descr, script_out_dir_when_generated, script_out_dir, nightly_features_allowed, targets, msrv, ) } /// Parses the output instructions of a build script. /// /// * `pkg_descr` --- for error messages /// * `library_name` --- for determining if `RUSTC_BOOTSTRAP` should be allowed pub fn parse( input: &[u8], // Takes String instead of InternedString so passing `unit.pkg.name()` will give a compile error. library_name: Option, pkg_descr: &str, script_out_dir_when_generated: &Path, script_out_dir: &Path, nightly_features_allowed: bool, targets: &[Target], msrv: &Option, ) -> CargoResult { let mut library_paths = Vec::new(); let mut library_links = Vec::new(); let mut linker_args = Vec::new(); let mut cfgs = Vec::new(); let mut check_cfgs = Vec::new(); let mut env = Vec::new(); let mut metadata = Vec::new(); let mut rerun_if_changed = Vec::new(); let mut rerun_if_env_changed = Vec::new(); let mut log_messages = Vec::new(); let whence = format!("build script of `{}`", pkg_descr); // Old syntax: // cargo:rustc-flags=VALUE // cargo:KEY=VALUE (for other unreserved keys) // New syntax: // cargo::rustc-flags=VALUE // cargo::metadata=KEY=VALUE (for other unreserved keys) // Due to backwards compatibility, no new keys can be added to this old format. const RESERVED_PREFIXES: &[&str] = &[ "rustc-flags=", "rustc-link-lib=", "rustc-link-search=", "rustc-link-arg-cdylib=", "rustc-cdylib-link-arg=", "rustc-link-arg-bins=", "rustc-link-arg-bin=", "rustc-link-arg-tests=", "rustc-link-arg-benches=", "rustc-link-arg-examples=", "rustc-link-arg=", "rustc-cfg=", "rustc-check-cfg=", "rustc-env=", "warning=", "rerun-if-changed=", "rerun-if-env-changed=", ]; const DOCS_LINK_SUGGESTION: &str = "See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script \ for more information about build script outputs."; fn has_reserved_prefix(flag: &str) -> bool { RESERVED_PREFIXES .iter() .any(|reserved_prefix| flag.starts_with(reserved_prefix)) } fn check_minimum_supported_rust_version_for_new_syntax( pkg_descr: &str, msrv: &Option, flag: &str, ) -> CargoResult<()> { if let Some(msrv) = msrv { let new_syntax_added_in = RustVersion::from_str("1.77.0")?; if !new_syntax_added_in.is_compatible_with(msrv.as_partial()) { let old_syntax_suggestion = if has_reserved_prefix(flag) { format!( "Switch to the old `cargo:{flag}` syntax (note the single colon).\n" ) } else if flag.starts_with("metadata=") { let old_format_flag = flag.strip_prefix("metadata=").unwrap(); format!("Switch to the old `cargo:{old_format_flag}` syntax instead of `cargo::{flag}` (note the single colon).\n") } else { String::new() }; bail!( "the `cargo::` syntax for build script output instructions was added in \ Rust 1.77.0, but the minimum supported Rust version of `{pkg_descr}` is {msrv}.\n\ {old_syntax_suggestion}\ {DOCS_LINK_SUGGESTION}" ); } } Ok(()) } fn parse_directive<'a>( whence: &str, line: &str, data: &'a str, old_syntax: bool, ) -> CargoResult<(&'a str, &'a str)> { let mut iter = data.splitn(2, "="); let key = iter.next(); let value = iter.next(); match (key, value) { (Some(a), Some(b)) => Ok((a, b.trim_end())), _ => bail!( "invalid output in {whence}: `{line}`\n\ Expected a line with `{syntax}KEY=VALUE` with an `=` character, \ but none was found.\n\ {DOCS_LINK_SUGGESTION}", syntax = if old_syntax { "cargo:" } else { "cargo::" }, ), } } fn parse_metadata<'a>( whence: &str, line: &str, data: &'a str, old_syntax: bool, ) -> CargoResult<(&'a str, &'a str)> { let mut iter = data.splitn(2, "="); let key = iter.next(); let value = iter.next(); match (key, value) { (Some(a), Some(b)) => Ok((a, b.trim_end())), _ => bail!( "invalid output in {whence}: `{line}`\n\ Expected a line with `{syntax}KEY=VALUE` with an `=` character, \ but none was found.\n\ {DOCS_LINK_SUGGESTION}", syntax = if old_syntax { "cargo:" } else { "cargo::metadata=" }, ), } } for line in input.split(|b| *b == b'\n') { let line = match str::from_utf8(line) { Ok(line) => line.trim(), Err(..) => continue, }; let mut old_syntax = false; let (key, value) = if let Some(data) = line.strip_prefix("cargo::") { check_minimum_supported_rust_version_for_new_syntax(pkg_descr, msrv, data)?; // For instance, `cargo::rustc-flags=foo` or `cargo::metadata=foo=bar`. parse_directive(whence.as_str(), line, data, old_syntax)? } else if let Some(data) = line.strip_prefix("cargo:") { old_syntax = true; // For instance, `cargo:rustc-flags=foo`. if has_reserved_prefix(data) { parse_directive(whence.as_str(), line, data, old_syntax)? } else { // For instance, `cargo:foo=bar`. ("metadata", data) } } else { // Skip this line since it doesn't start with "cargo:" or "cargo::". continue; }; // This will rewrite paths if the target directory has been moved. let value = value.replace( script_out_dir_when_generated.to_str().unwrap(), script_out_dir.to_str().unwrap(), ); let syntax_prefix = if old_syntax { "cargo:" } else { "cargo::" }; macro_rules! check_and_add_target { ($target_kind: expr, $is_target_kind: expr, $link_type: expr) => { if !targets.iter().any(|target| $is_target_kind(target)) { bail!( "invalid instruction `{}{}` from {}\n\ The package {} does not have a {} target.", syntax_prefix, key, whence, pkg_descr, $target_kind ); } linker_args.push(($link_type, value)); }; } // Keep in sync with TargetConfig::parse_links_overrides. match key { "rustc-flags" => { let (paths, links) = BuildOutput::parse_rustc_flags(&value, &whence)?; library_links.extend(links.into_iter()); library_paths.extend(paths.into_iter()); } "rustc-link-lib" => library_links.push(value.to_string()), "rustc-link-search" => library_paths.push(PathBuf::from(value)), "rustc-link-arg-cdylib" | "rustc-cdylib-link-arg" => { if !targets.iter().any(|target| target.is_cdylib()) { log_messages.push(( Severity::Warning, format!( "{}{} was specified in the build script of {}, \ but that package does not contain a cdylib target\n\ \n\ Allowing this was an unintended change in the 1.50 \ release, and may become an error in the future. \ For more information, see \ .", syntax_prefix, key, pkg_descr ), )); } linker_args.push((LinkArgTarget::Cdylib, value)) } "rustc-link-arg-bins" => { check_and_add_target!("bin", Target::is_bin, LinkArgTarget::Bin); } "rustc-link-arg-bin" => { let (bin_name, arg) = value.split_once('=').ok_or_else(|| { anyhow::format_err!( "invalid instruction `{}{}={}` from {}\n\ The instruction should have the form {}{}=BIN=ARG", syntax_prefix, key, value, whence, syntax_prefix, key ) })?; if !targets .iter() .any(|target| target.is_bin() && target.name() == bin_name) { bail!( "invalid instruction `{}{}` from {}\n\ The package {} does not have a bin target with the name `{}`.", syntax_prefix, key, whence, pkg_descr, bin_name ); } linker_args.push(( LinkArgTarget::SingleBin(bin_name.to_owned()), arg.to_string(), )); } "rustc-link-arg-tests" => { check_and_add_target!("test", Target::is_test, LinkArgTarget::Test); } "rustc-link-arg-benches" => { check_and_add_target!("benchmark", Target::is_bench, LinkArgTarget::Bench); } "rustc-link-arg-examples" => { check_and_add_target!("example", Target::is_example, LinkArgTarget::Example); } "rustc-link-arg" => { linker_args.push((LinkArgTarget::All, value)); } "rustc-cfg" => cfgs.push(value.to_string()), "rustc-check-cfg" => check_cfgs.push(value.to_string()), "rustc-env" => { let (key, val) = BuildOutput::parse_rustc_env(&value, &whence)?; // Build scripts aren't allowed to set RUSTC_BOOTSTRAP. // See https://github.com/rust-lang/cargo/issues/7088. if key == "RUSTC_BOOTSTRAP" { // If RUSTC_BOOTSTRAP is already set, the user of Cargo knows about // bootstrap and still wants to override the channel. Give them a way to do // so, but still emit a warning that the current crate shouldn't be trying // to set RUSTC_BOOTSTRAP. // If this is a nightly build, setting RUSTC_BOOTSTRAP wouldn't affect the // behavior, so still only give a warning. // NOTE: cargo only allows nightly features on RUSTC_BOOTSTRAP=1, but we // want setting any value of RUSTC_BOOTSTRAP to downgrade this to a warning // (so that `RUSTC_BOOTSTRAP=library_name` will work) let rustc_bootstrap_allows = |name: Option<&str>| { let name = match name { // as of 2021, no binaries on crates.io use RUSTC_BOOTSTRAP, so // fine-grained opt-outs aren't needed. end-users can always use // RUSTC_BOOTSTRAP=1 from the top-level if it's really a problem. None => return false, Some(n) => n, }; // ALLOWED: the process of rustc bootstrapping reads this through // `std::env`. We should make the behavior consistent. Also, we // don't advertise this for bypassing nightly. #[allow(clippy::disallowed_methods)] std::env::var("RUSTC_BOOTSTRAP") .map_or(false, |var| var.split(',').any(|s| s == name)) }; if nightly_features_allowed || rustc_bootstrap_allows(library_name.as_deref()) { log_messages.push((Severity::Warning, format!("Cannot set `RUSTC_BOOTSTRAP={}` from {}.\n\ note: Crates cannot set `RUSTC_BOOTSTRAP` themselves, as doing so would subvert the stability guarantees of Rust for your project.", val, whence ))); } else { // Setting RUSTC_BOOTSTRAP would change the behavior of the crate. // Abort with an error. bail!("Cannot set `RUSTC_BOOTSTRAP={}` from {}.\n\ note: Crates cannot set `RUSTC_BOOTSTRAP` themselves, as doing so would subvert the stability guarantees of Rust for your project.\n\ help: If you're sure you want to do this in your project, set the environment variable `RUSTC_BOOTSTRAP={}` before running cargo instead.", val, whence, library_name.as_deref().unwrap_or("1"), ); } } else { env.push((key, val)); } } "error" => log_messages.push((Severity::Error, value.to_string())), "warning" => log_messages.push((Severity::Warning, value.to_string())), "rerun-if-changed" => rerun_if_changed.push(PathBuf::from(value)), "rerun-if-env-changed" => rerun_if_env_changed.push(value.to_string()), "metadata" => { let (key, value) = parse_metadata(whence.as_str(), line, &value, old_syntax)?; metadata.push((key.to_owned(), value.to_owned())); } _ => bail!( "invalid output in {whence}: `{line}`\n\ Unknown key: `{key}`.\n\ {DOCS_LINK_SUGGESTION}", ), } } Ok(BuildOutput { library_paths, library_links, linker_args, cfgs, check_cfgs, env, metadata, rerun_if_changed, rerun_if_env_changed, log_messages, }) } /// Parses [`cargo::rustc-flags`] instruction. /// /// [`cargo::rustc-flags`]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#cargorustc-flagsflags pub fn parse_rustc_flags( value: &str, whence: &str, ) -> CargoResult<(Vec, Vec)> { let value = value.trim(); let mut flags_iter = value .split(|c: char| c.is_whitespace()) .filter(|w| w.chars().any(|c| !c.is_whitespace())); let (mut library_paths, mut library_links) = (Vec::new(), Vec::new()); while let Some(flag) = flags_iter.next() { if flag.starts_with("-l") || flag.starts_with("-L") { // Check if this flag has no space before the value as is // common with tools like pkg-config // e.g. -L/some/dir/local/lib or -licui18n let (flag, mut value) = flag.split_at(2); if value.is_empty() { value = match flags_iter.next() { Some(v) => v, None => bail! { "Flag in rustc-flags has no value in {}: {}", whence, value }, } } match flag { "-l" => library_links.push(value.to_string()), "-L" => library_paths.push(PathBuf::from(value)), // This was already checked above _ => unreachable!(), }; } else { bail!( "Only `-l` and `-L` flags are allowed in {}: `{}`", whence, value ) } } Ok((library_paths, library_links)) } /// Parses [`cargo::rustc-env`] instruction. /// /// [`cargo::rustc-env`]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-env pub fn parse_rustc_env(value: &str, whence: &str) -> CargoResult<(String, String)> { match value.split_once('=') { Some((n, v)) => Ok((n.to_owned(), v.to_owned())), _ => bail!("Variable rustc-env has no value in {whence}: {value}"), } } } /// Prepares the Rust script for the unstable feature [metabuild]. /// /// [metabuild]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#metabuild fn prepare_metabuild( build_runner: &BuildRunner<'_, '_>, unit: &Unit, deps: &[String], ) -> CargoResult<()> { let mut output = Vec::new(); let available_deps = build_runner.unit_deps(unit); // Filter out optional dependencies, and look up the actual lib name. let meta_deps: Vec<_> = deps .iter() .filter_map(|name| { available_deps .iter() .find(|d| d.unit.pkg.name().as_str() == name.as_str()) .map(|d| d.unit.target.crate_name()) }) .collect(); output.push("fn main() {\n".to_string()); for dep in &meta_deps { output.push(format!(" {}::metabuild();\n", dep)); } output.push("}\n".to_string()); let output = output.join(""); let path = unit .pkg .manifest() .metabuild_path(build_runner.bcx.ws.target_dir()); paths::create_dir_all(path.parent().unwrap())?; paths::write_if_changed(path, &output)?; Ok(()) } impl BuildDeps { /// Creates a build script dependency information from a previous /// build script output path and the content. pub fn new(output_file: &Path, output: Option<&BuildOutput>) -> BuildDeps { BuildDeps { build_script_output: output_file.to_path_buf(), rerun_if_changed: output .map(|p| &p.rerun_if_changed) .cloned() .unwrap_or_default(), rerun_if_env_changed: output .map(|p| &p.rerun_if_env_changed) .cloned() .unwrap_or_default(), } } } /// Computes several maps in [`BuildRunner`]. /// /// - [`build_scripts`]: A map that tracks which build scripts each package /// depends on. /// - [`build_explicit_deps`]: Dependency statements emitted by build scripts /// from a previous run. /// - [`build_script_outputs`]: Pre-populates this with any overridden build /// scripts. /// /// The important one here is [`build_scripts`], which for each `(package, /// metadata)` stores a [`BuildScripts`] object which contains a list of /// dependencies with build scripts that the unit should consider when linking. /// For example this lists all dependencies' `-L` flags which need to be /// propagated transitively. /// /// The given set of units to this function is the initial set of /// targets/profiles which are being built. /// /// [`build_scripts`]: BuildRunner::build_scripts /// [`build_explicit_deps`]: BuildRunner::build_explicit_deps /// [`build_script_outputs`]: BuildRunner::build_script_outputs pub fn build_map(build_runner: &mut BuildRunner<'_, '_>) -> CargoResult<()> { let mut ret = HashMap::new(); for unit in &build_runner.bcx.roots { build(&mut ret, build_runner, unit)?; } build_runner .build_scripts .extend(ret.into_iter().map(|(k, v)| (k, Arc::new(v)))); return Ok(()); // Recursive function to build up the map we're constructing. This function // memoizes all of its return values as it goes along. fn build<'a>( out: &'a mut HashMap, build_runner: &mut BuildRunner<'_, '_>, unit: &Unit, ) -> CargoResult<&'a BuildScripts> { // Do a quick pre-flight check to see if we've already calculated the // set of dependencies. if out.contains_key(unit) { return Ok(&out[unit]); } // If there is a build script override, pre-fill the build output. if unit.mode.is_run_custom_build() { if let Some(links) = unit.pkg.manifest().links() { if let Some(output) = unit.links_overrides.get(links) { let metadata = build_runner.get_run_build_script_metadata(unit); build_runner.build_script_outputs.lock().unwrap().insert( unit.pkg.package_id(), metadata, output.clone(), ); } } } let mut ret = BuildScripts::default(); // If a package has a build script, add itself as something to inspect for linking. if !unit.target.is_custom_build() && unit.pkg.has_custom_build() { let script_meta = build_runner .find_build_script_metadata(unit) .expect("has_custom_build should have RunCustomBuild"); add_to_link(&mut ret, unit.pkg.package_id(), script_meta); } if unit.mode.is_run_custom_build() { parse_previous_explicit_deps(build_runner, unit); } // We want to invoke the compiler deterministically to be cache-friendly // to rustc invocation caching schemes, so be sure to generate the same // set of build script dependency orderings via sorting the targets that // come out of the `Context`. let mut dependencies: Vec = build_runner .unit_deps(unit) .iter() .map(|d| d.unit.clone()) .collect(); dependencies.sort_by_key(|u| u.pkg.package_id()); for dep_unit in dependencies.iter() { let dep_scripts = build(out, build_runner, dep_unit)?; if dep_unit.target.for_host() { ret.plugins.extend(dep_scripts.to_link.iter().cloned()); } else if dep_unit.target.is_linkable() { for &(pkg, metadata) in dep_scripts.to_link.iter() { add_to_link(&mut ret, pkg, metadata); } } } match out.entry(unit.clone()) { Entry::Vacant(entry) => Ok(entry.insert(ret)), Entry::Occupied(_) => panic!("cyclic dependencies in `build_map`"), } } // When adding an entry to 'to_link' we only actually push it on if the // script hasn't seen it yet (e.g., we don't push on duplicates). fn add_to_link(scripts: &mut BuildScripts, pkg: PackageId, metadata: UnitHash) { if scripts.seen_to_link.insert((pkg, metadata)) { scripts.to_link.push((pkg, metadata)); } } /// Load any dependency declarations from a previous build script run. fn parse_previous_explicit_deps(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) { let script_run_dir = build_runner.files().build_script_run_dir(unit); let output_file = script_run_dir.join("output"); let (prev_output, _) = prev_build_output(build_runner, unit); let deps = BuildDeps::new(&output_file, prev_output.as_ref()); build_runner.build_explicit_deps.insert(unit.clone(), deps); } } /// Returns the previous parsed `BuildOutput`, if any, from a previous /// execution. /// /// Also returns the directory containing the output, typically used later in /// processing. fn prev_build_output( build_runner: &mut BuildRunner<'_, '_>, unit: &Unit, ) -> (Option, PathBuf) { let script_out_dir = build_runner.files().build_script_out_dir(unit); let script_run_dir = build_runner.files().build_script_run_dir(unit); let root_output_file = script_run_dir.join("root-output"); let output_file = script_run_dir.join("output"); let prev_script_out_dir = paths::read_bytes(&root_output_file) .and_then(|bytes| paths::bytes2path(&bytes)) .unwrap_or_else(|_| script_out_dir.clone()); ( BuildOutput::parse_file( &output_file, unit.pkg.library().map(|t| t.crate_name()), &unit.pkg.to_string(), &prev_script_out_dir, &script_out_dir, build_runner.bcx.gctx.nightly_features_allowed, unit.pkg.targets(), &unit.pkg.rust_version().cloned(), ) .ok(), prev_script_out_dir, ) } impl BuildScriptOutputs { /// Inserts a new entry into the map. fn insert(&mut self, pkg_id: PackageId, metadata: UnitHash, parsed_output: BuildOutput) { match self.outputs.entry(metadata) { Entry::Vacant(entry) => { entry.insert(parsed_output); } Entry::Occupied(entry) => panic!( "build script output collision for {}/{}\n\ old={:?}\nnew={:?}", pkg_id, metadata, entry.get(), parsed_output ), } } /// Returns `true` if the given key already exists. fn contains_key(&self, metadata: UnitHash) -> bool { self.outputs.contains_key(&metadata) } /// Gets the build output for the given key. pub fn get(&self, meta: UnitHash) -> Option<&BuildOutput> { self.outputs.get(&meta) } /// Returns an iterator over all entries. pub fn iter(&self) -> impl Iterator { self.outputs.iter() } } cargo-0.86.0/src/cargo/core/compiler/fingerprint/dep_info.rs000064400000000000000000000652401046102023000221250ustar 00000000000000//! Types and functions managing dep-info files. //! For more, see [the documentation] in the `fingerprint` module. //! //! [the documentation]: crate::core::compiler::fingerprint#dep-info-files use std::collections::HashMap; use std::ffi::OsString; use std::fmt; use std::io; use std::io::Read; use std::path::Path; use std::path::PathBuf; use std::str; use std::str::FromStr; use std::sync::Arc; use anyhow::bail; use cargo_util::paths; use cargo_util::ProcessBuilder; use cargo_util::Sha256; use crate::core::manifest::ManifestMetadata; use crate::CargoResult; use crate::CARGO_ENV; /// The current format version of [`EncodedDepInfo`]. const CURRENT_ENCODED_DEP_INFO_VERSION: u8 = 1; /// The representation of the `.d` dep-info file generated by rustc #[derive(Default)] pub struct RustcDepInfo { /// The list of files that the main target in the dep-info file depends on. /// /// The optional checksums are parsed from the special `# checksum:...` comments. pub files: HashMap>, /// The list of environment variables we found that the rustc compilation /// depends on. /// /// The first element of the pair is the name of the env var and the second /// item is the value. `Some` means that the env var was set, and `None` /// means that the env var wasn't actually set and the compilation depends /// on it not being set. /// /// These are from the special `# env-var:...` comments. pub env: Vec<(String, Option)>, } /// Tells the associated path in [`EncodedDepInfo::files`] is relative to package root, /// target root, or absolute. #[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)] pub enum DepInfoPathType { /// src/, e.g. src/lib.rs PackageRootRelative, /// target/debug/deps/lib... /// or an absolute path /.../sysroot/... TargetRootRelative, } /// Same as [`RustcDepInfo`] except avoids absolute paths as much as possible to /// allow moving around the target directory. /// /// This is also stored in an optimized format to make parsing it fast because /// Cargo will read it for crates on all future compilations. /// /// Currently the format looks like: /// /// ```text /// +--------+---------+------------+------------+---------------+---------------+ /// | marker | version | # of files | file paths | # of env vars | env var pairs | /// +--------+---------+------------+------------+---------------+---------------+ /// ``` /// /// Each field represents /// /// * _Marker_ --- A magic marker to ensure that older Cargoes, which only /// recognize format v0 (prior to checksum support in [`f4ca7390`]), do not /// proceed with parsing newer formats. Since [`EncodedDepInfo`] is merely /// an optimization, and to avoid adding complexity, Cargo recognizes only /// one version of [`CURRENT_ENCODED_DEP_INFO_VERSION`]. /// The current layout looks like this /// ```text /// +----------------------------+ /// | [0x01 0x00 0x00 0x00 0xff] | /// +----------------------------+ /// ``` /// These bytes will be interpreted as "one file tracked and an invalid /// [`DepInfoPathType`] variant with 255" by older Cargoes, causing them to /// stop parsing. This could prevent problematic parsing as noted in /// rust-lang/cargo#14712. /// * _Version_ --- The current format version. /// * _Number of files/envs_ --- A `u32` representing the number of things. /// * _File paths_ --- Zero or more paths of files the dep-info file depends on. /// Each path is encoded as the following: /// /// ```text /// +-----------+-------------+------------+---------------+-----------+-------+ /// | path type | len of path | path bytes | cksum exists? | file size | cksum | /// +-----------+-------------+------------+---------------+-----------+-------+ /// ``` /// * _Env var pairs_ --- Zero or more env vars the dep-info file depends on. /// Each env key-value pair is encoded as the following: /// ```text /// +------------+-----------+---------------+--------------+-------------+ /// | len of key | key bytes | value exists? | len of value | value bytes | /// +------------+-----------+---------------+--------------+-------------+ /// ``` /// /// [`f4ca7390`]: https://github.com/rust-lang/cargo/commit/f4ca739073185ea5e1148ff100bb4a06d3bf721d #[derive(Default, Debug, PartialEq, Eq)] pub struct EncodedDepInfo { pub files: Vec<(DepInfoPathType, PathBuf, Option<(u64, String)>)>, pub env: Vec<(String, Option)>, } impl EncodedDepInfo { pub fn parse(mut bytes: &[u8]) -> Option { let bytes = &mut bytes; read_magic_marker(bytes)?; let version = read_u8(bytes)?; if version != CURRENT_ENCODED_DEP_INFO_VERSION { return None; } let nfiles = read_usize(bytes)?; let mut files = Vec::with_capacity(nfiles); for _ in 0..nfiles { let ty = match read_u8(bytes)? { 0 => DepInfoPathType::PackageRootRelative, 1 => DepInfoPathType::TargetRootRelative, _ => return None, }; let path_bytes = read_bytes(bytes)?; let path = paths::bytes2path(path_bytes).ok()?; let has_checksum = read_bool(bytes)?; let checksum_info = has_checksum .then(|| { let file_len = read_u64(bytes); let checksum_string = read_bytes(bytes) .map(Vec::from) .and_then(|v| String::from_utf8(v).ok()); file_len.zip(checksum_string) }) .flatten(); files.push((ty, path, checksum_info)); } let nenv = read_usize(bytes)?; let mut env = Vec::with_capacity(nenv); for _ in 0..nenv { let key = str::from_utf8(read_bytes(bytes)?).ok()?.to_string(); let val = match read_u8(bytes)? { 0 => None, 1 => Some(str::from_utf8(read_bytes(bytes)?).ok()?.to_string()), _ => return None, }; env.push((key, val)); } return Some(EncodedDepInfo { files, env }); /// See [`EncodedDepInfo`] for why a magic marker exists. fn read_magic_marker(bytes: &mut &[u8]) -> Option<()> { let _size = read_usize(bytes)?; let path_type = read_u8(bytes)?; if path_type != u8::MAX { // Old depinfo. Give up parsing it. None } else { Some(()) } } fn read_usize(bytes: &mut &[u8]) -> Option { let ret = bytes.get(..4)?; *bytes = &bytes[4..]; Some(u32::from_le_bytes(ret.try_into().unwrap()) as usize) } fn read_u64(bytes: &mut &[u8]) -> Option { let ret = bytes.get(..8)?; *bytes = &bytes[8..]; Some(u64::from_le_bytes(ret.try_into().unwrap())) } fn read_bool(bytes: &mut &[u8]) -> Option { read_u8(bytes).map(|b| b != 0) } fn read_u8(bytes: &mut &[u8]) -> Option { let ret = *bytes.get(0)?; *bytes = &bytes[1..]; Some(ret) } fn read_bytes<'a>(bytes: &mut &'a [u8]) -> Option<&'a [u8]> { let n = read_usize(bytes)? as usize; let ret = bytes.get(..n)?; *bytes = &bytes[n..]; Some(ret) } } pub fn serialize(&self) -> CargoResult> { let mut ret = Vec::new(); let dst = &mut ret; write_magic_marker(dst); dst.push(CURRENT_ENCODED_DEP_INFO_VERSION); write_usize(dst, self.files.len()); for (ty, file, checksum_info) in self.files.iter() { match ty { DepInfoPathType::PackageRootRelative => dst.push(0), DepInfoPathType::TargetRootRelative => dst.push(1), } write_bytes(dst, paths::path2bytes(file)?); write_bool(dst, checksum_info.is_some()); if let Some((len, checksum)) = checksum_info { write_u64(dst, *len); write_bytes(dst, checksum); } } write_usize(dst, self.env.len()); for (key, val) in self.env.iter() { write_bytes(dst, key); match val { None => dst.push(0), Some(val) => { dst.push(1); write_bytes(dst, val); } } } return Ok(ret); /// See [`EncodedDepInfo`] for why a magic marker exists. /// /// There is an assumption that there is always at least a file. fn write_magic_marker(dst: &mut Vec) { write_usize(dst, 1); dst.push(u8::MAX); } fn write_bytes(dst: &mut Vec, val: impl AsRef<[u8]>) { let val = val.as_ref(); write_usize(dst, val.len()); dst.extend_from_slice(val); } fn write_usize(dst: &mut Vec, val: usize) { dst.extend(&u32::to_le_bytes(val as u32)); } fn write_u64(dst: &mut Vec, val: u64) { dst.extend(&u64::to_le_bytes(val)); } fn write_bool(dst: &mut Vec, val: bool) { dst.push(u8::from(val)); } } } /// Parses the dep-info file coming out of rustc into a Cargo-specific format. /// /// This function will parse `rustc_dep_info` as a makefile-style dep info to /// learn about the all files which a crate depends on. This is then /// re-serialized into the `cargo_dep_info` path in a Cargo-specific format. /// /// The `pkg_root` argument here is the absolute path to the directory /// containing `Cargo.toml` for this crate that was compiled. The paths listed /// in the rustc dep-info file may or may not be absolute but we'll want to /// consider all of them relative to the `root` specified. /// /// The `rustc_cwd` argument is the absolute path to the cwd of the compiler /// when it was invoked. /// /// If the `allow_package` argument is true, then package-relative paths are /// included. If it is false, then package-relative paths are skipped and /// ignored (typically used for registry or git dependencies where we assume /// the source never changes, and we don't want the cost of running `stat` on /// all those files). See the module-level docs for the note about /// `-Zbinary-dep-depinfo` for more details on why this is done. /// /// The serialized Cargo format will contain a list of files, all of which are /// relative if they're under `root`. or absolute if they're elsewhere. /// /// The `env_config` argument is a set of environment variables that are /// defined in `[env]` table of the `config.toml`. pub fn translate_dep_info( rustc_dep_info: &Path, cargo_dep_info: &Path, rustc_cwd: &Path, pkg_root: &Path, target_root: &Path, rustc_cmd: &ProcessBuilder, allow_package: bool, env_config: &Arc>, ) -> CargoResult<()> { let depinfo = parse_rustc_dep_info(rustc_dep_info)?; let target_root = crate::util::try_canonicalize(target_root)?; let pkg_root = crate::util::try_canonicalize(pkg_root)?; let mut on_disk_info = EncodedDepInfo::default(); on_disk_info.env = depinfo.env; // This is a bit of a tricky statement, but here we're *removing* the // dependency on environment variables that were defined specifically for // the command itself. Environment variables returned by `get_envs` includes // environment variables like: // // * `OUT_DIR` if applicable // * env vars added by a build script, if any // // The general idea here is that the dep info file tells us what, when // changed, should cause us to rebuild the crate. These environment // variables are synthesized by Cargo and/or the build script, and the // intention is that their values are tracked elsewhere for whether the // crate needs to be rebuilt. // // For example a build script says when it needs to be rerun and otherwise // it's assumed to produce the same output, so we're guaranteed that env // vars defined by the build script will always be the same unless the build // script itself reruns, in which case the crate will rerun anyway. // // For things like `OUT_DIR` it's a bit sketchy for now. Most of the time // that's used for code generation but this is technically buggy where if // you write a binary that does `println!("{}", env!("OUT_DIR"))` we won't // recompile that if you move the target directory. Hopefully that's not too // bad of an issue for now... // // This also includes `CARGO` since if the code is explicitly wanting to // know that path, it should be rebuilt if it changes. The CARGO path is // not tracked elsewhere in the fingerprint. // // For cargo#13280, We trace env vars that are defined in the `[env]` config table. on_disk_info.env.retain(|(key, _)| { ManifestMetadata::should_track(key) || env_config.contains_key(key) || !rustc_cmd.get_envs().contains_key(key) || key == CARGO_ENV }); let serialize_path = |file| { // The path may be absolute or relative, canonical or not. Make sure // it is canonicalized so we are comparing the same kinds of paths. let abs_file = rustc_cwd.join(file); // If canonicalization fails, just use the abs path. There is currently // a bug where --remap-path-prefix is affecting .d files, causing them // to point to non-existent paths. let canon_file = crate::util::try_canonicalize(&abs_file).unwrap_or_else(|_| abs_file.clone()); let (ty, path) = if let Ok(stripped) = canon_file.strip_prefix(&target_root) { (DepInfoPathType::TargetRootRelative, stripped) } else if let Ok(stripped) = canon_file.strip_prefix(&pkg_root) { if !allow_package { return None; } (DepInfoPathType::PackageRootRelative, stripped) } else { // It's definitely not target root relative, but this is an absolute path (since it was // joined to rustc_cwd) and as such re-joining it later to the target root will have no // effect. (DepInfoPathType::TargetRootRelative, &*abs_file) }; Some((ty, path.to_owned())) }; for (file, checksum_info) in depinfo.files { let Some((path_type, path)) = serialize_path(file) else { continue; }; on_disk_info.files.push(( path_type, path, checksum_info.map(|(len, checksum)| (len, checksum.to_string())), )); } paths::write(cargo_dep_info, on_disk_info.serialize()?)?; Ok(()) } /// Parse the `.d` dep-info file generated by rustc. pub fn parse_rustc_dep_info(rustc_dep_info: &Path) -> CargoResult { let contents = paths::read(rustc_dep_info)?; let mut ret = RustcDepInfo::default(); let mut found_deps = false; for line in contents.lines() { if let Some(rest) = line.strip_prefix("# env-dep:") { let mut parts = rest.splitn(2, '='); let Some(env_var) = parts.next() else { continue; }; let env_val = match parts.next() { Some(s) => Some(unescape_env(s)?), None => None, }; ret.env.push((unescape_env(env_var)?, env_val)); } else if let Some(pos) = line.find(": ") { if found_deps { continue; } found_deps = true; let mut deps = line[pos + 2..].split_whitespace(); while let Some(s) = deps.next() { let mut file = s.to_string(); while file.ends_with('\\') { file.pop(); file.push(' '); file.push_str(deps.next().ok_or_else(|| { crate::util::internal("malformed dep-info format, trailing \\") })?); } ret.files.entry(file.into()).or_default(); } } else if let Some(rest) = line.strip_prefix("# checksum:") { let mut parts = rest.splitn(3, ' '); let Some(checksum) = parts.next().map(Checksum::from_str).transpose()? else { continue; }; let Some(Ok(file_len)) = parts .next() .and_then(|s| s.strip_prefix("file_len:").map(|s| s.parse::())) else { continue; }; let Some(path) = parts.next().map(PathBuf::from) else { continue; }; ret.files.insert(path, Some((file_len, checksum))); } } return Ok(ret); // rustc tries to fit env var names and values all on a single line, which // means it needs to escape `\r` and `\n`. The escape syntax used is "\n" // which means that `\` also needs to be escaped. fn unescape_env(s: &str) -> CargoResult { let mut ret = String::with_capacity(s.len()); let mut chars = s.chars(); while let Some(c) = chars.next() { if c != '\\' { ret.push(c); continue; } match chars.next() { Some('\\') => ret.push('\\'), Some('n') => ret.push('\n'), Some('r') => ret.push('\r'), Some(c) => bail!("unknown escape character `{}`", c), None => bail!("unterminated escape character"), } } Ok(ret) } } /// Parses Cargo's internal [`EncodedDepInfo`] structure that was previously /// serialized to disk. /// /// Note that this is not rustc's `*.d` files. /// /// Also note that rustc's `*.d` files are translated to Cargo-specific /// `EncodedDepInfo` files after compilations have finished in /// [`translate_dep_info`]. /// /// Returns `None` if the file is corrupt or couldn't be read from disk. This /// indicates that the crate should likely be rebuilt. pub fn parse_dep_info( pkg_root: &Path, target_root: &Path, dep_info: &Path, ) -> CargoResult> { let Ok(data) = paths::read_bytes(dep_info) else { return Ok(None); }; let Some(info) = EncodedDepInfo::parse(&data) else { tracing::warn!("failed to parse cargo's dep-info at {:?}", dep_info); return Ok(None); }; let mut ret = RustcDepInfo::default(); ret.env = info.env; ret.files .extend(info.files.into_iter().map(|(ty, path, checksum_info)| { ( make_absolute_path(ty, pkg_root, target_root, path), checksum_info.and_then(|(file_len, checksum)| { Checksum::from_str(&checksum).ok().map(|c| (file_len, c)) }), ) })); Ok(Some(ret)) } fn make_absolute_path( ty: DepInfoPathType, pkg_root: &Path, target_root: &Path, path: PathBuf, ) -> PathBuf { match ty { DepInfoPathType::PackageRootRelative => pkg_root.join(path), // N.B. path might be absolute here in which case the join will have no effect DepInfoPathType::TargetRootRelative => target_root.join(path), } } /// Some algorithms are here to ensure compatibility with possible rustc outputs. /// The presence of an algorithm here is not a suggestion that it's fit for use. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum ChecksumAlgo { Sha256, Blake3, } impl ChecksumAlgo { fn hash_len(&self) -> usize { match self { ChecksumAlgo::Sha256 | ChecksumAlgo::Blake3 => 32, } } } impl FromStr for ChecksumAlgo { type Err = InvalidChecksum; fn from_str(s: &str) -> Result { match s { "sha256" => Ok(Self::Sha256), "blake3" => Ok(Self::Blake3), _ => Err(InvalidChecksum::InvalidChecksumAlgo), } } } impl fmt::Display for ChecksumAlgo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match self { ChecksumAlgo::Sha256 => "sha256", ChecksumAlgo::Blake3 => "blake3", }) } } #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct Checksum { algo: ChecksumAlgo, /// If the algorithm uses fewer than 32 bytes, then the remaining bytes will be zero. value: [u8; 32], } impl Checksum { pub fn new(algo: ChecksumAlgo, value: [u8; 32]) -> Self { Self { algo, value } } pub fn compute(algo: ChecksumAlgo, contents: impl Read) -> Result { // Buffer size is the recommended amount to fully leverage SIMD instructions on AVX-512 as per // blake3 documentation. let mut buf = vec![0; 16 * 1024]; let mut ret = Self { algo, value: [0; 32], }; let len = algo.hash_len(); let value = &mut ret.value[..len]; fn digest( mut hasher: T, mut update: impl FnMut(&mut T, &[u8]), finish: impl FnOnce(T, &mut [u8]), mut contents: impl Read, buf: &mut [u8], value: &mut [u8], ) -> Result<(), io::Error> { loop { let bytes_read = contents.read(buf)?; if bytes_read == 0 { break; } update(&mut hasher, &buf[0..bytes_read]); } finish(hasher, value); Ok(()) } match algo { ChecksumAlgo::Sha256 => { digest( Sha256::new(), |h, b| { h.update(b); }, |mut h, out| out.copy_from_slice(&h.finish()), contents, &mut buf, value, )?; } ChecksumAlgo::Blake3 => { digest( blake3::Hasher::new(), |h, b| { h.update(b); }, |h, out| out.copy_from_slice(h.finalize().as_bytes()), contents, &mut buf, value, )?; } } Ok(ret) } pub fn algo(&self) -> ChecksumAlgo { self.algo } pub fn value(&self) -> &[u8; 32] { &self.value } } impl FromStr for Checksum { type Err = InvalidChecksum; fn from_str(s: &str) -> Result { let mut parts = s.split('='); let Some(algo) = parts.next().map(ChecksumAlgo::from_str).transpose()? else { return Err(InvalidChecksum::InvalidFormat); }; let Some(checksum) = parts.next() else { return Err(InvalidChecksum::InvalidFormat); }; let mut value = [0; 32]; if hex::decode_to_slice(checksum, &mut value[0..algo.hash_len()]).is_err() { return Err(InvalidChecksum::InvalidChecksum(algo)); } Ok(Self { algo, value }) } } impl fmt::Display for Checksum { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut checksum = [0; 64]; let hash_len = self.algo.hash_len(); hex::encode_to_slice(&self.value[0..hash_len], &mut checksum[0..(hash_len * 2)]) .map_err(|_| fmt::Error)?; write!( f, "{}={}", self.algo, str::from_utf8(&checksum[0..(hash_len * 2)]).unwrap_or_default() ) } } #[derive(Debug, thiserror::Error)] pub enum InvalidChecksum { #[error("algorithm portion incorrect, expected `sha256`, or `blake3`")] InvalidChecksumAlgo, #[error("expected {} hexadecimal digits in checksum portion", .0.hash_len() * 2)] InvalidChecksum(ChecksumAlgo), #[error("expected a string with format \"algorithm=hex_checksum\"")] InvalidFormat, } #[cfg(test)] mod encoded_dep_info { use super::*; #[track_caller] fn gen_test(checksum: bool) { let checksum = checksum.then_some((768, "c01efc669f09508b55eced32d3c88702578a7c3e".into())); let lib_rs = ( DepInfoPathType::TargetRootRelative, PathBuf::from("src/lib.rs"), checksum.clone(), ); let depinfo = EncodedDepInfo { files: vec![lib_rs.clone()], env: Vec::new(), }; let data = depinfo.serialize().unwrap(); assert_eq!(EncodedDepInfo::parse(&data).unwrap(), depinfo); let mod_rs = ( DepInfoPathType::TargetRootRelative, PathBuf::from("src/mod.rs"), checksum.clone(), ); let depinfo = EncodedDepInfo { files: vec![lib_rs.clone(), mod_rs.clone()], env: Vec::new(), }; let data = depinfo.serialize().unwrap(); assert_eq!(EncodedDepInfo::parse(&data).unwrap(), depinfo); let depinfo = EncodedDepInfo { files: vec![lib_rs, mod_rs], env: vec![ ("Gimli".into(), Some("Legolas".into())), ("Beren".into(), Some("LΓΊthien".into())), ], }; let data = depinfo.serialize().unwrap(); assert_eq!(EncodedDepInfo::parse(&data).unwrap(), depinfo); } #[test] fn round_trip() { gen_test(false); } #[test] fn round_trip_with_checksums() { gen_test(true); } #[test] fn path_type_is_u8_max() { #[rustfmt::skip] let data = [ 0x01, 0x00, 0x00, 0x00, 0xff, // magic marker CURRENT_ENCODED_DEP_INFO_VERSION, // version 0x01, 0x00, 0x00, 0x00, // # of files 0x00, // path type 0x04, 0x00, 0x00, 0x00, // len of path 0x72, 0x75, 0x73, 0x74, // path bytes ("rust") 0x00, // cksum exists? 0x00, 0x00, 0x00, 0x00, // # of env vars ]; // The current cargo doesn't recognize the magic marker. assert_eq!( EncodedDepInfo::parse(&data).unwrap(), EncodedDepInfo { files: vec![(DepInfoPathType::PackageRootRelative, "rust".into(), None)], env: Vec::new(), } ); } #[test] fn parse_v0_fingerprint_dep_info() { #[rustfmt::skip] let data = [ 0x01, 0x00, 0x00, 0x00, // # of files 0x00, // path type 0x04, 0x00, 0x00, 0x00, // len of path 0x72, 0x75, 0x73, 0x74, // path bytes: "rust" 0x00, 0x00, 0x00, 0x00, // # of env vars ]; // Cargo can't recognize v0 after `-Zchecksum-freshess` added. assert!(EncodedDepInfo::parse(&data).is_none()); } } cargo-0.86.0/src/cargo/core/compiler/fingerprint/dirty_reason.rs000064400000000000000000000276161046102023000230510ustar 00000000000000use std::fmt; use std::fmt::Debug; use super::*; use crate::core::Shell; /// Tells a better story of why a build is considered "dirty" that leads /// to a recompile. Usually constructed via [`Fingerprint::compare`]. /// /// [`Fingerprint::compare`]: super::Fingerprint::compare #[derive(Clone, Debug)] pub enum DirtyReason { RustcChanged, FeaturesChanged { old: String, new: String, }, DeclaredFeaturesChanged { old: String, new: String, }, TargetConfigurationChanged, PathToSourceChanged, ProfileConfigurationChanged, RustflagsChanged { old: Vec, new: Vec, }, ConfigSettingsChanged, CompileKindChanged, LocalLengthsChanged, PrecalculatedComponentsChanged { old: String, new: String, }, ChecksumUseChanged { old: bool, }, DepInfoOutputChanged { old: PathBuf, new: PathBuf, }, RerunIfChangedOutputFileChanged { old: PathBuf, new: PathBuf, }, RerunIfChangedOutputPathsChanged { old: Vec, new: Vec, }, EnvVarsChanged { old: String, new: String, }, EnvVarChanged { name: String, old_value: Option, new_value: Option, }, LocalFingerprintTypeChanged { old: &'static str, new: &'static str, }, NumberOfDependenciesChanged { old: usize, new: usize, }, UnitDependencyNameChanged { old: InternedString, new: InternedString, }, UnitDependencyInfoChanged { old_name: InternedString, old_fingerprint: u64, new_name: InternedString, new_fingerprint: u64, }, FsStatusOutdated(FsStatus), NothingObvious, Forced, /// First time to build something. FreshBuild, } trait ShellExt { fn dirty_because(&mut self, unit: &Unit, s: impl fmt::Display) -> CargoResult<()>; } impl ShellExt for Shell { fn dirty_because(&mut self, unit: &Unit, s: impl fmt::Display) -> CargoResult<()> { self.status("Dirty", format_args!("{}: {s}", &unit.pkg)) } } struct FileTimeDiff { old_time: FileTime, new_time: FileTime, } impl fmt::Display for FileTimeDiff { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s_diff = self.new_time.seconds() - self.old_time.seconds(); if s_diff >= 1 { fmt::Display::fmt( &humantime::Duration::from(std::time::Duration::from_secs(s_diff as u64)), f, ) } else { // format nanoseconds as it is, humantime would display ms, us and ns let ns_diff = self.new_time.nanoseconds() - self.old_time.nanoseconds(); write!(f, "{ns_diff}ns") } } } #[derive(Copy, Clone)] struct After { old_time: FileTime, new_time: FileTime, what: &'static str, } impl fmt::Display for After { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { old_time, new_time, what, } = *self; let diff = FileTimeDiff { old_time, new_time }; write!(f, "{new_time}, {diff} after {what} at {old_time}") } } impl DirtyReason { /// Whether a build is dirty because it is a fresh build being kicked off. pub fn is_fresh_build(&self) -> bool { matches!(self, DirtyReason::FreshBuild) } fn after(old_time: FileTime, new_time: FileTime, what: &'static str) -> After { After { old_time, new_time, what, } } pub fn present_to(&self, s: &mut Shell, unit: &Unit, root: &Path) -> CargoResult<()> { match self { DirtyReason::RustcChanged => s.dirty_because(unit, "the toolchain changed"), DirtyReason::FeaturesChanged { .. } => { s.dirty_because(unit, "the list of features changed") } DirtyReason::DeclaredFeaturesChanged { .. } => { s.dirty_because(unit, "the list of declared features changed") } DirtyReason::TargetConfigurationChanged => { s.dirty_because(unit, "the target configuration changed") } DirtyReason::PathToSourceChanged => { s.dirty_because(unit, "the path to the source changed") } DirtyReason::ProfileConfigurationChanged => { s.dirty_because(unit, "the profile configuration changed") } DirtyReason::RustflagsChanged { .. } => s.dirty_because(unit, "the rustflags changed"), DirtyReason::ConfigSettingsChanged => { s.dirty_because(unit, "the config settings changed") } DirtyReason::CompileKindChanged => { s.dirty_because(unit, "the rustc compile kind changed") } DirtyReason::LocalLengthsChanged => { s.dirty_because(unit, "the local lengths changed")?; s.note( "this could happen because of added/removed `cargo::rerun-if` instructions in the build script", )?; Ok(()) } DirtyReason::PrecalculatedComponentsChanged { .. } => { s.dirty_because(unit, "the precalculated components changed") } DirtyReason::ChecksumUseChanged { old } => { if *old { s.dirty_because( unit, "the prior compilation used checksum freshness and this one does not", ) } else { s.dirty_because(unit, "checksum freshness requested, prior compilation did not use checksum freshness") } } DirtyReason::DepInfoOutputChanged { .. } => { s.dirty_because(unit, "the dependency info output changed") } DirtyReason::RerunIfChangedOutputFileChanged { .. } => { s.dirty_because(unit, "rerun-if-changed output file path changed") } DirtyReason::RerunIfChangedOutputPathsChanged { .. } => { s.dirty_because(unit, "the rerun-if-changed instructions changed") } DirtyReason::EnvVarsChanged { .. } => { s.dirty_because(unit, "the environment variables changed") } DirtyReason::EnvVarChanged { name, .. } => { s.dirty_because(unit, format_args!("the env variable {name} changed")) } DirtyReason::LocalFingerprintTypeChanged { .. } => { s.dirty_because(unit, "the local fingerprint type changed") } DirtyReason::NumberOfDependenciesChanged { old, new } => s.dirty_because( unit, format_args!("number of dependencies changed ({old} => {new})",), ), DirtyReason::UnitDependencyNameChanged { old, new } => s.dirty_because( unit, format_args!("name of dependency changed ({old} => {new})"), ), DirtyReason::UnitDependencyInfoChanged { .. } => { s.dirty_because(unit, "dependency info changed") } DirtyReason::FsStatusOutdated(status) => match status { FsStatus::Stale => s.dirty_because(unit, "stale, unknown reason"), FsStatus::StaleItem(item) => match item { StaleItem::MissingFile(missing_file) => { let file = missing_file.strip_prefix(root).unwrap_or(&missing_file); s.dirty_because( unit, format_args!("the file `{}` is missing", file.display()), ) } StaleItem::UnableToReadFile(file) => { let file = file.strip_prefix(root).unwrap_or(&file); s.dirty_because( unit, format_args!("the file `{}` could not be read", file.display()), ) } StaleItem::FailedToReadMetadata(file) => { let file = file.strip_prefix(root).unwrap_or(&file); s.dirty_because( unit, format_args!("couldn't read metadata for file `{}`", file.display()), ) } StaleItem::ChangedFile { stale, stale_mtime, reference_mtime, .. } => { let file = stale.strip_prefix(root).unwrap_or(&stale); let after = Self::after(*reference_mtime, *stale_mtime, "last build"); s.dirty_because( unit, format_args!("the file `{}` has changed ({after})", file.display()), ) } StaleItem::ChangedChecksum { source, stored_checksum, new_checksum, } => { let file = source.strip_prefix(root).unwrap_or(&source); s.dirty_because( unit, format_args!( "the file `{}` has changed (checksum didn't match, {stored_checksum} != {new_checksum})", file.display(), ), ) } StaleItem::FileSizeChanged { path, old_size, new_size, } => { let file = path.strip_prefix(root).unwrap_or(&path); s.dirty_because( unit, format_args!( "file size changed ({old_size} != {new_size}) for `{}`", file.display() ), ) } StaleItem::MissingChecksum(path) => { let file = path.strip_prefix(root).unwrap_or(&path); s.dirty_because( unit, format_args!("the checksum for file `{}` is missing", file.display()), ) } StaleItem::ChangedEnv { var, .. } => s.dirty_because( unit, format_args!("the environment variable {var} changed"), ), }, FsStatus::StaleDependency { name, dep_mtime, max_mtime, .. } => { let after = Self::after(*max_mtime, *dep_mtime, "last build"); s.dirty_because( unit, format_args!("the dependency {name} was rebuilt ({after})"), ) } FsStatus::StaleDepFingerprint { name } => { s.dirty_because(unit, format_args!("the dependency {name} was rebuilt")) } FsStatus::UpToDate { .. } => { unreachable!() } }, DirtyReason::NothingObvious => { // See comment in fingerprint compare method. s.dirty_because(unit, "the fingerprint comparison turned up nothing obvious") } DirtyReason::Forced => s.dirty_because(unit, "forced"), DirtyReason::FreshBuild => s.dirty_because(unit, "fresh build"), } } } cargo-0.86.0/src/cargo/core/compiler/fingerprint/mod.rs000064400000000000000000002550131046102023000211200ustar 00000000000000//! 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 //! `.fingerprint` directory, that tracks information about the Unit. If the //! fingerprint is missing (such as the first time the unit is being //! compiled), then the unit is dirty. If any of the fingerprint fields //! change (like the name of the source file), then the Unit is considered //! dirty. //! //! The `Fingerprint` also tracks the fingerprints of all its dependencies, //! so a change in a dependency will propagate the "dirty" status up. //! //! - Filesystem mtime tracking is also used to check if a unit is dirty. //! See the section below on "Mtime comparison" for more details. There //! are essentially two parts to mtime tracking: //! //! 1. The mtime of a Unit's output files is compared to the mtime of all //! its dependencies' output file mtimes (see //! [`check_filesystem`]). If any output is missing, or is //! older than a dependency's output, then the unit is dirty. //! 2. The mtime of a Unit's source files is compared to the mtime of its //! dep-info file in the fingerprint directory (see [`find_stale_file`]). //! The dep-info file is used as an anchor to know when the last build of //! the unit was done. See the "dep-info files" section below for more //! details. If any input files are missing, or are newer than the //! dep-info, then the unit is dirty. //! //! - Alternatively if you're using the unstable feature `checksum-freshness` //! mtimes are ignored entirely in favor of comparing first the file size, and //! then the checksum with a known prior value emitted by rustc. Only nightly //! rustc will emit the needed metadata at the time of writing. This is dependent //! on the unstable feature `-Z checksum-hash-algorithm`. //! //! Note: Fingerprinting is not a perfect solution. Filesystem mtime tracking //! is notoriously imprecise and problematic. Only a small part of the //! environment is captured. This is a balance of performance, simplicity, and //! completeness. Sandboxing, hashing file contents, tracking every file //! access, environment variable, and network operation would ensure more //! reliable and reproducible builds at the cost of being complex, slow, and //! platform-dependent. //! //! ## Fingerprints and [`UnitHash`]s //! //! [`Metadata`] tracks several [`UnitHash`]s, including //! [`Metadata::unit_id`], [`Metadata::c_metadata`], and [`Metadata::c_extra_filename`]. //! See its documentation for more details. //! //! NOTE: Not all output files are isolated via filename hashes (like dylibs). //! The fingerprint directory uses a hash, but sometimes units share the same //! fingerprint directory (when they don't have Metadata) so care should be //! taken to handle this! //! //! Fingerprints and [`UnitHash`]s are similar, and track some of the same things. //! [`UnitHash`]s contains information that is required to keep Units separate. //! The Fingerprint includes additional information that should cause a //! recompile, but it is desired to reuse the same filenames. A comparison //! of what is tracked: //! //! Value | Fingerprint | `Metadata::unit_id` | `Metadata::c_metadata` | `Metadata::c_extra_filename` //! -------------------------------------------|-------------|---------------------|------------------------|---------- //! rustc | βœ“ | βœ“ | βœ“ | βœ“ //! [`Profile`] | βœ“ | βœ“ | βœ“ | βœ“ //! `cargo rustc` extra args | βœ“ | βœ“[^7] | | βœ“[^7] //! [`CompileMode`] | βœ“ | βœ“ | βœ“ | βœ“ //! Target Name | βœ“ | βœ“ | βœ“ | βœ“ //! `TargetKind` (bin/lib/etc.) | βœ“ | βœ“ | βœ“ | βœ“ //! Enabled Features | βœ“ | βœ“ | βœ“ | βœ“ //! Declared Features | βœ“ | | | //! Immediate dependency’s hashes | βœ“[^1] | βœ“ | βœ“ | βœ“ //! [`CompileKind`] (host/target) | βœ“ | βœ“ | βœ“ | βœ“ //! `__CARGO_DEFAULT_LIB_METADATA`[^4] | | βœ“ | βœ“ | βœ“ //! `package_id` | | βœ“ | βœ“ | βœ“ //! Target src path relative to ws | βœ“ | | | //! Target flags (test/bench/for_host/edition) | βœ“ | | | //! -C incremental=… flag | βœ“ | | | //! mtime of sources | βœ“[^3] | | | //! RUSTFLAGS/RUSTDOCFLAGS | βœ“ | βœ“[^7] | | βœ“[^7] //! [`Lto`] flags | βœ“ | βœ“ | βœ“ | βœ“ //! config settings[^5] | βœ“ | | | //! `is_std` | | βœ“ | βœ“ | βœ“ //! `[lints]` table[^6] | βœ“ | | | //! `[lints.rust.unexpected_cfgs.check-cfg]` | βœ“ | | | //! //! [^1]: Build script and bin dependencies are not included. //! //! [^3]: See below for details on mtime tracking. //! //! [^4]: `__CARGO_DEFAULT_LIB_METADATA` is set by rustbuild to embed the //! release channel (bootstrap/stable/beta/nightly) in libstd. //! //! [^5]: Config settings that are not otherwise captured anywhere else. //! Currently, this is only `doc.extern-map`. //! //! [^6]: Via [`Manifest::lint_rustflags`][crate::core::Manifest::lint_rustflags] //! //! [^7]: extra-flags and RUSTFLAGS are conditionally excluded when `--remap-path-prefix` is //! present to avoid breaking build reproducibility while we wait for trim-paths //! //! When deciding what should go in the Metadata vs the Fingerprint, consider //! that some files (like dylibs) do not have a hash in their filename. Thus, //! if a value changes, only the fingerprint will detect the change (consider, //! for example, swapping between different features). Fields that are only in //! Metadata generally aren't relevant to the fingerprint because they //! fundamentally change the output (like target vs host changes the directory //! where it is emitted). //! //! ## Fingerprint files //! //! Fingerprint information is stored in the //! `target/{debug,release}/.fingerprint/` directory. Each Unit is stored in a //! separate directory. Each Unit directory contains: //! //! - A file with a 16 hex-digit hash. This is the Fingerprint hash, used for //! quick loading and comparison. //! - A `.json` file that contains details about the Fingerprint. This is only //! used to log details about *why* a fingerprint is considered dirty. //! `CARGO_LOG=cargo::core::compiler::fingerprint=trace cargo build` can be //! used to display this log information. //! - A "dep-info" file which is a translation of rustc's `*.d` dep-info files //! to a Cargo-specific format that tweaks file names and is optimized for //! reading quickly. //! - An `invoked.timestamp` file whose filesystem mtime is updated every time //! the Unit is built. This is used for capturing the time when the build //! starts, to detect if files are changed in the middle of the build. See //! below for more details. //! //! Note that some units are a little different. A Unit for *running* a build //! script or for `rustdoc` does not have a dep-info file (it's not //! applicable). Build script `invoked.timestamp` files are in the build //! output directory. //! //! ## Fingerprint calculation //! //! After the list of Units has been calculated, the Units are added to the //! [`JobQueue`]. As each one is added, the fingerprint is calculated, and the //! dirty/fresh status is recorded. A closure is used to update the fingerprint //! on-disk when the Unit successfully finishes. The closure will recompute the //! Fingerprint based on the updated information. If the Unit fails to compile, //! the fingerprint is not updated. //! //! Fingerprints are cached in the [`BuildRunner`]. This makes computing //! Fingerprints faster, but also is necessary for properly updating //! dependency information. Since a Fingerprint includes the Fingerprints of //! all dependencies, when it is updated, by using `Arc` clones, it //! automatically picks up the updates to its dependencies. //! //! ### dep-info files //! //! Cargo has several kinds of "dep info" files: //! //! * dep-info files generated by `rustc`. //! * Fingerprint dep-info files translated from the first one. //! * dep-info for external build system integration. //! * Unstable `-Zbinary-dep-depinfo`. //! //! #### `rustc` dep-info files //! //! Cargo passes the `--emit=dep-info` flag to `rustc` so that `rustc` will //! generate a "dep info" file (with the `.d` extension). This is a //! Makefile-like syntax that includes all of the source files used to build //! the crate. This file is used by Cargo to know which files to check to see //! if the crate will need to be rebuilt. Example: //! //! ```makefile //! /path/to/target/debug/deps/cargo-b6219d178925203d: src/bin/main.rs src/bin/cargo/cli.rs # … etc. //! ``` //! //! #### Fingerprint dep-info files //! //! After `rustc` exits successfully, Cargo will read the first kind of dep //! info file and translate it into a binary format that is stored in the //! fingerprint directory ([`translate_dep_info`]). //! //! These are used to quickly scan for any changed files. The mtime of the //! fingerprint dep-info file itself is used as the reference for comparing the //! source files to determine if any of the source files have been modified //! (see [below](#mtime-comparison) for more detail). //! //! Note that Cargo parses the special `# env-var:...` comments in dep-info //! files to learn about environment variables that the rustc compile depends on. //! Cargo then later uses this to trigger a recompile if a referenced env var //! changes (even if the source didn't change). //! This also includes env vars generated from Cargo metadata like `CARGO_PKG_DESCRIPTION`. //! (See [`crate::core::manifest::ManifestMetadata`] //! //! #### dep-info files for build system integration. //! //! There is also a third dep-info file. Cargo will extend the file created by //! rustc with some additional information and saves this into the output //! directory. This is intended for build system integration. See the //! [`output_depinfo`] function for more detail. //! //! #### -Zbinary-dep-depinfo //! //! `rustc` has an experimental flag `-Zbinary-dep-depinfo`. This causes //! `rustc` to include binary files (like rlibs) in the dep-info file. This is //! primarily to support rustc development, so that Cargo can check the //! implicit dependency to the standard library (which lives in the sysroot). //! We want Cargo to recompile whenever the standard library rlib/dylibs //! change, and this is a generic mechanism to make that work. //! //! ### Mtime comparison //! //! The use of modification timestamps is the most common way a unit will be //! determined to be dirty or fresh between builds. There are many subtle //! issues and edge cases with mtime comparisons. This gives a high-level //! overview, but you'll need to read the code for the gritty details. Mtime //! handling is different for different unit kinds. The different styles are //! driven by the [`Fingerprint::local`] field, which is set based on the unit //! kind. //! //! The status of whether or not the mtime is "stale" or "up-to-date" is //! stored in [`Fingerprint::fs_status`]. //! //! All units will compare the mtime of its newest output file with the mtimes //! of the outputs of all its dependencies. If any output file is missing, //! then the unit is stale. If any dependency is newer, the unit is stale. //! //! #### Normal package mtime handling //! //! [`LocalFingerprint::CheckDepInfo`] is used for checking the mtime of //! packages. It compares the mtime of the input files (the source files) to //! the mtime of the dep-info file (which is written last after a build is //! finished). If the dep-info is missing, the unit is stale (it has never //! been built). The list of input files comes from the dep-info file. See the //! section above for details on dep-info files. //! //! Also note that although registry and git packages use [`CheckDepInfo`], none //! of their source files are included in the dep-info (see //! [`translate_dep_info`]), so for those kinds no mtime checking is done //! (unless `-Zbinary-dep-depinfo` is used). Repository and git packages are //! static, so there is no need to check anything. //! //! When a build is complete, the mtime of the dep-info file in the //! fingerprint directory is modified to rewind it to the time when the build //! started. This is done by creating an `invoked.timestamp` file when the //! build starts to capture the start time. The mtime is rewound to the start //! to handle the case where the user modifies a source file while a build is //! running. Cargo can't know whether or not the file was included in the //! build, so it takes a conservative approach of assuming the file was *not* //! included, and it should be rebuilt during the next build. //! //! #### Rustdoc mtime handling //! //! Rustdoc does not emit a dep-info file, so Cargo currently has a relatively //! simple system for detecting rebuilds. [`LocalFingerprint::Precalculated`] is //! used for rustdoc units. For registry packages, this is the package //! version. For git packages, it is the git hash. For path packages, it is //! the a string of the mtime of the newest file in the package. //! //! There are some known bugs with how this works, so it should be improved at //! some point. //! //! #### Build script mtime handling //! //! Build script mtime handling runs in different modes. There is the "old //! style" where the build script does not emit any `rerun-if` directives. In //! this mode, Cargo will use [`LocalFingerprint::Precalculated`]. See the //! "rustdoc" section above how it works. //! //! In the new-style, each `rerun-if` directive is translated to the //! corresponding [`LocalFingerprint`] variant. The [`RerunIfChanged`] variant //! compares the mtime of the given filenames against the mtime of the //! "output" file. //! //! Similar to normal units, the build script "output" file mtime is rewound //! to the time just before the build script is executed to handle mid-build //! modifications. //! //! ## Considerations for inclusion in a fingerprint //! //! Over time we've realized a few items which historically were included in //! fingerprint hashings should not actually be included. Examples are: //! //! * Modification time values. We strive to never include a modification time //! inside a `Fingerprint` to get hashed into an actual value. While //! theoretically fine to do, in practice this causes issues with common //! applications like Docker. Docker, after a layer is built, will zero out //! the nanosecond part of all filesystem modification times. This means that //! the actual modification time is different for all build artifacts, which //! if we tracked the actual values of modification times would cause //! unnecessary recompiles. To fix this we instead only track paths which are //! relevant. These paths are checked dynamically to see if they're up to //! date, and the modification time doesn't make its way into the fingerprint //! hash. //! //! * Absolute path names. We strive to maintain a property where if you rename //! a project directory Cargo will continue to preserve all build artifacts //! and reuse the cache. This means that we can't ever hash an absolute path //! name. Instead we always hash relative path names and the "root" is passed //! in at runtime dynamically. Some of this is best effort, but the general //! idea is that we assume all accesses within a crate stay within that //! crate. //! //! These are pretty tricky to test for unfortunately, but we should have a good //! test suite nowadays and lord knows Cargo gets enough testing in the wild! //! //! ## Build scripts //! //! The *running* of a build script ([`CompileMode::RunCustomBuild`]) is treated //! significantly different than all other Unit kinds. It has its own function //! for calculating the Fingerprint ([`calculate_run_custom_build`]) and has some //! unique considerations. It does not track the same information as a normal //! Unit. The information tracked depends on the `rerun-if-changed` and //! `rerun-if-env-changed` statements produced by the build script. If the //! script does not emit either of these statements, the Fingerprint runs in //! "old style" mode where an mtime change of *any* file in the package will //! cause the build script to be re-run. Otherwise, the fingerprint *only* //! tracks the individual "rerun-if" items listed by the build script. //! //! The "rerun-if" statements from a *previous* build are stored in the build //! output directory in a file called `output`. Cargo parses this file when //! the Unit for that build script is prepared for the [`JobQueue`]. The //! Fingerprint code can then use that information to compute the Fingerprint //! and compare against the old fingerprint hash. //! //! Care must be taken with build script Fingerprints because the //! [`Fingerprint::local`] value may be changed after the build script runs //! (such as if the build script adds or removes "rerun-if" items). //! //! Another complication is if a build script is overridden. In that case, the //! fingerprint is the hash of the output of the override. //! //! ## Special considerations //! //! Registry dependencies do not track the mtime of files. This is because //! registry dependencies are not expected to change (if a new version is //! used, the Package ID will change, causing a rebuild). Cargo currently //! partially works with Docker caching. When a Docker image is built, it has //! normal mtime information. However, when a step is cached, the nanosecond //! portions of all files is zeroed out. Currently this works, but care must //! be taken for situations like these. //! //! HFS on macOS only supports 1 second timestamps. This causes a significant //! number of problems, particularly with Cargo's testsuite which does rapid //! builds in succession. Other filesystems have various degrees of //! resolution. //! //! Various weird filesystems (such as network filesystems) also can cause //! complications. Network filesystems may track the time on the server //! (except when the time is set manually such as with //! `filetime::set_file_times`). Not all filesystems support modifying the //! mtime. //! //! See the [`A-rebuild-detection`] label on the issue tracker for more. //! //! [`check_filesystem`]: Fingerprint::check_filesystem //! [`Metadata`]: crate::core::compiler::Metadata //! [`Metadata::unit_id`]: crate::core::compiler::Metadata::unit_id //! [`Metadata::c_metadata`]: crate::core::compiler::Metadata::c_metadata //! [`Metadata::c_extra_filename`]: crate::core::compiler::Metadata::c_extra_filename //! [`UnitHash`]: crate::core::compiler::UnitHash //! [`Profile`]: crate::core::profiles::Profile //! [`CompileMode`]: crate::core::compiler::CompileMode //! [`Lto`]: crate::core::compiler::Lto //! [`CompileKind`]: crate::core::compiler::CompileKind //! [`JobQueue`]: super::job_queue::JobQueue //! [`output_depinfo`]: super::output_depinfo() //! [`CheckDepInfo`]: LocalFingerprint::CheckDepInfo //! [`RerunIfChanged`]: LocalFingerprint::RerunIfChanged //! [`CompileMode::RunCustomBuild`]: crate::core::compiler::CompileMode::RunCustomBuild //! [`A-rebuild-detection`]: https://github.com/rust-lang/cargo/issues?q=is%3Aissue+is%3Aopen+label%3AA-rebuild-detection mod dep_info; mod dirty_reason; use std::collections::hash_map::{Entry, HashMap}; use std::env; use std::fs; use std::fs::File; use std::hash::{self, Hash, Hasher}; use std::io::{self}; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; use std::time::SystemTime; use anyhow::format_err; use anyhow::Context as _; use cargo_util::paths; use filetime::FileTime; use serde::de; use serde::ser; use serde::{Deserialize, Serialize}; use tracing::{debug, info}; use crate::core::compiler::unit_graph::UnitDep; use crate::core::Package; use crate::util; use crate::util::errors::CargoResult; use crate::util::interning::InternedString; use crate::util::{internal, path_args, StableHasher}; use crate::{GlobalContext, CARGO_ENV}; use super::custom_build::BuildDeps; use super::{BuildContext, BuildRunner, FileFlavor, Job, Unit, Work}; pub use self::dep_info::parse_dep_info; pub use self::dep_info::parse_rustc_dep_info; pub use self::dep_info::translate_dep_info; pub use self::dep_info::Checksum; pub use self::dirty_reason::DirtyReason; /// Determines if a [`Unit`] is up-to-date, and if not prepares necessary work to /// update the persisted fingerprint. /// /// This function will inspect `Unit`, calculate a fingerprint for it, and then /// return an appropriate [`Job`] to run. The returned `Job` will be a noop if /// `unit` is considered "fresh", or if it was previously built and cached. /// Otherwise the `Job` returned will write out the true fingerprint to the /// filesystem, to be executed after the unit's work has completed. /// /// The `force` flag is a way to force the `Job` to be "dirty", or always /// update the fingerprint. **Beware using this flag** because it does not /// transitively propagate throughout the dependency graph, it only forces this /// one unit which is very unlikely to be what you want unless you're /// exclusively talking about top-level units. #[tracing::instrument( skip(build_runner, unit), fields(package_id = %unit.pkg.package_id(), target = unit.target.name()) )] pub fn prepare_target( build_runner: &mut BuildRunner<'_, '_>, unit: &Unit, force: bool, ) -> CargoResult { let bcx = build_runner.bcx; let loc = build_runner.files().fingerprint_file_path(unit, ""); debug!("fingerprint at: {}", loc.display()); // Figure out if this unit is up to date. After calculating the fingerprint // compare it to an old version, if any, and attempt to print diagnostic // information about failed comparisons to aid in debugging. let fingerprint = calculate(build_runner, unit)?; let mtime_on_use = build_runner.bcx.gctx.cli_unstable().mtime_on_use; let dirty_reason = compare_old_fingerprint(unit, &loc, &*fingerprint, mtime_on_use, force); let Some(dirty_reason) = dirty_reason else { return Ok(Job::new_fresh()); }; // We're going to rebuild, so ensure the source of the crate passes all // verification checks before we build it. // // The `Source::verify` method is intended to allow sources to execute // pre-build checks to ensure that the relevant source code is all // up-to-date and as expected. This is currently used primarily for // directory sources which will use this hook to perform an integrity check // on all files in the source to ensure they haven't changed. If they have // changed then an error is issued. let source_id = unit.pkg.package_id().source_id(); let sources = bcx.packages.sources(); let source = sources .get(source_id) .ok_or_else(|| internal("missing package source"))?; source.verify(unit.pkg.package_id())?; // Clear out the old fingerprint file if it exists. This protects when // compilation is interrupted leaving a corrupt file. For example, a // project with a lib.rs and integration test (two units): // // 1. Build the library and integration test. // 2. Make a change to lib.rs (NOT the integration test). // 3. Build the integration test, hit Ctrl-C while linking. With gcc, this // will leave behind an incomplete executable (zero size, or partially // written). NOTE: The library builds successfully, it is the linking // of the integration test that we are interrupting. // 4. Build the integration test again. // // Without the following line, then step 3 will leave a valid fingerprint // on the disk. Then step 4 will think the integration test is "fresh" // because: // // - There is a valid fingerprint hash on disk (written in step 1). // - The mtime of the output file (the corrupt integration executable // written in step 3) is newer than all of its dependencies. // - The mtime of the integration test fingerprint dep-info file (written // in step 1) is newer than the integration test's source files, because // we haven't modified any of its source files. // // But the executable is corrupt and needs to be rebuilt. Clearing the // fingerprint at step 3 ensures that Cargo never mistakes a partially // written output as up-to-date. if loc.exists() { // Truncate instead of delete so that compare_old_fingerprint will // still log the reason for the fingerprint failure instead of just // reporting "failed to read fingerprint" during the next build if // this build fails. paths::write(&loc, b"")?; } let write_fingerprint = if unit.mode.is_run_custom_build() { // For build scripts the `local` field of the fingerprint may change // while we're executing it. For example it could be in the legacy // "consider everything a dependency mode" and then we switch to "deps // are explicitly specified" mode. // // To handle this movement we need to regenerate the `local` field of a // build script's fingerprint after it's executed. We do this by // using the `build_script_local_fingerprints` function which returns a // thunk we can invoke on a foreign thread to calculate this. let build_script_outputs = Arc::clone(&build_runner.build_script_outputs); let metadata = build_runner.get_run_build_script_metadata(unit); let (gen_local, _overridden) = build_script_local_fingerprints(build_runner, unit); let output_path = build_runner.build_explicit_deps[unit] .build_script_output .clone(); Work::new(move |_| { let outputs = build_script_outputs.lock().unwrap(); let output = outputs .get(metadata) .expect("output must exist after running"); let deps = BuildDeps::new(&output_path, Some(output)); // FIXME: it's basically buggy that we pass `None` to `call_box` // here. See documentation on `build_script_local_fingerprints` // below for more information. Despite this just try to proceed and // hobble along if it happens to return `Some`. if let Some(new_local) = (gen_local)(&deps, None)? { *fingerprint.local.lock().unwrap() = new_local; } write_fingerprint(&loc, &fingerprint) }) } else { Work::new(move |_| write_fingerprint(&loc, &fingerprint)) }; Ok(Job::new_dirty(write_fingerprint, dirty_reason)) } /// Dependency edge information for fingerprints. This is generated for each /// dependency and is stored in a [`Fingerprint`]. #[derive(Clone)] struct DepFingerprint { /// The hash of the package id that this dependency points to pkg_id: u64, /// The crate name we're using for this dependency, which if we change we'll /// need to recompile! name: InternedString, /// Whether or not this dependency is flagged as a public dependency or not. public: bool, /// Whether or not this dependency is an rmeta dependency or a "full" /// dependency. In the case of an rmeta dependency our dependency edge only /// actually requires the rmeta from what we depend on, so when checking /// mtime information all files other than the rmeta can be ignored. only_requires_rmeta: bool, /// The dependency's fingerprint we recursively point to, containing all the /// other hash information we'd otherwise need. fingerprint: Arc, } /// A fingerprint can be considered to be a "short string" representing the /// state of a world for a package. /// /// If a fingerprint ever changes, then the package itself needs to be /// recompiled. Inputs to the fingerprint include source code modifications, /// compiler flags, compiler version, etc. This structure is not simply a /// `String` due to the fact that some fingerprints cannot be calculated lazily. /// /// Path sources, for example, use the mtime of the corresponding dep-info file /// as a fingerprint (all source files must be modified *before* this mtime). /// This dep-info file is not generated, however, until after the crate is /// compiled. As a result, this structure can be thought of as a fingerprint /// to-be. The actual value can be calculated via [`hash_u64()`], but the operation /// may fail as some files may not have been generated. /// /// Note that dependencies are taken into account for fingerprints because rustc /// requires that whenever an upstream crate is recompiled that all downstream /// dependents are also recompiled. This is typically tracked through /// [`DependencyQueue`], but it also needs to be retained here because Cargo can /// be interrupted while executing, losing the state of the [`DependencyQueue`] /// graph. /// /// [`hash_u64()`]: crate::core::compiler::fingerprint::Fingerprint::hash_u64 /// [`DependencyQueue`]: crate::util::DependencyQueue #[derive(Serialize, Deserialize)] pub struct Fingerprint { /// Hash of the version of `rustc` used. rustc: u64, /// Sorted list of cfg features enabled. features: String, /// Sorted list of all the declared cfg features. declared_features: String, /// Hash of the `Target` struct, including the target name, /// package-relative source path, edition, etc. target: u64, /// Hash of the [`Profile`], [`CompileMode`], and any extra flags passed via /// `cargo rustc` or `cargo rustdoc`. /// /// [`Profile`]: crate::core::profiles::Profile /// [`CompileMode`]: crate::core::compiler::CompileMode profile: u64, /// Hash of the path to the base source file. This is relative to the /// workspace root for path members, or absolute for other sources. path: u64, /// Fingerprints of dependencies. deps: Vec, /// Information about the inputs that affect this Unit (such as source /// file mtimes or build script environment variables). local: Mutex>, /// Cached hash of the [`Fingerprint`] struct. Used to improve performance /// for hashing. #[serde(skip)] memoized_hash: Mutex>, /// RUSTFLAGS/RUSTDOCFLAGS environment variable value (or config value). rustflags: Vec, /// Hash of various config settings that change how things are compiled. config: u64, /// The rustc target. This is only relevant for `.json` files, otherwise /// the metadata hash segregates the units. compile_kind: u64, /// Description of whether the filesystem status for this unit is up to date /// or should be considered stale. #[serde(skip)] fs_status: FsStatus, /// Files, relative to `target_root`, that are produced by the step that /// this `Fingerprint` represents. This is used to detect when the whole /// fingerprint is out of date if this is missing, or if previous /// fingerprints output files are regenerated and look newer than this one. #[serde(skip)] outputs: Vec, } /// Indication of the status on the filesystem for a particular unit. #[derive(Clone, Default, Debug)] pub enum FsStatus { /// This unit is to be considered stale, even if hash information all /// matches. #[default] Stale, /// File system inputs have changed (or are missing), or there were /// changes to the environment variables that affect this unit. See /// the variants of [`StaleItem`] for more information. StaleItem(StaleItem), /// A dependency was stale. StaleDependency { name: InternedString, dep_mtime: FileTime, max_mtime: FileTime, }, /// A dependency was stale. StaleDepFingerprint { name: InternedString }, /// This unit is up-to-date. All outputs and their corresponding mtime are /// listed in the payload here for other dependencies to compare against. UpToDate { mtimes: HashMap }, } impl FsStatus { fn up_to_date(&self) -> bool { match self { FsStatus::UpToDate { .. } => true, FsStatus::Stale | FsStatus::StaleItem(_) | FsStatus::StaleDependency { .. } | FsStatus::StaleDepFingerprint { .. } => false, } } } impl Serialize for DepFingerprint { fn serialize(&self, ser: S) -> Result where S: ser::Serializer, { ( &self.pkg_id, &self.name, &self.public, &self.fingerprint.hash_u64(), ) .serialize(ser) } } impl<'de> Deserialize<'de> for DepFingerprint { fn deserialize(d: D) -> Result where D: de::Deserializer<'de>, { let (pkg_id, name, public, hash) = <(u64, String, bool, u64)>::deserialize(d)?; Ok(DepFingerprint { pkg_id, name: InternedString::new(&name), public, fingerprint: Arc::new(Fingerprint { memoized_hash: Mutex::new(Some(hash)), ..Fingerprint::new() }), // This field is never read since it's only used in // `check_filesystem` which isn't used by fingerprints loaded from // disk. only_requires_rmeta: false, }) } } /// A `LocalFingerprint` represents something that we use to detect direct /// changes to a `Fingerprint`. /// /// This is where we track file information, env vars, etc. This /// `LocalFingerprint` struct is hashed and if the hash changes will force a /// recompile of any fingerprint it's included into. Note that the "local" /// terminology comes from the fact that it only has to do with one crate, and /// `Fingerprint` tracks the transitive propagation of fingerprint changes. /// /// Note that because this is hashed its contents are carefully managed. Like /// mentioned in the above module docs, we don't want to hash absolute paths or /// mtime information. /// /// Also note that a `LocalFingerprint` is used in `check_filesystem` to detect /// when the filesystem contains stale information (based on mtime currently). /// The paths here don't change much between compilations but they're used as /// inputs when we probe the filesystem looking at information. #[derive(Debug, Serialize, Deserialize, Hash)] enum LocalFingerprint { /// This is a precalculated fingerprint which has an opaque string we just /// hash as usual. This variant is primarily used for rustdoc where we /// don't have a dep-info file to compare against. /// /// This is also used for build scripts with no `rerun-if-*` statements, but /// that's overall a mistake and causes bugs in Cargo. We shouldn't use this /// for build scripts. Precalculated(String), /// This is used for crate compilations. The `dep_info` file is a relative /// path anchored at `target_root(...)` to the dep-info file that Cargo /// generates (which is a custom serialization after parsing rustc's own /// `dep-info` output). /// /// The `dep_info` file, when present, also lists a number of other files /// for us to look at. If any of those files are newer than this file then /// we need to recompile. /// /// If the `checksum` bool is true then the `dep_info` file is expected to /// contain file checksums instead of file mtimes. CheckDepInfo { dep_info: PathBuf, checksum: bool }, /// This represents a nonempty set of `rerun-if-changed` annotations printed /// out by a build script. The `output` file is a relative file anchored at /// `target_root(...)` which is the actual output of the build script. That /// output has already been parsed and the paths printed out via /// `rerun-if-changed` are listed in `paths`. The `paths` field is relative /// to `pkg.root()` /// /// This is considered up-to-date if all of the `paths` are older than /// `output`, otherwise we need to recompile. RerunIfChanged { output: PathBuf, paths: Vec, }, /// This represents a single `rerun-if-env-changed` annotation printed by a /// build script. The exact env var and value are hashed here. There's no /// filesystem dependence here, and if the values are changed the hash will /// change forcing a recompile. RerunIfEnvChanged { var: String, val: Option }, } /// See [`FsStatus::StaleItem`]. #[derive(Clone, Debug)] pub enum StaleItem { MissingFile(PathBuf), UnableToReadFile(PathBuf), FailedToReadMetadata(PathBuf), FileSizeChanged { path: PathBuf, old_size: u64, new_size: u64, }, ChangedFile { reference: PathBuf, reference_mtime: FileTime, stale: PathBuf, stale_mtime: FileTime, }, ChangedChecksum { source: PathBuf, stored_checksum: Checksum, new_checksum: Checksum, }, MissingChecksum(PathBuf), ChangedEnv { var: String, previous: Option, current: Option, }, } impl LocalFingerprint { /// Read the environment variable of the given env `key`, and creates a new /// [`LocalFingerprint::RerunIfEnvChanged`] for it. /// // TODO: This is allowed at this moment. Should figure out if it makes // sense if permitting to read env from the config system. #[allow(clippy::disallowed_methods)] fn from_env>(key: K) -> LocalFingerprint { let key = key.as_ref(); let var = key.to_owned(); let val = env::var(key).ok(); LocalFingerprint::RerunIfEnvChanged { var, val } } /// Checks dynamically at runtime if this `LocalFingerprint` has a stale /// item inside of it. /// /// The main purpose of this function is to handle two different ways /// fingerprints can be invalidated: /// /// * One is a dependency listed in rustc's dep-info files is invalid. Note /// that these could either be env vars or files. We check both here. /// /// * Another is the `rerun-if-changed` directive from build scripts. This /// is where we'll find whether files have actually changed fn find_stale_item( &self, mtime_cache: &mut HashMap, checksum_cache: &mut HashMap, pkg: &Package, target_root: &Path, cargo_exe: &Path, gctx: &GlobalContext, ) -> CargoResult> { let pkg_root = pkg.root(); match self { // We need to parse `dep_info`, learn about the crate's dependencies. // // For each env var we see if our current process's env var still // matches, and for each file we see if any of them are newer than // the `dep_info` file itself whose mtime represents the start of // rustc. LocalFingerprint::CheckDepInfo { dep_info, checksum } => { let dep_info = target_root.join(dep_info); let Some(info) = parse_dep_info(pkg_root, target_root, &dep_info)? else { return Ok(Some(StaleItem::MissingFile(dep_info))); }; for (key, previous) in info.env.iter() { if let Some(value) = pkg.manifest().metadata().env_var(key.as_str()) { if Some(value.as_ref()) == previous.as_deref() { continue; } } let current = if key == CARGO_ENV { Some(cargo_exe.to_str().ok_or_else(|| { format_err!( "cargo exe path {} must be valid UTF-8", cargo_exe.display() ) })?) } else { if let Some(value) = gctx.env_config()?.get(key) { value.to_str() } else { gctx.get_env(key).ok() } }; if current == previous.as_deref() { continue; } return Ok(Some(StaleItem::ChangedEnv { var: key.clone(), previous: previous.clone(), current: current.map(Into::into), })); } if *checksum { Ok(find_stale_file( mtime_cache, checksum_cache, &dep_info, info.files.iter().map(|(file, checksum)| (file, *checksum)), *checksum, )) } else { Ok(find_stale_file( mtime_cache, checksum_cache, &dep_info, info.files.into_keys().map(|p| (p, None)), *checksum, )) } } // We need to verify that no paths listed in `paths` are newer than // the `output` path itself, or the last time the build script ran. LocalFingerprint::RerunIfChanged { output, paths } => Ok(find_stale_file( mtime_cache, checksum_cache, &target_root.join(output), paths.iter().map(|p| (pkg_root.join(p), None)), false, )), // These have no dependencies on the filesystem, and their values // are included natively in the `Fingerprint` hash so nothing // tocheck for here. LocalFingerprint::RerunIfEnvChanged { .. } => Ok(None), LocalFingerprint::Precalculated(..) => Ok(None), } } fn kind(&self) -> &'static str { match self { LocalFingerprint::Precalculated(..) => "precalculated", LocalFingerprint::CheckDepInfo { .. } => "dep-info", LocalFingerprint::RerunIfChanged { .. } => "rerun-if-changed", LocalFingerprint::RerunIfEnvChanged { .. } => "rerun-if-env-changed", } } } impl Fingerprint { fn new() -> Fingerprint { Fingerprint { rustc: 0, target: 0, profile: 0, path: 0, features: String::new(), declared_features: String::new(), deps: Vec::new(), local: Mutex::new(Vec::new()), memoized_hash: Mutex::new(None), rustflags: Vec::new(), config: 0, compile_kind: 0, fs_status: FsStatus::Stale, outputs: Vec::new(), } } /// For performance reasons fingerprints will memoize their own hash, but /// there's also internal mutability with its `local` field which can /// change, for example with build scripts, during a build. /// /// This method can be used to bust all memoized hashes just before a build /// to ensure that after a build completes everything is up-to-date. pub fn clear_memoized(&self) { *self.memoized_hash.lock().unwrap() = None; } fn hash_u64(&self) -> u64 { if let Some(s) = *self.memoized_hash.lock().unwrap() { return s; } let ret = util::hash_u64(self); *self.memoized_hash.lock().unwrap() = Some(ret); ret } /// Compares this fingerprint with an old version which was previously /// serialized to filesystem. /// /// The purpose of this is exclusively to produce a diagnostic message /// [`DirtyReason`], indicating why we're recompiling something. fn compare(&self, old: &Fingerprint) -> DirtyReason { if self.rustc != old.rustc { return DirtyReason::RustcChanged; } if self.features != old.features { return DirtyReason::FeaturesChanged { old: old.features.clone(), new: self.features.clone(), }; } if self.declared_features != old.declared_features { return DirtyReason::DeclaredFeaturesChanged { old: old.declared_features.clone(), new: self.declared_features.clone(), }; } if self.target != old.target { return DirtyReason::TargetConfigurationChanged; } if self.path != old.path { return DirtyReason::PathToSourceChanged; } if self.profile != old.profile { return DirtyReason::ProfileConfigurationChanged; } if self.rustflags != old.rustflags { return DirtyReason::RustflagsChanged { old: old.rustflags.clone(), new: self.rustflags.clone(), }; } if self.config != old.config { return DirtyReason::ConfigSettingsChanged; } if self.compile_kind != old.compile_kind { return DirtyReason::CompileKindChanged; } let my_local = self.local.lock().unwrap(); let old_local = old.local.lock().unwrap(); if my_local.len() != old_local.len() { return DirtyReason::LocalLengthsChanged; } for (new, old) in my_local.iter().zip(old_local.iter()) { match (new, old) { (LocalFingerprint::Precalculated(a), LocalFingerprint::Precalculated(b)) => { if a != b { return DirtyReason::PrecalculatedComponentsChanged { old: b.to_string(), new: a.to_string(), }; } } ( LocalFingerprint::CheckDepInfo { dep_info: adep, checksum: checksum_a, }, LocalFingerprint::CheckDepInfo { dep_info: bdep, checksum: checksum_b, }, ) => { if adep != bdep { return DirtyReason::DepInfoOutputChanged { old: bdep.clone(), new: adep.clone(), }; } if checksum_a != checksum_b { return DirtyReason::ChecksumUseChanged { old: *checksum_b }; } } ( LocalFingerprint::RerunIfChanged { output: aout, paths: apaths, }, LocalFingerprint::RerunIfChanged { output: bout, paths: bpaths, }, ) => { if aout != bout { return DirtyReason::RerunIfChangedOutputFileChanged { old: bout.clone(), new: aout.clone(), }; } if apaths != bpaths { return DirtyReason::RerunIfChangedOutputPathsChanged { old: bpaths.clone(), new: apaths.clone(), }; } } ( LocalFingerprint::RerunIfEnvChanged { var: akey, val: avalue, }, LocalFingerprint::RerunIfEnvChanged { var: bkey, val: bvalue, }, ) => { if *akey != *bkey { return DirtyReason::EnvVarsChanged { old: bkey.clone(), new: akey.clone(), }; } if *avalue != *bvalue { return DirtyReason::EnvVarChanged { name: akey.clone(), old_value: bvalue.clone(), new_value: avalue.clone(), }; } } (a, b) => { return DirtyReason::LocalFingerprintTypeChanged { old: b.kind(), new: a.kind(), } } } } if self.deps.len() != old.deps.len() { return DirtyReason::NumberOfDependenciesChanged { old: old.deps.len(), new: self.deps.len(), }; } for (a, b) in self.deps.iter().zip(old.deps.iter()) { if a.name != b.name { return DirtyReason::UnitDependencyNameChanged { old: b.name, new: a.name, }; } if a.fingerprint.hash_u64() != b.fingerprint.hash_u64() { return DirtyReason::UnitDependencyInfoChanged { new_name: a.name, new_fingerprint: a.fingerprint.hash_u64(), old_name: b.name, old_fingerprint: b.fingerprint.hash_u64(), }; } } if !self.fs_status.up_to_date() { return DirtyReason::FsStatusOutdated(self.fs_status.clone()); } // This typically means some filesystem modifications happened or // something transitive was odd. In general we should strive to provide // a better error message than this, so if you see this message a lot it // likely means this method needs to be updated! DirtyReason::NothingObvious } /// Dynamically inspect the local filesystem to update the `fs_status` field /// of this `Fingerprint`. /// /// This function is used just after a `Fingerprint` is constructed to check /// the local state of the filesystem and propagate any dirtiness from /// dependencies up to this unit as well. This function assumes that the /// unit starts out as [`FsStatus::Stale`] and then it will optionally switch /// it to `UpToDate` if it can. fn check_filesystem( &mut self, mtime_cache: &mut HashMap, checksum_cache: &mut HashMap, pkg: &Package, target_root: &Path, cargo_exe: &Path, gctx: &GlobalContext, ) -> CargoResult<()> { assert!(!self.fs_status.up_to_date()); let pkg_root = pkg.root(); let mut mtimes = HashMap::new(); // Get the `mtime` of all outputs. Optionally update their mtime // afterwards based on the `mtime_on_use` flag. Afterwards we want the // minimum mtime as it's the one we'll be comparing to inputs and // dependencies. for output in self.outputs.iter() { let mtime = match paths::mtime(output) { Ok(mtime) => mtime, // This path failed to report its `mtime`. It probably doesn't // exists, so leave ourselves as stale and bail out. Err(e) => { debug!("failed to get mtime of {:?}: {}", output, e); return Ok(()); } }; assert!(mtimes.insert(output.clone(), mtime).is_none()); } let opt_max = mtimes.iter().max_by_key(|kv| kv.1); let Some((max_path, max_mtime)) = opt_max else { // We had no output files. This means we're an overridden build // script and we're just always up to date because we aren't // watching the filesystem. self.fs_status = FsStatus::UpToDate { mtimes }; return Ok(()); }; debug!( "max output mtime for {:?} is {:?} {}", pkg_root, max_path, max_mtime ); for dep in self.deps.iter() { let dep_mtimes = match &dep.fingerprint.fs_status { FsStatus::UpToDate { mtimes } => mtimes, // If our dependency is stale, so are we, so bail out. FsStatus::Stale | FsStatus::StaleItem(_) | FsStatus::StaleDependency { .. } | FsStatus::StaleDepFingerprint { .. } => { self.fs_status = FsStatus::StaleDepFingerprint { name: dep.name }; return Ok(()); } }; // If our dependency edge only requires the rmeta file to be present // then we only need to look at that one output file, otherwise we // need to consider all output files to see if we're out of date. let (dep_path, dep_mtime) = if dep.only_requires_rmeta { dep_mtimes .iter() .find(|(path, _mtime)| { path.extension().and_then(|s| s.to_str()) == Some("rmeta") }) .expect("failed to find rmeta") } else { match dep_mtimes.iter().max_by_key(|kv| kv.1) { Some(dep_mtime) => dep_mtime, // If our dependencies is up to date and has no filesystem // interactions, then we can move on to the next dependency. None => continue, } }; debug!( "max dep mtime for {:?} is {:?} {}", pkg_root, dep_path, dep_mtime ); // If the dependency is newer than our own output then it was // recompiled previously. We transitively become stale ourselves in // that case, so bail out. // // Note that this comparison should probably be `>=`, not `>`, but // for a discussion of why it's `>` see the discussion about #5918 // below in `find_stale`. if dep_mtime > max_mtime { info!( "dependency on `{}` is newer than we are {} > {} {:?}", dep.name, dep_mtime, max_mtime, pkg_root ); self.fs_status = FsStatus::StaleDependency { name: dep.name, dep_mtime: *dep_mtime, max_mtime: *max_mtime, }; return Ok(()); } } // If we reached this far then all dependencies are up to date. Check // all our `LocalFingerprint` information to see if we have any stale // files for this package itself. If we do find something log a helpful // message and bail out so we stay stale. for local in self.local.get_mut().unwrap().iter() { if let Some(item) = local.find_stale_item( mtime_cache, checksum_cache, pkg, target_root, cargo_exe, gctx, )? { item.log(); self.fs_status = FsStatus::StaleItem(item); return Ok(()); } } // Everything was up to date! Record such. self.fs_status = FsStatus::UpToDate { mtimes }; debug!("filesystem up-to-date {:?}", pkg_root); Ok(()) } } impl hash::Hash for Fingerprint { fn hash(&self, h: &mut H) { let Fingerprint { rustc, ref features, ref declared_features, target, path, profile, ref deps, ref local, config, compile_kind, ref rustflags, .. } = *self; let local = local.lock().unwrap(); ( rustc, features, declared_features, target, path, profile, &*local, config, compile_kind, rustflags, ) .hash(h); h.write_usize(deps.len()); for DepFingerprint { pkg_id, name, public, fingerprint, only_requires_rmeta: _, // static property, no need to hash } in deps { pkg_id.hash(h); name.hash(h); public.hash(h); // use memoized dep hashes to avoid exponential blowup h.write_u64(fingerprint.hash_u64()); } } } impl DepFingerprint { fn new( build_runner: &mut BuildRunner<'_, '_>, parent: &Unit, dep: &UnitDep, ) -> CargoResult { let fingerprint = calculate(build_runner, &dep.unit)?; // We need to be careful about what we hash here. We have a goal of // supporting renaming a project directory and not rebuilding // everything. To do that, however, we need to make sure that the cwd // doesn't make its way into any hashes, and one source of that is the // `SourceId` for `path` packages. // // We already have a requirement that `path` packages all have unique // names (sort of for this same reason), so if the package source is a // `path` then we just hash the name, but otherwise we hash the full // id as it won't change when the directory is renamed. let pkg_id = if dep.unit.pkg.package_id().source_id().is_path() { util::hash_u64(dep.unit.pkg.package_id().name()) } else { util::hash_u64(dep.unit.pkg.package_id()) }; Ok(DepFingerprint { pkg_id, name: dep.extern_crate_name, public: dep.public, fingerprint, only_requires_rmeta: build_runner.only_requires_rmeta(parent, &dep.unit), }) } } impl StaleItem { /// Use the `log` crate to log a hopefully helpful message in diagnosing /// what file is considered stale and why. This is intended to be used in /// conjunction with `CARGO_LOG` to determine why Cargo is recompiling /// something. Currently there's no user-facing usage of this other than /// that. fn log(&self) { match self { StaleItem::MissingFile(path) => { info!("stale: missing {:?}", path); } StaleItem::UnableToReadFile(path) => { info!("stale: unable to read {:?}", path); } StaleItem::FailedToReadMetadata(path) => { info!("stale: couldn't read metadata {:?}", path); } StaleItem::ChangedFile { reference, reference_mtime, stale, stale_mtime, } => { info!("stale: changed {:?}", stale); info!(" (vs) {:?}", reference); info!(" {:?} < {:?}", reference_mtime, stale_mtime); } StaleItem::FileSizeChanged { path, new_size, old_size, } => { info!("stale: changed {:?}", path); info!("prior file size {old_size}"); info!(" new file size {new_size}"); } StaleItem::ChangedChecksum { source, stored_checksum, new_checksum, } => { info!("stale: changed {:?}", source); info!("prior checksum {stored_checksum}"); info!(" new checksum {new_checksum}"); } StaleItem::MissingChecksum(path) => { info!("stale: no prior checksum {:?}", path); } StaleItem::ChangedEnv { var, previous, current, } => { info!("stale: changed env {:?}", var); info!(" {:?} != {:?}", previous, current); } } } } /// Calculates the fingerprint for a [`Unit`]. /// /// This fingerprint is used by Cargo to learn about when information such as: /// /// * A non-path package changes (changes version, changes revision, etc). /// * Any dependency changes /// * The compiler changes /// * The set of features a package is built with changes /// * The profile a target is compiled with changes (e.g., opt-level changes) /// * Any other compiler flags change that will affect the result /// /// Information like file modification time is only calculated for path /// dependencies. fn calculate(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult> { // This function is slammed quite a lot, so the result is memoized. if let Some(s) = build_runner.fingerprints.get(unit) { return Ok(Arc::clone(s)); } let mut fingerprint = if unit.mode.is_run_custom_build() { calculate_run_custom_build(build_runner, unit)? } else if unit.mode.is_doc_test() { panic!("doc tests do not fingerprint"); } else { calculate_normal(build_runner, unit)? }; // After we built the initial `Fingerprint` be sure to update the // `fs_status` field of it. let target_root = target_root(build_runner); let cargo_exe = build_runner.bcx.gctx.cargo_exe()?; fingerprint.check_filesystem( &mut build_runner.mtime_cache, &mut build_runner.checksum_cache, &unit.pkg, &target_root, cargo_exe, build_runner.bcx.gctx, )?; let fingerprint = Arc::new(fingerprint); build_runner .fingerprints .insert(unit.clone(), Arc::clone(&fingerprint)); Ok(fingerprint) } /// Calculate a fingerprint for a "normal" unit, or anything that's not a build /// script. This is an internal helper of [`calculate`], don't call directly. fn calculate_normal( build_runner: &mut BuildRunner<'_, '_>, unit: &Unit, ) -> CargoResult { let deps = { // Recursively calculate the fingerprint for all of our dependencies. // // Skip fingerprints of binaries because they don't actually induce a // recompile, they're just dependencies in the sense that they need to be // built. The only exception here are artifact dependencies, // which is an actual dependency that needs a recompile. // // Create Vec since mutable build_runner is needed in closure. let deps = Vec::from(build_runner.unit_deps(unit)); let mut deps = deps .into_iter() .filter(|dep| !dep.unit.target.is_bin() || dep.unit.artifact.is_true()) .map(|dep| DepFingerprint::new(build_runner, unit, &dep)) .collect::>>()?; deps.sort_by(|a, b| a.pkg_id.cmp(&b.pkg_id)); deps }; // Afterwards calculate our own fingerprint information. let target_root = target_root(build_runner); let local = if unit.mode.is_doc() || unit.mode.is_doc_scrape() { // rustdoc does not have dep-info files. let fingerprint = pkg_fingerprint(build_runner.bcx, &unit.pkg).with_context(|| { format!( "failed to determine package fingerprint for documenting {}", unit.pkg ) })?; vec![LocalFingerprint::Precalculated(fingerprint)] } else { let dep_info = dep_info_loc(build_runner, unit); let dep_info = dep_info.strip_prefix(&target_root).unwrap().to_path_buf(); vec![LocalFingerprint::CheckDepInfo { dep_info, checksum: build_runner.bcx.gctx.cli_unstable().checksum_freshness, }] }; // Figure out what the outputs of our unit is, and we'll be storing them // into the fingerprint as well. let outputs = build_runner .outputs(unit)? .iter() .filter(|output| !matches!(output.flavor, FileFlavor::DebugInfo | FileFlavor::Auxiliary)) .map(|output| output.path.clone()) .collect(); // Fill out a bunch more information that we'll be tracking typically // hashed to take up less space on disk as we just need to know when things // change. let extra_flags = if unit.mode.is_doc() || unit.mode.is_doc_scrape() { &unit.rustdocflags } else { &unit.rustflags } .to_vec(); let profile_hash = util::hash_u64(( &unit.profile, unit.mode, build_runner.bcx.extra_args_for(unit), build_runner.lto[unit], unit.pkg.manifest().lint_rustflags(), )); let mut config = StableHasher::new(); if let Some(linker) = build_runner.compilation.target_linker(unit.kind) { linker.hash(&mut config); } if unit.mode.is_doc() && build_runner.bcx.gctx.cli_unstable().rustdoc_map { if let Ok(map) = build_runner.bcx.gctx.doc_extern_map() { map.hash(&mut config); } } if let Some(allow_features) = &build_runner.bcx.gctx.cli_unstable().allow_features { allow_features.hash(&mut config); } let compile_kind = unit.kind.fingerprint_hash(); let mut declared_features = unit.pkg.summary().features().keys().collect::>(); declared_features.sort(); // to avoid useless rebuild if the user orders it's features // differently Ok(Fingerprint { rustc: util::hash_u64(&build_runner.bcx.rustc().verbose_version), target: util::hash_u64(&unit.target), profile: profile_hash, // Note that .0 is hashed here, not .1 which is the cwd. That doesn't // actually affect the output artifact so there's no need to hash it. path: util::hash_u64(path_args(build_runner.bcx.ws, unit).0), features: format!("{:?}", unit.features), declared_features: format!("{declared_features:?}"), deps, local: Mutex::new(local), memoized_hash: Mutex::new(None), config: Hasher::finish(&config), compile_kind, rustflags: extra_flags, fs_status: FsStatus::Stale, outputs, }) } /// Calculate a fingerprint for an "execute a build script" unit. This is an /// internal helper of [`calculate`], don't call directly. fn calculate_run_custom_build( build_runner: &mut BuildRunner<'_, '_>, unit: &Unit, ) -> CargoResult { assert!(unit.mode.is_run_custom_build()); // Using the `BuildDeps` information we'll have previously parsed and // inserted into `build_explicit_deps` built an initial snapshot of the // `LocalFingerprint` list for this build script. If we previously executed // the build script this means we'll be watching files and env vars. // Otherwise if we haven't previously executed it we'll just start watching // the whole crate. let (gen_local, overridden) = build_script_local_fingerprints(build_runner, unit); let deps = &build_runner.build_explicit_deps[unit]; let local = (gen_local)( deps, Some(&|| { const IO_ERR_MESSAGE: &str = "\ An I/O error happened. Please make sure you can access the file. By default, if your project contains a build script, cargo scans all files in it to determine whether a rebuild is needed. If you don't expect to access the file, specify `rerun-if-changed` in your build script. See https://doc.rust-lang.org/cargo/reference/build-scripts.html#rerun-if-changed for more information."; pkg_fingerprint(build_runner.bcx, &unit.pkg).map_err(|err| { let mut message = format!("failed to determine package fingerprint for build script for {}", unit.pkg); if err.root_cause().is::() { message = format!("{}\n{}", message, IO_ERR_MESSAGE) } err.context(message) }) }), )? .unwrap(); let output = deps.build_script_output.clone(); // Include any dependencies of our execution, which is typically just the // compilation of the build script itself. (if the build script changes we // should be rerun!). Note though that if we're an overridden build script // we have no dependencies so no need to recurse in that case. let deps = if overridden { // Overridden build scripts don't need to track deps. vec![] } else { // Create Vec since mutable build_runner is needed in closure. let deps = Vec::from(build_runner.unit_deps(unit)); deps.into_iter() .map(|dep| DepFingerprint::new(build_runner, unit, &dep)) .collect::>>()? }; let rustflags = unit.rustflags.to_vec(); Ok(Fingerprint { local: Mutex::new(local), rustc: util::hash_u64(&build_runner.bcx.rustc().verbose_version), deps, outputs: if overridden { Vec::new() } else { vec![output] }, rustflags, // Most of the other info is blank here as we don't really include it // in the execution of the build script, but... this may be a latent // bug in Cargo. ..Fingerprint::new() }) } /// Get ready to compute the [`LocalFingerprint`] values /// for a [`RunCustomBuild`] unit. /// /// This function has, what's on the surface, a seriously wonky interface. /// You'll call this function and it'll return a closure and a boolean. The /// boolean is pretty simple in that it indicates whether the `unit` has been /// overridden via `.cargo/config.toml`. The closure is much more complicated. /// /// This closure is intended to capture any local state necessary to compute /// the `LocalFingerprint` values for this unit. It is `Send` and `'static` to /// be sent to other threads as well (such as when we're executing build /// scripts). That deduplication is the rationale for the closure at least. /// /// The arguments to the closure are a bit weirder, though, and I'll apologize /// in advance for the weirdness too. The first argument to the closure is a /// `&BuildDeps`. This is the parsed version of a build script, and when Cargo /// starts up this is cached from previous runs of a build script. After a /// build script executes the output file is reparsed and passed in here. /// /// The second argument is the weirdest, it's *optionally* a closure to /// call [`pkg_fingerprint`]. The `pkg_fingerprint` requires access to /// "source map" located in `Context`. That's very non-`'static` and /// non-`Send`, so it can't be used on other threads, such as when we invoke /// this after a build script has finished. The `Option` allows us to for sure /// calculate it on the main thread at the beginning, and then swallow the bug /// for now where a worker thread after a build script has finished doesn't /// have access. Ideally there would be no second argument or it would be more /// "first class" and not an `Option` but something that can be sent between /// threads. In any case, it's a bug for now. /// /// This isn't the greatest of interfaces, and if there's suggestions to /// improve please do so! /// /// FIXME(#6779) - see all the words above /// /// [`RunCustomBuild`]: crate::core::compiler::CompileMode::RunCustomBuild fn build_script_local_fingerprints( build_runner: &mut BuildRunner<'_, '_>, unit: &Unit, ) -> ( Box< dyn FnOnce( &BuildDeps, Option<&dyn Fn() -> CargoResult>, ) -> CargoResult>> + Send, >, bool, ) { assert!(unit.mode.is_run_custom_build()); // First up, if this build script is entirely overridden, then we just // return the hash of what we overrode it with. This is the easy case! if let Some(fingerprint) = build_script_override_fingerprint(build_runner, unit) { debug!("override local fingerprints deps {}", unit.pkg); return ( Box::new( move |_: &BuildDeps, _: Option<&dyn Fn() -> CargoResult>| { Ok(Some(vec![fingerprint])) }, ), true, // this is an overridden build script ); } // ... Otherwise this is a "real" build script and we need to return a real // closure. Our returned closure classifies the build script based on // whether it prints `rerun-if-*`. If it *doesn't* print this it's where the // magical second argument comes into play, which fingerprints a whole // package. Remember that the fact that this is an `Option` is a bug, but a // longstanding bug, in Cargo. Recent refactorings just made it painfully // obvious. let pkg_root = unit.pkg.root().to_path_buf(); let target_dir = target_root(build_runner); let calculate = move |deps: &BuildDeps, pkg_fingerprint: Option<&dyn Fn() -> CargoResult>| { if deps.rerun_if_changed.is_empty() && deps.rerun_if_env_changed.is_empty() { match pkg_fingerprint { // FIXME: this is somewhat buggy with respect to docker and // weird filesystems. The `Precalculated` variant // constructed below will, for `path` dependencies, contain // a stringified version of the mtime for the local crate. // This violates one of the things we describe in this // module's doc comment, never hashing mtimes. We should // figure out a better scheme where a package fingerprint // may be a string (like for a registry) or a list of files // (like for a path dependency). Those list of files would // be stored here rather than the mtime of them. Some(f) => { let s = f()?; debug!( "old local fingerprints deps {:?} precalculated={:?}", pkg_root, s ); return Ok(Some(vec![LocalFingerprint::Precalculated(s)])); } None => return Ok(None), } } // Ok so now we're in "new mode" where we can have files listed as // dependencies as well as env vars listed as dependencies. Process // them all here. Ok(Some(local_fingerprints_deps(deps, &target_dir, &pkg_root))) }; // Note that `false` == "not overridden" (Box::new(calculate), false) } /// Create a [`LocalFingerprint`] for an overridden build script. /// Returns None if it is not overridden. fn build_script_override_fingerprint( build_runner: &mut BuildRunner<'_, '_>, unit: &Unit, ) -> Option { // Build script output is only populated at this stage when it is // overridden. let build_script_outputs = build_runner.build_script_outputs.lock().unwrap(); let metadata = build_runner.get_run_build_script_metadata(unit); // Returns None if it is not overridden. let output = build_script_outputs.get(metadata)?; let s = format!( "overridden build state with hash: {}", util::hash_u64(output) ); Some(LocalFingerprint::Precalculated(s)) } /// Compute the [`LocalFingerprint`] values for a [`RunCustomBuild`] unit for /// non-overridden new-style build scripts only. This is only used when `deps` /// is already known to have a nonempty `rerun-if-*` somewhere. /// /// [`RunCustomBuild`]: crate::core::compiler::CompileMode::RunCustomBuild fn local_fingerprints_deps( deps: &BuildDeps, target_root: &Path, pkg_root: &Path, ) -> Vec { debug!("new local fingerprints deps {:?}", pkg_root); let mut local = Vec::new(); if !deps.rerun_if_changed.is_empty() { // Note that like the module comment above says we are careful to never // store an absolute path in `LocalFingerprint`, so ensure that we strip // absolute prefixes from them. let output = deps .build_script_output .strip_prefix(target_root) .unwrap() .to_path_buf(); let paths = deps .rerun_if_changed .iter() .map(|p| p.strip_prefix(pkg_root).unwrap_or(p).to_path_buf()) .collect(); local.push(LocalFingerprint::RerunIfChanged { output, paths }); } local.extend( deps.rerun_if_env_changed .iter() .map(LocalFingerprint::from_env), ); local } /// Writes the short fingerprint hash value to `` /// and logs detailed JSON information to `.json`. fn write_fingerprint(loc: &Path, fingerprint: &Fingerprint) -> CargoResult<()> { debug_assert_ne!(fingerprint.rustc, 0); // fingerprint::new().rustc == 0, make sure it doesn't make it to the file system. // This is mostly so outside tools can reliably find out what rust version this file is for, // as we can use the full hash. let hash = fingerprint.hash_u64(); debug!("write fingerprint ({:x}) : {}", hash, loc.display()); paths::write(loc, util::to_hex(hash).as_bytes())?; let json = serde_json::to_string(fingerprint).unwrap(); if cfg!(debug_assertions) { let f: Fingerprint = serde_json::from_str(&json).unwrap(); assert_eq!(f.hash_u64(), hash); } paths::write(&loc.with_extension("json"), json.as_bytes())?; Ok(()) } /// Prepare for work when a package starts to build pub fn prepare_init(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<()> { let new1 = build_runner.files().fingerprint_dir(unit); // Doc tests have no output, thus no fingerprint. if !new1.exists() && !unit.mode.is_doc_test() { paths::create_dir_all(&new1)?; } Ok(()) } /// Returns the location that the dep-info file will show up at /// for the [`Unit`] specified. pub fn dep_info_loc(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> PathBuf { build_runner.files().fingerprint_file_path(unit, "dep-") } /// Returns an absolute path that target directory. /// All paths are rewritten to be relative to this. fn target_root(build_runner: &BuildRunner<'_, '_>) -> PathBuf { build_runner.bcx.ws.target_dir().into_path_unlocked() } /// Reads the value from the old fingerprint hash file and compare. /// /// If dirty, it then restores the detailed information /// from the fingerprint JSON file, and provides an rich dirty reason. fn compare_old_fingerprint( unit: &Unit, old_hash_path: &Path, new_fingerprint: &Fingerprint, mtime_on_use: bool, forced: bool, ) -> Option { if mtime_on_use { // update the mtime so other cleaners know we used it let t = FileTime::from_system_time(SystemTime::now()); debug!("mtime-on-use forcing {:?} to {}", old_hash_path, t); paths::set_file_time_no_err(old_hash_path, t); } let compare = _compare_old_fingerprint(old_hash_path, new_fingerprint); match compare.as_ref() { Ok(None) => {} Ok(Some(reason)) => { info!( "fingerprint dirty for {}/{:?}/{:?}", unit.pkg, unit.mode, unit.target, ); info!(" dirty: {reason:?}"); } Err(e) => { info!( "fingerprint error for {}/{:?}/{:?}", unit.pkg, unit.mode, unit.target, ); info!(" err: {e:?}"); } } match compare { Ok(None) if forced => Some(DirtyReason::Forced), Ok(reason) => reason, Err(_) => Some(DirtyReason::FreshBuild), } } fn _compare_old_fingerprint( old_hash_path: &Path, new_fingerprint: &Fingerprint, ) -> CargoResult> { let old_fingerprint_short = paths::read(old_hash_path)?; let new_hash = new_fingerprint.hash_u64(); if util::to_hex(new_hash) == old_fingerprint_short && new_fingerprint.fs_status.up_to_date() { return Ok(None); } let old_fingerprint_json = paths::read(&old_hash_path.with_extension("json"))?; let old_fingerprint: Fingerprint = serde_json::from_str(&old_fingerprint_json) .with_context(|| internal("failed to deserialize json"))?; // Fingerprint can be empty after a failed rebuild (see comment in prepare_target). if !old_fingerprint_short.is_empty() { debug_assert_eq!( util::to_hex(old_fingerprint.hash_u64()), old_fingerprint_short ); } Ok(Some(new_fingerprint.compare(&old_fingerprint))) } /// Calculates the fingerprint of a unit thats contains no dep-info files. fn pkg_fingerprint(bcx: &BuildContext<'_, '_>, pkg: &Package) -> CargoResult { let source_id = pkg.package_id().source_id(); let sources = bcx.packages.sources(); let source = sources .get(source_id) .ok_or_else(|| internal("missing package source"))?; source.fingerprint(pkg) } /// The `reference` file is considered as "stale" if any file from `paths` has a newer mtime. fn find_stale_file( mtime_cache: &mut HashMap, checksum_cache: &mut HashMap, reference: &Path, paths: I, use_checksums: bool, ) -> Option where I: IntoIterator)>, P: AsRef, { let Ok(reference_mtime) = paths::mtime(reference) else { return Some(StaleItem::MissingFile(reference.to_path_buf())); }; let skipable_dirs = if let Ok(cargo_home) = home::cargo_home() { let skipable_dirs: Vec<_> = ["git", "registry"] .into_iter() .map(|subfolder| cargo_home.join(subfolder)) .collect(); Some(skipable_dirs) } else { None }; for (path, prior_checksum) in paths { let path = path.as_ref(); // Assuming anything in cargo_home/{git, registry} is immutable // (see also #9455 about marking the src directory readonly) which avoids rebuilds when CI // caches $CARGO_HOME/registry/{index, cache} and $CARGO_HOME/git/db across runs, keeping // the content the same but changing the mtime. if let Some(ref skipable_dirs) = skipable_dirs { if skipable_dirs.iter().any(|dir| path.starts_with(dir)) { continue; } } if use_checksums { let Some((file_len, prior_checksum)) = prior_checksum else { return Some(StaleItem::MissingChecksum(path.to_path_buf())); }; let path_buf = path.to_path_buf(); let path_checksum = match checksum_cache.entry(path_buf) { Entry::Occupied(o) => *o.get(), Entry::Vacant(v) => { let Ok(current_file_len) = fs::metadata(&path).map(|m| m.len()) else { return Some(StaleItem::FailedToReadMetadata(path.to_path_buf())); }; if current_file_len != file_len { return Some(StaleItem::FileSizeChanged { path: path.to_path_buf(), new_size: current_file_len, old_size: file_len, }); } let Ok(file) = File::open(path) else { return Some(StaleItem::MissingFile(path.to_path_buf())); }; let Ok(checksum) = Checksum::compute(prior_checksum.algo(), file) else { return Some(StaleItem::UnableToReadFile(path.to_path_buf())); }; *v.insert(checksum) } }; if path_checksum == prior_checksum { continue; } return Some(StaleItem::ChangedChecksum { source: path.to_path_buf(), stored_checksum: prior_checksum, new_checksum: path_checksum, }); } else { let path_mtime = match mtime_cache.entry(path.to_path_buf()) { Entry::Occupied(o) => *o.get(), Entry::Vacant(v) => { let Ok(mtime) = paths::mtime_recursive(path) else { return Some(StaleItem::MissingFile(path.to_path_buf())); }; *v.insert(mtime) } }; // TODO: fix #5918. // Note that equal mtimes should be considered "stale". For filesystems with // not much timestamp precision like 1s this is would be a conservative approximation // to handle the case where a file is modified within the same second after // a build starts. We want to make sure that incremental rebuilds pick that up! // // For filesystems with nanosecond precision it's been seen in the wild that // its "nanosecond precision" isn't really nanosecond-accurate. It turns out that // kernels may cache the current time so files created at different times actually // list the same nanosecond precision. Some digging on #5919 picked up that the // kernel caches the current time between timer ticks, which could mean that if // a file is updated at most 10ms after a build starts then Cargo may not // pick up the build changes. // // All in all, an equality check here would be a conservative assumption that, // if equal, files were changed just after a previous build finished. // Unfortunately this became problematic when (in #6484) cargo switch to more accurately // measuring the start time of builds. if path_mtime <= reference_mtime { continue; } return Some(StaleItem::ChangedFile { reference: reference.to_path_buf(), reference_mtime, stale: path.to_path_buf(), stale_mtime: path_mtime, }); } } debug!( "all paths up-to-date relative to {:?} mtime={}", reference, reference_mtime ); None } cargo-0.86.0/src/cargo/core/compiler/future_incompat.rs000064400000000000000000000422271046102023000212170ustar 00000000000000//! Support for [future-incompatible warning reporting][1]. //! //! Here is an overview of how Cargo handles future-incompatible reports. //! //! ## Receive reports from the compiler //! //! When receiving a compiler message during a build, if it is effectively //! a [`FutureIncompatReport`], Cargo gathers and forwards it as a //! `Message::FutureIncompatReport` to the main thread. //! //! To have the correct layout of strucutures for deserializing a report //! emitted by the compiler, most of structure definitions, for example //! [`FutureIncompatReport`], are copied either partially or entirely from //! [compiler/rustc_errors/src/json.rs][2] in rust-lang/rust repository. //! //! ## Persist reports on disk //! //! When a build comes to an end, by calling [`save_and_display_report`] //! Cargo saves the report on disk, and displays it directly if requested //! via command line or configuration. The information of the on-disk file can //! be found in [`FUTURE_INCOMPAT_FILE`]. //! //! During the persistent process, Cargo will attempt to query the source of //! each package emitting the report, for the sake of providing an upgrade //! information as a solution to fix the incompatibility. //! //! ## Display reports to users //! //! Users can run `cargo report future-incompat` to retrieve a report. This is //! done by [`OnDiskReports::load`]. Cargo simply prints reports to the //! standard output. //! //! [1]: https://doc.rust-lang.org/nightly/cargo/reference/future-incompat-report.html //! [2]: https://github.com/rust-lang/rust/blob/9bb6e60d1f1360234aae90c97964c0fa5524f141/compiler/rustc_errors/src/json.rs#L312-L315 use crate::core::compiler::BuildContext; use crate::core::{Dependency, PackageId, Workspace}; use crate::sources::source::QueryKind; use crate::sources::SourceConfigMap; use crate::util::cache_lock::CacheLockMode; use crate::util::CargoResult; use anyhow::{bail, format_err, Context}; use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::fmt::Write as _; use std::io::{Read, Write}; use std::task::Poll; pub const REPORT_PREAMBLE: &str = "\ The following warnings were discovered during the build. These warnings are an indication that the packages contain code that will become an error in a future release of Rust. These warnings typically cover changes to close soundness problems, unintended or undocumented behavior, or critical problems that cannot be fixed in a backwards-compatible fashion, and are not expected to be in wide use. Each warning should contain a link for more information on what the warning means and how to resolve it. "; /// Current version of the on-disk format. const ON_DISK_VERSION: u32 = 0; /// The future incompatibility report, emitted by the compiler as a JSON message. #[derive(serde::Deserialize)] pub struct FutureIncompatReport { pub future_incompat_report: Vec, } /// Structure used for collecting reports in-memory. pub struct FutureIncompatReportPackage { pub package_id: PackageId, pub items: Vec, } /// A single future-incompatible warning emitted by rustc. #[derive(Serialize, Deserialize)] pub struct FutureBreakageItem { /// The date at which this lint will become an error. /// Currently unused pub future_breakage_date: Option, /// The original diagnostic emitted by the compiler pub diagnostic: Diagnostic, } /// A diagnostic emitted by the compiler as a JSON message. /// We only care about the 'rendered' field #[derive(Serialize, Deserialize)] pub struct Diagnostic { pub rendered: String, pub level: String, } /// The filename in the top-level `target` directory where we store /// the report const FUTURE_INCOMPAT_FILE: &str = ".future-incompat-report.json"; /// Max number of reports to save on disk. const MAX_REPORTS: usize = 5; /// The structure saved to disk containing the reports. #[derive(Serialize, Deserialize)] pub struct OnDiskReports { /// A schema version number, to handle older cargo's from trying to read /// something that they don't understand. version: u32, /// The report ID to use for the next report to save. next_id: u32, /// Available reports. reports: Vec, } /// A single report for a given compilation session. #[derive(Serialize, Deserialize)] struct OnDiskReport { /// Unique reference to the report for the `--id` CLI flag. id: u32, /// A message describing suggestions for fixing the /// reported issues suggestion_message: String, /// Report, suitable for printing to the console. /// Maps package names to the corresponding report /// We use a `BTreeMap` so that the iteration order /// is stable across multiple runs of `cargo` per_package: BTreeMap, } impl Default for OnDiskReports { fn default() -> OnDiskReports { OnDiskReports { version: ON_DISK_VERSION, next_id: 1, reports: Vec::new(), } } } impl OnDiskReports { /// Saves a new report returning its id pub fn save_report( mut self, ws: &Workspace<'_>, suggestion_message: String, per_package_reports: &[FutureIncompatReportPackage], ) -> u32 { let per_package = render_report(per_package_reports); if let Some(existing_report) = self .reports .iter() .find(|existing| existing.per_package == per_package) { return existing_report.id; } let report = OnDiskReport { id: self.next_id, suggestion_message, per_package, }; let saved_id = report.id; self.next_id += 1; self.reports.push(report); if self.reports.len() > MAX_REPORTS { self.reports.remove(0); } let on_disk = serde_json::to_vec(&self).unwrap(); if let Err(e) = ws .target_dir() .open_rw_exclusive_create( FUTURE_INCOMPAT_FILE, ws.gctx(), "Future incompatibility report", ) .and_then(|file| { let mut file = file.file(); file.set_len(0)?; file.write_all(&on_disk)?; Ok(()) }) { crate::display_warning_with_error( "failed to write on-disk future incompatible report", &e, &mut ws.gctx().shell(), ); } saved_id } /// Loads the on-disk reports. pub fn load(ws: &Workspace<'_>) -> CargoResult { let report_file = match ws.target_dir().open_ro_shared( FUTURE_INCOMPAT_FILE, ws.gctx(), "Future incompatible report", ) { Ok(r) => r, Err(e) => { if let Some(io_err) = e.downcast_ref::() { if io_err.kind() == std::io::ErrorKind::NotFound { bail!("no reports are currently available"); } } return Err(e); } }; let mut file_contents = String::new(); report_file .file() .read_to_string(&mut file_contents) .context("failed to read report")?; let on_disk_reports: OnDiskReports = serde_json::from_str(&file_contents).context("failed to load report")?; if on_disk_reports.version != ON_DISK_VERSION { bail!("unable to read reports; reports were saved from a future version of Cargo"); } Ok(on_disk_reports) } /// Returns the most recent report ID. pub fn last_id(&self) -> u32 { self.reports.last().map(|r| r.id).unwrap() } /// Returns an ANSI-styled report pub fn get_report(&self, id: u32, package: Option<&str>) -> CargoResult { let report = self.reports.iter().find(|r| r.id == id).ok_or_else(|| { let available = itertools::join(self.reports.iter().map(|r| r.id), ", "); format_err!( "could not find report with ID {}\n\ Available IDs are: {}", id, available ) })?; let mut to_display = report.suggestion_message.clone(); to_display += "\n"; let package_report = if let Some(package) = package { report .per_package .get(package) .ok_or_else(|| { format_err!( "could not find package with ID `{}`\n Available packages are: {}\n Omit the `--package` flag to display a report for all packages", package, itertools::join(report.per_package.keys(), ", ") ) })? .to_string() } else { report .per_package .values() .cloned() .collect::>() .join("\n") }; to_display += &package_report; Ok(to_display) } } fn render_report(per_package_reports: &[FutureIncompatReportPackage]) -> BTreeMap { let mut report: BTreeMap = BTreeMap::new(); for per_package in per_package_reports { let package_spec = format!( "{}@{}", per_package.package_id.name(), per_package.package_id.version() ); let rendered = report.entry(package_spec).or_default(); rendered.push_str(&format!( "The package `{}` currently triggers the following future incompatibility lints:\n", per_package.package_id )); for item in &per_package.items { rendered.extend( item.diagnostic .rendered .lines() .map(|l| format!("> {}\n", l)), ); } } report } /// Returns a user-readable message explaining which of /// the packages in `package_ids` have updates available. /// This is best-effort - if an error occurs, `None` will be returned. fn get_updates(ws: &Workspace<'_>, package_ids: &BTreeSet) -> Option { // This in general ignores all errors since this is opportunistic. let _lock = ws .gctx() .acquire_package_cache_lock(CacheLockMode::DownloadExclusive) .ok()?; // Create a set of updated registry sources. let map = SourceConfigMap::new(ws.gctx()).ok()?; let mut package_ids: BTreeSet<_> = package_ids .iter() .filter(|pkg_id| pkg_id.source_id().is_registry()) .collect(); let source_ids: HashSet<_> = package_ids .iter() .map(|pkg_id| pkg_id.source_id()) .collect(); let mut sources: HashMap<_, _> = source_ids .into_iter() .filter_map(|sid| { let source = map.load(sid, &HashSet::new()).ok()?; Some((sid, source)) }) .collect(); // Query the sources for new versions, mapping `package_ids` into `summaries`. let mut summaries = Vec::new(); while !package_ids.is_empty() { package_ids.retain(|&pkg_id| { let Some(source) = sources.get_mut(&pkg_id.source_id()) else { return false; }; let Ok(dep) = Dependency::parse(pkg_id.name(), None, pkg_id.source_id()) else { return false; }; match source.query_vec(&dep, QueryKind::Exact) { Poll::Ready(Ok(sum)) => { summaries.push((pkg_id, sum)); false } Poll::Ready(Err(_)) => false, Poll::Pending => true, } }); for (_, source) in sources.iter_mut() { source.block_until_ready().ok()?; } } let mut updates = String::new(); for (pkg_id, summaries) in summaries { let mut updated_versions: Vec<_> = summaries .iter() .map(|summary| summary.as_summary().version()) .filter(|version| *version > pkg_id.version()) .collect(); updated_versions.sort(); if !updated_versions.is_empty() { let updated_versions = itertools::join(updated_versions, ", "); writeln!( updates, "{} has the following newer versions available: {}", pkg_id, updated_versions ) .unwrap(); } } Some(updates) } /// Writes a future-incompat report to disk, using the per-package /// reports gathered during the build. If requested by the user, /// a message is also displayed in the build output. pub fn save_and_display_report( bcx: &BuildContext<'_, '_>, per_package_future_incompat_reports: &[FutureIncompatReportPackage], ) { let should_display_message = match bcx.gctx.future_incompat_config() { Ok(config) => config.should_display_message(), Err(e) => { crate::display_warning_with_error( "failed to read future-incompat config from disk", &e, &mut bcx.gctx.shell(), ); true } }; if per_package_future_incompat_reports.is_empty() { // Explicitly passing a command-line flag overrides // `should_display_message` from the config file if bcx.build_config.future_incompat_report { drop( bcx.gctx .shell() .note("0 dependencies had future-incompatible warnings"), ); } return; } let current_reports = match OnDiskReports::load(bcx.ws) { Ok(r) => r, Err(e) => { tracing::debug!( "saving future-incompatible reports failed to load current reports: {:?}", e ); OnDiskReports::default() } }; let report_id = current_reports.next_id; // Get a list of unique and sorted package name/versions. let package_ids: BTreeSet<_> = per_package_future_incompat_reports .iter() .map(|r| r.package_id) .collect(); let package_vers: Vec<_> = package_ids.iter().map(|pid| pid.to_string()).collect(); if should_display_message || bcx.build_config.future_incompat_report { drop(bcx.gctx.shell().warn(&format!( "the following packages contain code that will be rejected by a future \ version of Rust: {}", package_vers.join(", ") ))); } let updated_versions = get_updates(bcx.ws, &package_ids).unwrap_or(String::new()); let update_message = if !updated_versions.is_empty() { format!( " - Some affected dependencies have newer versions available. You may want to consider updating them to a newer version to see if the issue has been fixed. {updated_versions}\n", updated_versions = updated_versions ) } else { String::new() }; let upstream_info = package_ids .iter() .map(|package_id| { let manifest = bcx.packages.get_one(*package_id).unwrap().manifest(); format!( " - {package_spec} - Repository: {url} - Detailed warning command: `cargo report future-incompatibilities --id {id} --package {package_spec}`", package_spec = format!("{}@{}", package_id.name(), package_id.version()), url = manifest .metadata() .repository .as_deref() .unwrap_or(""), id = report_id, ) }) .collect::>() .join("\n"); let suggestion_message = format!( " To solve this problem, you can try the following approaches: {update_message} - If the issue is not solved by updating the dependencies, a fix has to be implemented by those dependencies. You can help with that by notifying the maintainers of this problem (e.g. by creating a bug report) or by proposing a fix to the maintainers (e.g. by creating a pull request): {upstream_info} - If waiting for an upstream fix is not an option, you can use the `[patch]` section in `Cargo.toml` to use your own version of the dependency. For more information, see: https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html#the-patch-section ", upstream_info = upstream_info, update_message = update_message, ); let saved_report_id = current_reports.save_report( bcx.ws, suggestion_message.clone(), per_package_future_incompat_reports, ); if bcx.build_config.future_incompat_report { drop(bcx.gctx.shell().note(&suggestion_message)); drop(bcx.gctx.shell().note(&format!( "this report can be shown with `cargo report \ future-incompatibilities --id {}`", saved_report_id ))); } else if should_display_message { drop(bcx.gctx.shell().note(&format!( "to see what the problems were, use the option \ `--future-incompat-report`, or run `cargo report \ future-incompatibilities --id {}`", saved_report_id ))); } } cargo-0.86.0/src/cargo/core/compiler/job_queue/job.rs000064400000000000000000000056531046102023000205450ustar 00000000000000//! See [`Job`] and [`Work`]. use std::fmt; use std::mem; use super::JobState; use crate::core::compiler::fingerprint::DirtyReason; use crate::util::CargoResult; /// Represents a unit of [`Work`] with a [`Freshness`] for caller /// to determine whether to re-execute or not. pub struct Job { work: Work, fresh: Freshness, } /// The basic unit of work. /// /// Each proc should send its description before starting. /// It should send either once or close immediately. pub struct Work { inner: Box) -> CargoResult<()> + Send>, } impl Work { /// Creates a unit of work. pub fn new(f: F) -> Work where F: FnOnce(&JobState<'_, '_>) -> CargoResult<()> + Send + 'static, { Work { inner: Box::new(f) } } /// Creates a unit of work that does nothing. pub fn noop() -> Work { Work::new(|_| Ok(())) } /// Consumes this work by running it. pub fn call(self, tx: &JobState<'_, '_>) -> CargoResult<()> { (self.inner)(tx) } /// Creates a new unit of work that chains `next` after ourself. pub fn then(self, next: Work) -> Work { Work::new(move |state| { self.call(state)?; next.call(state) }) } } impl Job { /// Creates a new job that does nothing. pub fn new_fresh() -> Job { Job { work: Work::noop(), fresh: Freshness::Fresh, } } /// Creates a new job representing a unit of work. pub fn new_dirty(work: Work, dirty_reason: DirtyReason) -> Job { Job { work, fresh: Freshness::Dirty(dirty_reason), } } /// Consumes this job by running it, returning the result of the /// computation. pub fn run(self, state: &JobState<'_, '_>) -> CargoResult<()> { self.work.call(state) } /// Returns whether this job was fresh/dirty, where "fresh" means we're /// likely to perform just some small bookkeeping where "dirty" means we'll /// probably do something slow like invoke rustc. pub fn freshness(&self) -> &Freshness { &self.fresh } /// Chains the given work by putting it in front of our own unit of work. pub fn before(&mut self, next: Work) { let prev = mem::replace(&mut self.work, Work::noop()); self.work = next.then(prev); } } impl fmt::Debug for Job { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Job {{ ... }}") } } /// Indication of the freshness of a package. /// /// A fresh package does not necessarily need to be rebuilt (unless a dependency /// was also rebuilt), and a dirty package must always be rebuilt. #[derive(Debug, Clone)] pub enum Freshness { Fresh, Dirty(DirtyReason), } impl Freshness { pub fn is_dirty(&self) -> bool { matches!(self, Freshness::Dirty(_)) } pub fn is_fresh(&self) -> bool { matches!(self, Freshness::Fresh) } } cargo-0.86.0/src/cargo/core/compiler/job_queue/job_state.rs000064400000000000000000000164431046102023000217440ustar 00000000000000//! See [`JobState`]. use std::{cell::Cell, marker, sync::Arc}; use cargo_util::ProcessBuilder; use crate::core::compiler::build_runner::OutputFile; use crate::core::compiler::future_incompat::FutureBreakageItem; use crate::util::Queue; use crate::CargoResult; use super::{Artifact, DiagDedupe, Job, JobId, Message}; /// A `JobState` is constructed by `JobQueue::run` and passed to `Job::run`. It includes everything /// necessary to communicate between the main thread and the execution of the job. /// /// The job may execute on either a dedicated thread or the main thread. If the job executes on the /// main thread, the `output` field must be set to prevent a deadlock. pub struct JobState<'a, 'gctx> { /// Channel back to the main thread to coordinate messages and such. /// /// When the `output` field is `Some`, care must be taken to avoid calling `push_bounded` on /// the message queue to prevent a deadlock. messages: Arc>, /// Normally output is sent to the job queue with backpressure. When the job is fresh /// however we need to immediately display the output to prevent a deadlock as the /// output messages are processed on the same thread as they are sent from. `output` /// defines where to output in this case. /// /// Currently the [`Shell`] inside [`GlobalContext`] is wrapped in a `RefCell` and thus can't /// be passed between threads. This means that it isn't possible for multiple output messages /// to be interleaved. In the future, it may be wrapped in a `Mutex` instead. In this case /// interleaving is still prevented as the lock would be held for the whole printing of an /// output message. /// /// [`Shell`]: crate::core::Shell /// [`GlobalContext`]: crate::GlobalContext output: Option<&'a DiagDedupe<'gctx>>, /// The job id that this state is associated with, used when sending /// messages back to the main thread. id: JobId, /// Whether or not we're expected to have a call to `rmeta_produced`. Once /// that method is called this is dynamically set to `false` to prevent /// sending a double message later on. rmeta_required: Cell, // Historical versions of Cargo made use of the `'a` argument here, so to // leave the door open to future refactorings keep it here. _marker: marker::PhantomData<&'a ()>, } impl<'a, 'gctx> JobState<'a, 'gctx> { pub(super) fn new( id: JobId, messages: Arc>, output: Option<&'a DiagDedupe<'gctx>>, rmeta_required: bool, ) -> Self { Self { id, messages, output, rmeta_required: Cell::new(rmeta_required), _marker: marker::PhantomData, } } pub fn running(&self, cmd: &ProcessBuilder) { self.messages.push(Message::Run(self.id, cmd.to_string())); } pub fn build_plan( &self, module_name: String, cmd: ProcessBuilder, filenames: Arc>, ) { self.messages .push(Message::BuildPlanMsg(module_name, cmd, filenames)); } pub fn stdout(&self, stdout: String) -> CargoResult<()> { if let Some(dedupe) = self.output { writeln!(dedupe.gctx.shell().out(), "{}", stdout)?; } else { self.messages.push_bounded(Message::Stdout(stdout)); } Ok(()) } pub fn stderr(&self, stderr: String) -> CargoResult<()> { if let Some(dedupe) = self.output { let mut shell = dedupe.gctx.shell(); shell.print_ansi_stderr(stderr.as_bytes())?; shell.err().write_all(b"\n")?; } else { self.messages.push_bounded(Message::Stderr(stderr)); } Ok(()) } /// See [`Message::Diagnostic`] and [`Message::WarningCount`]. pub fn emit_diag(&self, level: &str, diag: String, fixable: bool) -> CargoResult<()> { if let Some(dedupe) = self.output { let emitted = dedupe.emit_diag(&diag)?; if level == "warning" { self.messages.push(Message::WarningCount { id: self.id, emitted, fixable, }); } } else { self.messages.push_bounded(Message::Diagnostic { id: self.id, level: level.to_string(), diag, fixable, }); } Ok(()) } /// See [`Message::Warning`]. pub fn warning(&self, warning: String) -> CargoResult<()> { self.messages.push_bounded(Message::Warning { id: self.id, warning, }); Ok(()) } /// A method used to signal to the coordinator thread that the rmeta file /// for an rlib has been produced. This is only called for some rmeta /// builds when required, and can be called at any time before a job ends. /// This should only be called once because a metadata file can only be /// produced once! pub fn rmeta_produced(&self) { self.rmeta_required.set(false); self.messages .push(Message::Finish(self.id, Artifact::Metadata, Ok(()))); } /// Drives a [`Job`] to finish. This ensures that a [`Message::Finish`] is /// sent even if our job panics. pub(super) fn run_to_finish(self, job: Job) { let mut sender = FinishOnDrop { messages: &self.messages, id: self.id, result: None, }; sender.result = Some(job.run(&self)); // If the `rmeta_required` wasn't consumed but it was set // previously, then we either have: // // 1. The `job` didn't do anything because it was "fresh". // 2. The `job` returned an error and didn't reach the point where // it called `rmeta_produced`. // 3. We forgot to call `rmeta_produced` and there's a bug in Cargo. // // Ruling out the third, the other two are pretty common for 2 // we'll just naturally abort the compilation operation but for 1 // we need to make sure that the metadata is flagged as produced so // send a synthetic message here. if self.rmeta_required.get() && sender.result.as_ref().unwrap().is_ok() { self.messages .push(Message::Finish(self.id, Artifact::Metadata, Ok(()))); } // Use a helper struct with a `Drop` implementation to guarantee // that a `Finish` message is sent even if our job panics. We // shouldn't panic unless there's a bug in Cargo, so we just need // to make sure nothing hangs by accident. struct FinishOnDrop<'a> { messages: &'a Queue, id: JobId, result: Option>, } impl Drop for FinishOnDrop<'_> { fn drop(&mut self) { let result = self .result .take() .unwrap_or_else(|| Err(anyhow::format_err!("worker panicked"))); self.messages .push(Message::Finish(self.id, Artifact::All, result)); } } } pub fn future_incompat_report(&self, report: Vec) { self.messages .push(Message::FutureIncompatReport(self.id, report)); } } cargo-0.86.0/src/cargo/core/compiler/job_queue/mod.rs000064400000000000000000001417401046102023000205500ustar 00000000000000//! Management of the interaction between the main `cargo` and all spawned jobs. //! //! ## Overview //! //! This module implements a job queue. A job here represents a unit of work, //! which is roughly a rustc invocation, a build script run, or just a no-op. //! The job queue primarily handles the following things: //! //! * Spawns concurrent jobs. Depending on its [`Freshness`], a job could be //! either executed on a spawned thread or ran on the same thread to avoid //! the threading overhead. //! * Controls the number of concurrency. It allocates and manages [`jobserver`] //! tokens to each spawned off rustc and build scripts. //! * Manages the communication between the main `cargo` process and its //! spawned jobs. Those [`Message`]s are sent over a [`Queue`] shared //! across threads. //! * Schedules the execution order of each [`Job`]. Priorities are determined //! when calling [`JobQueue::enqueue`] to enqueue a job. The scheduling is //! relatively rudimentary and could likely be improved. //! //! A rough outline of building a queue and executing jobs is: //! //! 1. [`JobQueue::new`] to simply create one queue. //! 2. [`JobQueue::enqueue`] to add new jobs onto the queue. //! 3. Consumes the queue and executes all jobs via [`JobQueue::execute`]. //! //! The primary loop happens insides [`JobQueue::execute`], which is effectively //! [`DrainState::drain_the_queue`]. [`DrainState`] is, as its name tells, //! the running state of the job queue getting drained. //! //! ## Jobserver //! //! As of Feb. 2023, Cargo and rustc have a relatively simple jobserver //! relationship with each other. They share a single jobserver amongst what //! is potentially hundreds of threads of work on many-cored systems. //! The jobserver could come from either the environment (e.g., from a `make` //! invocation), or from Cargo creating its own jobserver server if there is no //! jobserver to inherit from. //! //! Cargo wants to complete the build as quickly as possible, fully saturating //! all cores (as constrained by the `-j=N`) parameter. Cargo also must not spawn //! more than N threads of work: the total amount of tokens we have floating //! around must always be limited to N. //! //! It is not really possible to optimally choose which crate should build //! first or last; nor is it possible to decide whether to give an additional //! token to rustc first or rather spawn a new crate of work. The algorithm in //! Cargo prioritizes spawning as many crates (i.e., rustc processes) as //! possible. In short, the jobserver relationship among Cargo and rustc //! processes is **1 `cargo` to N `rustc`**. Cargo knows nothing beyond rustc //! processes in terms of parallelism[^parallel-rustc]. //! //! We integrate with the [jobserver] crate, originating from GNU make //! [POSIX jobserver], to make sure that build scripts which use make to //! build C code can cooperate with us on the number of used tokens and //! avoid overfilling the system we're on. //! //! ## Scheduling //! //! The current scheduling algorithm is not really polished. It is simply based //! on a dependency graph [`DependencyQueue`]. We continue adding nodes onto //! the graph until we finalize it. When the graph gets finalized, it finds the //! sum of the cost of each dependencies of each node, including transitively. //! The sum of dependency cost turns out to be the cost of each given node. //! //! At the time being, the cost is just passed as a fixed placeholder in //! [`JobQueue::enqueue`]. In the future, we could explore more possibilities //! around it. For instance, we start persisting timing information for each //! build somewhere. For a subsequent build, we can look into the historical //! data and perform a PGO-like optimization to prioritize jobs, making a build //! fully pipelined. //! //! ## Message queue //! //! Each spawned thread running a process uses the message queue [`Queue`] to //! send messages back to the main thread (the one running `cargo`). //! The main thread coordinates everything, and handles printing output. //! //! It is important to be careful which messages use [`push`] vs [`push_bounded`]. //! `push` is for priority messages (like tokens, or "finished") where the //! sender shouldn't block. We want to handle those so real work can proceed //! ASAP. //! //! `push_bounded` is only for messages being printed to stdout/stderr. Being //! bounded prevents a flood of messages causing a large amount of memory //! being used. //! //! `push` also avoids blocking which helps avoid deadlocks. For example, when //! the diagnostic server thread is dropped, it waits for the thread to exit. //! But if the thread is blocked on a full queue, and there is a critical //! error, the drop will deadlock. This should be fixed at some point in the //! future. The jobserver thread has a similar problem, though it will time //! out after 1 second. //! //! To access the message queue, each running `Job` is given its own [`JobState`], //! containing everything it needs to communicate with the main thread. //! //! See [`Message`] for all available message kinds. //! //! [^parallel-rustc]: In fact, `jobserver` that Cargo uses also manages the //! allocation of tokens to rustc beyond the implicit token each rustc owns //! (i.e., the ones used for parallel LLVM work and parallel rustc threads). //! See also ["Rust Compiler Development Guide: Parallel Compilation"] //! and [this comment][rustc-codegen] in rust-lang/rust. //! //! ["Rust Compiler Development Guide: Parallel Compilation"]: https://rustc-dev-guide.rust-lang.org/parallel-rustc.html //! [rustc-codegen]: https://github.com/rust-lang/rust/blob/5423745db8b434fcde54888b35f518f00cce00e4/compiler/rustc_codegen_ssa/src/back/write.rs#L1204-L1217 //! [jobserver]: https://docs.rs/jobserver //! [POSIX jobserver]: https://www.gnu.org/software/make/manual/html_node/POSIX-Jobserver.html //! [`push`]: Queue::push //! [`push_bounded`]: Queue::push_bounded mod job; mod job_state; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::fmt::Write as _; use std::io; use std::path::{Path, PathBuf}; use std::sync::Arc; use std::thread::{self, Scope}; use std::time::Duration; use anyhow::{format_err, Context as _}; use cargo_util::ProcessBuilder; use jobserver::{Acquired, HelperThread}; use semver::Version; use tracing::{debug, trace}; pub use self::job::Freshness::{self, Dirty, Fresh}; pub use self::job::{Job, Work}; pub use self::job_state::JobState; use super::build_runner::OutputFile; use super::custom_build::Severity; use super::timings::Timings; use super::{BuildContext, BuildPlan, BuildRunner, CompileMode, Unit}; use crate::core::compiler::descriptive_pkg_name; use crate::core::compiler::future_incompat::{ self, FutureBreakageItem, FutureIncompatReportPackage, }; use crate::core::resolver::ResolveBehavior; use crate::core::{PackageId, Shell, TargetKind}; use crate::util::context::WarningHandling; use crate::util::diagnostic_server::{self, DiagnosticPrinter}; use crate::util::errors::AlreadyPrintedError; use crate::util::machine_message::{self, Message as _}; use crate::util::CargoResult; use crate::util::{self, internal}; use crate::util::{DependencyQueue, GlobalContext, Progress, ProgressStyle, Queue}; /// This structure is backed by the `DependencyQueue` type and manages the /// queueing of compilation steps for each package. Packages enqueue units of /// work and then later on the entire graph is converted to `DrainState` and /// executed. pub struct JobQueue<'gctx> { queue: DependencyQueue, counts: HashMap, timings: Timings<'gctx>, } /// This structure is backed by the `DependencyQueue` type and manages the /// actual compilation step of each package. Packages enqueue units of work and /// then later on the entire graph is processed and compiled. /// /// It is created from `JobQueue` when we have fully assembled the crate graph /// (i.e., all package dependencies are known). struct DrainState<'gctx> { // This is the length of the DependencyQueue when starting out total_units: usize, queue: DependencyQueue, messages: Arc>, /// Diagnostic deduplication support. diag_dedupe: DiagDedupe<'gctx>, /// Count of warnings, used to print a summary after the job succeeds warning_count: HashMap, active: HashMap, compiled: HashSet, documented: HashSet, scraped: HashSet, counts: HashMap, progress: Progress<'gctx>, next_id: u32, timings: Timings<'gctx>, /// Tokens that are currently owned by this Cargo, and may be "associated" /// with a rustc process. They may also be unused, though if so will be /// dropped on the next loop iteration. /// /// Note that the length of this may be zero, but we will still spawn work, /// as we share the implicit token given to this Cargo process with a /// single rustc process. tokens: Vec, /// The list of jobs that we have not yet started executing, but have /// retrieved from the `queue`. We eagerly pull jobs off the main queue to /// allow us to request jobserver tokens pretty early. pending_queue: Vec<(Unit, Job, usize)>, print: DiagnosticPrinter<'gctx>, /// How many jobs we've finished finished: usize, per_package_future_incompat_reports: Vec, } /// Count of warnings, used to print a summary after the job succeeds #[derive(Default)] pub struct WarningCount { /// total number of warnings pub total: usize, /// number of warnings that were suppressed because they /// were duplicates of a previous warning pub duplicates: usize, /// number of fixable warnings set to `NotAllowed` /// if any errors have been seen ofr the current /// target pub fixable: FixableWarnings, } impl WarningCount { /// If an error is seen this should be called /// to set `fixable` to `NotAllowed` fn disallow_fixable(&mut self) { self.fixable = FixableWarnings::NotAllowed; } /// Checks fixable if warnings are allowed /// fixable warnings are allowed if no /// errors have been seen for the current /// target. If an error was seen `fixable` /// will be `NotAllowed`. fn fixable_allowed(&self) -> bool { match &self.fixable { FixableWarnings::NotAllowed => false, _ => true, } } } /// Used to keep track of how many fixable warnings there are /// and if fixable warnings are allowed #[derive(Default)] pub enum FixableWarnings { NotAllowed, #[default] Zero, Positive(usize), } pub struct ErrorsDuringDrain { pub count: usize, } struct ErrorToHandle { error: anyhow::Error, /// This field is true for "interesting" errors and false for "mundane" /// errors. If false, we print the above error only if it's the first one /// encountered so far while draining the job queue. /// /// At most places that an error is propagated, we set this to false to /// avoid scenarios where Cargo might end up spewing tons of redundant error /// messages. For example if an i/o stream got closed somewhere, we don't /// care about individually reporting every thread that it broke; just the /// first is enough. /// /// The exception where `print_always` is true is that we do report every /// instance of a rustc invocation that failed with diagnostics. This /// corresponds to errors from `Message::Finish`. print_always: bool, } impl From for ErrorToHandle where anyhow::Error: From, { fn from(error: E) -> Self { ErrorToHandle { error: anyhow::Error::from(error), print_always: false, } } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct JobId(pub u32); impl std::fmt::Display for JobId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } /// Handler for deduplicating diagnostics. struct DiagDedupe<'gctx> { seen: RefCell>, gctx: &'gctx GlobalContext, } impl<'gctx> DiagDedupe<'gctx> { fn new(gctx: &'gctx GlobalContext) -> Self { DiagDedupe { seen: RefCell::new(HashSet::new()), gctx, } } /// Emits a diagnostic message. /// /// Returns `true` if the message was emitted, or `false` if it was /// suppressed for being a duplicate. fn emit_diag(&self, diag: &str) -> CargoResult { let h = util::hash_u64(diag); if !self.seen.borrow_mut().insert(h) { return Ok(false); } let mut shell = self.gctx.shell(); shell.print_ansi_stderr(diag.as_bytes())?; shell.err().write_all(b"\n")?; Ok(true) } } /// Possible artifacts that can be produced by compilations, used as edge values /// in the dependency graph. /// /// As edge values we can have multiple kinds of edges depending on one node, /// for example some units may only depend on the metadata for an rlib while /// others depend on the full rlib. This `Artifact` enum is used to distinguish /// this case and track the progress of compilations as they proceed. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] enum Artifact { /// A generic placeholder for "depends on everything run by a step" and /// means that we can't start the next compilation until the previous has /// finished entirely. All, /// A node indicating that we only depend on the metadata of a compilation, /// but the compilation is typically also producing an rlib. We can start /// our step, however, before the full rlib is available. Metadata, } enum Message { Run(JobId, String), BuildPlanMsg(String, ProcessBuilder, Arc>), Stdout(String), Stderr(String), // This is for general stderr output from subprocesses Diagnostic { id: JobId, level: String, diag: String, fixable: bool, }, // This handles duplicate output that is suppressed, for showing // only a count of duplicate messages instead WarningCount { id: JobId, emitted: bool, fixable: bool, }, // This is for warnings generated by Cargo's interpretation of the // subprocess output, e.g. scrape-examples prints a warning if a // unit fails to be scraped Warning { id: JobId, warning: String, }, FixDiagnostic(diagnostic_server::Message), Token(io::Result), Finish(JobId, Artifact, CargoResult<()>), FutureIncompatReport(JobId, Vec), } impl<'gctx> JobQueue<'gctx> { pub fn new(bcx: &BuildContext<'_, 'gctx>) -> JobQueue<'gctx> { JobQueue { queue: DependencyQueue::new(), counts: HashMap::new(), timings: Timings::new(bcx, &bcx.roots), } } pub fn enqueue( &mut self, build_runner: &BuildRunner<'_, 'gctx>, unit: &Unit, job: Job, ) -> CargoResult<()> { let dependencies = build_runner.unit_deps(unit); let mut queue_deps = dependencies .iter() .filter(|dep| { // Binaries aren't actually needed to *compile* tests, just to run // them, so we don't include this dependency edge in the job graph. // But we shouldn't filter out dependencies being scraped for Rustdoc. (!dep.unit.target.is_test() && !dep.unit.target.is_bin()) || dep.unit.artifact.is_true() || dep.unit.mode.is_doc_scrape() }) .map(|dep| { // Handle the case here where our `unit -> dep` dependency may // only require the metadata, not the full compilation to // finish. Use the tables in `build_runner` to figure out what // kind of artifact is associated with this dependency. let artifact = if build_runner.only_requires_rmeta(unit, &dep.unit) { Artifact::Metadata } else { Artifact::All }; (dep.unit.clone(), artifact) }) .collect::>(); // This is somewhat tricky, but we may need to synthesize some // dependencies for this target if it requires full upstream // compilations to have completed. Because of pipelining, some // dependency edges may be `Metadata` due to the above clause (as // opposed to everything being `All`). For example consider: // // a (binary) // β”” b (lib) // β”” c (lib) // // Here the dependency edge from B to C will be `Metadata`, and the // dependency edge from A to B will be `All`. For A to be compiled, // however, it currently actually needs the full rlib of C. This means // that we need to synthesize a dependency edge for the dependency graph // from A to C. That's done here. // // This will walk all dependencies of the current target, and if any of // *their* dependencies are `Metadata` then we depend on the `All` of // the target as well. This should ensure that edges changed to // `Metadata` propagate upwards `All` dependencies to anything that // transitively contains the `Metadata` edge. if unit.requires_upstream_objects() { for dep in dependencies { depend_on_deps_of_deps(build_runner, &mut queue_deps, dep.unit.clone()); } fn depend_on_deps_of_deps( build_runner: &BuildRunner<'_, '_>, deps: &mut HashMap, unit: Unit, ) { for dep in build_runner.unit_deps(&unit) { if deps.insert(dep.unit.clone(), Artifact::All).is_none() { depend_on_deps_of_deps(build_runner, deps, dep.unit.clone()); } } } } // For now we use a fixed placeholder value for the cost of each unit, but // in the future this could be used to allow users to provide hints about // relative expected costs of units, or this could be automatically set in // a smarter way using timing data from a previous compilation. self.queue.queue(unit.clone(), job, queue_deps, 100); *self.counts.entry(unit.pkg.package_id()).or_insert(0) += 1; Ok(()) } /// Executes all jobs necessary to build the dependency graph. /// /// This function will spawn off `config.jobs()` workers to build all of the /// necessary dependencies, in order. Freshness is propagated as far as /// possible along each dependency chain. #[tracing::instrument(skip_all)] pub fn execute( mut self, build_runner: &mut BuildRunner<'_, '_>, plan: &mut BuildPlan, ) -> CargoResult<()> { self.queue.queue_finished(); let progress = Progress::with_style("Building", ProgressStyle::Ratio, build_runner.bcx.gctx); let state = DrainState { total_units: self.queue.len(), queue: self.queue, // 100 here is somewhat arbitrary. It is a few screenfulls of // output, and hopefully at most a few megabytes of memory for // typical messages. If you change this, please update the test // caching_large_output, too. messages: Arc::new(Queue::new(100)), diag_dedupe: DiagDedupe::new(build_runner.bcx.gctx), warning_count: HashMap::new(), active: HashMap::new(), compiled: HashSet::new(), documented: HashSet::new(), scraped: HashSet::new(), counts: self.counts, progress, next_id: 0, timings: self.timings, tokens: Vec::new(), pending_queue: Vec::new(), print: DiagnosticPrinter::new( build_runner.bcx.gctx, &build_runner.bcx.rustc().workspace_wrapper, ), finished: 0, per_package_future_incompat_reports: Vec::new(), }; // Create a helper thread for acquiring jobserver tokens let messages = state.messages.clone(); let helper = build_runner .jobserver .clone() .into_helper_thread(move |token| { messages.push(Message::Token(token)); }) .context("failed to create helper thread for jobserver management")?; // Create a helper thread to manage the diagnostics for rustfix if // necessary. let messages = state.messages.clone(); // It is important that this uses `push` instead of `push_bounded` for // now. If someone wants to fix this to be bounded, the `drop` // implementation needs to be changed to avoid possible deadlocks. let _diagnostic_server = build_runner .bcx .build_config .rustfix_diagnostic_server .borrow_mut() .take() .map(move |srv| srv.start(move |msg| messages.push(Message::FixDiagnostic(msg)))); thread::scope(move |scope| { match state.drain_the_queue(build_runner, plan, scope, &helper) { Some(err) => Err(err), None => Ok(()), } }) } } impl<'gctx> DrainState<'gctx> { fn spawn_work_if_possible<'s>( &mut self, build_runner: &mut BuildRunner<'_, '_>, jobserver_helper: &HelperThread, scope: &'s Scope<'s, '_>, ) -> CargoResult<()> { // Dequeue as much work as we can, learning about everything // possible that can run. Note that this is also the point where we // start requesting job tokens. Each job after the first needs to // request a token. while let Some((unit, job, priority)) = self.queue.dequeue() { // We want to keep the pieces of work in the `pending_queue` sorted // by their priorities, and insert the current job at its correctly // sorted position: following the lower priority jobs, and the ones // with the same priority (since they were dequeued before the // current one, we also keep that relation). let idx = self .pending_queue .partition_point(|&(_, _, p)| p <= priority); self.pending_queue.insert(idx, (unit, job, priority)); if self.active.len() + self.pending_queue.len() > 1 { jobserver_helper.request_token(); } } // Now that we've learned of all possible work that we can execute // try to spawn it so long as we've got a jobserver token which says // we're able to perform some parallel work. // The `pending_queue` is sorted in ascending priority order, and we // remove items from its end to schedule the highest priority items // sooner. while self.has_extra_tokens() && !self.pending_queue.is_empty() { let (unit, job, _) = self.pending_queue.pop().unwrap(); *self.counts.get_mut(&unit.pkg.package_id()).unwrap() -= 1; if !build_runner.bcx.build_config.build_plan { // Print out some nice progress information. // NOTE: An error here will drop the job without starting it. // That should be OK, since we want to exit as soon as // possible during an error. self.note_working_on( build_runner.bcx.gctx, build_runner.bcx.ws.root(), &unit, job.freshness(), )?; } self.run(&unit, job, build_runner, scope); } Ok(()) } fn has_extra_tokens(&self) -> bool { self.active.len() < self.tokens.len() + 1 } fn handle_event( &mut self, build_runner: &mut BuildRunner<'_, '_>, plan: &mut BuildPlan, event: Message, ) -> Result<(), ErrorToHandle> { let warning_handling = build_runner.bcx.gctx.warning_handling()?; match event { Message::Run(id, cmd) => { build_runner .bcx .gctx .shell() .verbose(|c| c.status("Running", &cmd))?; self.timings.unit_start(id, self.active[&id].clone()); } Message::BuildPlanMsg(module_name, cmd, filenames) => { plan.update(&module_name, &cmd, &filenames)?; } Message::Stdout(out) => { writeln!(build_runner.bcx.gctx.shell().out(), "{}", out)?; } Message::Stderr(err) => { let mut shell = build_runner.bcx.gctx.shell(); shell.print_ansi_stderr(err.as_bytes())?; shell.err().write_all(b"\n")?; } Message::Diagnostic { id, level, diag, fixable, } => { let emitted = self.diag_dedupe.emit_diag(&diag)?; if level == "warning" { self.bump_warning_count(id, emitted, fixable); } if level == "error" { let cnts = self.warning_count.entry(id).or_default(); // If there is an error, the `cargo fix` message should not show cnts.disallow_fixable(); } } Message::Warning { id, warning } => { if warning_handling != WarningHandling::Allow { build_runner.bcx.gctx.shell().warn(warning)?; } self.bump_warning_count(id, true, false); } Message::WarningCount { id, emitted, fixable, } => { self.bump_warning_count(id, emitted, fixable); } Message::FixDiagnostic(msg) => { self.print.print(&msg)?; } Message::Finish(id, artifact, result) => { let unit = match artifact { // If `id` has completely finished we remove it // from the `active` map ... Artifact::All => { trace!("end: {:?}", id); self.finished += 1; self.report_warning_count( build_runner, id, &build_runner.bcx.rustc().workspace_wrapper, ); self.active.remove(&id).unwrap() } // ... otherwise if it hasn't finished we leave it // in there as we'll get another `Finish` later on. Artifact::Metadata => { trace!("end (meta): {:?}", id); self.active[&id].clone() } }; debug!("end ({:?}): {:?}", unit, result); match result { Ok(()) => self.finish(id, &unit, artifact, build_runner)?, Err(_) if build_runner.bcx.unit_can_fail_for_docscraping(&unit) => { build_runner .failed_scrape_units .lock() .unwrap() .insert(build_runner.files().metadata(&unit).unit_id()); self.queue.finish(&unit, &artifact); } Err(error) => { let show_warnings = true; self.emit_log_messages(&unit, build_runner, show_warnings)?; self.back_compat_notice(build_runner, &unit)?; return Err(ErrorToHandle { error, print_always: true, }); } } } Message::FutureIncompatReport(id, items) => { let package_id = self.active[&id].pkg.package_id(); self.per_package_future_incompat_reports .push(FutureIncompatReportPackage { package_id, items }); } Message::Token(acquired_token) => { let token = acquired_token.context("failed to acquire jobserver token")?; self.tokens.push(token); } } Ok(()) } // This will also tick the progress bar as appropriate fn wait_for_events(&mut self) -> Vec { // Drain all events at once to avoid displaying the progress bar // unnecessarily. If there's no events we actually block waiting for // an event, but we keep a "heartbeat" going to allow `record_cpu` // to run above to calculate CPU usage over time. To do this we // listen for a message with a timeout, and on timeout we run the // previous parts of the loop again. let mut events = self.messages.try_pop_all(); if events.is_empty() { loop { self.tick_progress(); self.tokens.truncate(self.active.len() - 1); match self.messages.pop(Duration::from_millis(500)) { Some(message) => { events.push(message); break; } None => continue, } } } events } /// This is the "main" loop, where Cargo does all work to run the /// compiler. /// /// This returns an Option to prevent the use of `?` on `Result` types /// because it is important for the loop to carefully handle errors. fn drain_the_queue<'s>( mut self, build_runner: &mut BuildRunner<'_, '_>, plan: &mut BuildPlan, scope: &'s Scope<'s, '_>, jobserver_helper: &HelperThread, ) -> Option { trace!("queue: {:#?}", self.queue); // Iteratively execute the entire dependency graph. Each turn of the // loop starts out by scheduling as much work as possible (up to the // maximum number of parallel jobs we have tokens for). A local queue // is maintained separately from the main dependency queue as one // dequeue may actually dequeue quite a bit of work (e.g., 10 binaries // in one package). // // After a job has finished we update our internal state if it was // successful and otherwise wait for pending work to finish if it failed // and then immediately return (or keep going, if requested by the build // config). let mut errors = ErrorsDuringDrain { count: 0 }; // CAUTION! Do not use `?` or break out of the loop early. Every error // must be handled in such a way that the loop is still allowed to // drain event messages. loop { if errors.count == 0 || build_runner.bcx.build_config.keep_going { if let Err(e) = self.spawn_work_if_possible(build_runner, jobserver_helper, scope) { self.handle_error(&mut build_runner.bcx.gctx.shell(), &mut errors, e); } } // If after all that we're not actually running anything then we're // done! if self.active.is_empty() { break; } // And finally, before we block waiting for the next event, drop any // excess tokens we may have accidentally acquired. Due to how our // jobserver interface is architected we may acquire a token that we // don't actually use, and if this happens just relinquish it back // to the jobserver itself. for event in self.wait_for_events() { if let Err(event_err) = self.handle_event(build_runner, plan, event) { self.handle_error(&mut build_runner.bcx.gctx.shell(), &mut errors, event_err); } } } self.progress.clear(); let profile_name = build_runner.bcx.build_config.requested_profile; // NOTE: this may be a bit inaccurate, since this may not display the // profile for what was actually built. Profile overrides can change // these settings, and in some cases different targets are built with // different profiles. To be accurate, it would need to collect a // list of Units built, and maybe display a list of the different // profiles used. However, to keep it simple and compatible with old // behavior, we just display what the base profile is. let profile = build_runner.bcx.profiles.base_profile(); let mut opt_type = String::from(if profile.opt_level.as_str() == "0" { "unoptimized" } else { "optimized" }); if profile.debuginfo.is_turned_on() { opt_type += " + debuginfo"; } let time_elapsed = util::elapsed(build_runner.bcx.gctx.creation_time().elapsed()); if let Err(e) = self.timings.finished(build_runner, &errors.to_error()) { self.handle_error(&mut build_runner.bcx.gctx.shell(), &mut errors, e); } if build_runner.bcx.build_config.emit_json() { let mut shell = build_runner.bcx.gctx.shell(); let msg = machine_message::BuildFinished { success: errors.count == 0, } .to_json_string(); if let Err(e) = writeln!(shell.out(), "{}", msg) { self.handle_error(&mut shell, &mut errors, e); } } if let Some(error) = errors.to_error() { // Any errors up to this point have already been printed via the // `display_error` inside `handle_error`. Some(anyhow::Error::new(AlreadyPrintedError::new(error))) } else if self.queue.is_empty() && self.pending_queue.is_empty() { let profile_link = build_runner.bcx.gctx.shell().err_hyperlink( "https://doc.rust-lang.org/cargo/reference/profiles.html#default-profiles", ); let message = format!( "{profile_link}`{profile_name}` profile [{opt_type}]{profile_link:#} target(s) in {time_elapsed}", ); if !build_runner.bcx.build_config.build_plan { // It doesn't really matter if this fails. let _ = build_runner.bcx.gctx.shell().status("Finished", message); future_incompat::save_and_display_report( build_runner.bcx, &self.per_package_future_incompat_reports, ); } None } else { debug!("queue: {:#?}", self.queue); Some(internal("finished with jobs still left in the queue")) } } fn handle_error( &self, shell: &mut Shell, err_state: &mut ErrorsDuringDrain, new_err: impl Into, ) { let new_err = new_err.into(); if new_err.print_always || err_state.count == 0 { crate::display_error(&new_err.error, shell); if err_state.count == 0 && !self.active.is_empty() { let _ = shell.warn("build failed, waiting for other jobs to finish..."); } err_state.count += 1; } else { tracing::warn!("{:?}", new_err.error); } } // This also records CPU usage and marks concurrency; we roughly want to do // this as often as we spin on the events receiver (at least every 500ms or // so). fn tick_progress(&mut self) { // Record some timing information if `--timings` is enabled, and // this'll end up being a noop if we're not recording this // information. self.timings.mark_concurrency( self.active.len(), self.pending_queue.len(), self.queue.len(), ); self.timings.record_cpu(); let active_names = self .active .values() .map(|u| self.name_for_progress(u)) .collect::>(); let _ = self.progress.tick_now( self.finished, self.total_units, &format!(": {}", active_names.join(", ")), ); } fn name_for_progress(&self, unit: &Unit) -> String { let pkg_name = unit.pkg.name(); let target_name = unit.target.name(); match unit.mode { CompileMode::Doc { .. } => format!("{}(doc)", pkg_name), CompileMode::RunCustomBuild => format!("{}(build)", pkg_name), CompileMode::Test | CompileMode::Check { test: true } => match unit.target.kind() { TargetKind::Lib(_) => format!("{}(test)", target_name), TargetKind::CustomBuild => panic!("cannot test build script"), TargetKind::Bin => format!("{}(bin test)", target_name), TargetKind::Test => format!("{}(test)", target_name), TargetKind::Bench => format!("{}(bench)", target_name), TargetKind::ExampleBin | TargetKind::ExampleLib(_) => { format!("{}(example test)", target_name) } }, _ => match unit.target.kind() { TargetKind::Lib(_) => pkg_name.to_string(), TargetKind::CustomBuild => format!("{}(build.rs)", pkg_name), TargetKind::Bin => format!("{}(bin)", target_name), TargetKind::Test => format!("{}(test)", target_name), TargetKind::Bench => format!("{}(bench)", target_name), TargetKind::ExampleBin | TargetKind::ExampleLib(_) => { format!("{}(example)", target_name) } }, } } /// Executes a job. /// /// Fresh jobs block until finished (which should be very fast!), Dirty /// jobs will spawn a thread in the background and return immediately. fn run<'s>( &mut self, unit: &Unit, job: Job, build_runner: &BuildRunner<'_, '_>, scope: &'s Scope<'s, '_>, ) { let id = JobId(self.next_id); self.next_id = self.next_id.checked_add(1).unwrap(); debug!("start {}: {:?}", id, unit); assert!(self.active.insert(id, unit.clone()).is_none()); let messages = self.messages.clone(); let is_fresh = job.freshness().is_fresh(); let rmeta_required = build_runner.rmeta_required(unit); let doit = move |diag_dedupe| { let state = JobState::new(id, messages, diag_dedupe, rmeta_required); state.run_to_finish(job); }; match is_fresh { true => { self.timings.add_fresh(); // Running a fresh job on the same thread is often much faster than spawning a new // thread to run the job. doit(Some(&self.diag_dedupe)); } false => { self.timings.add_dirty(); scope.spawn(move || doit(None)); } } } fn emit_log_messages( &self, unit: &Unit, build_runner: &mut BuildRunner<'_, '_>, show_warnings: bool, ) -> CargoResult<()> { let outputs = build_runner.build_script_outputs.lock().unwrap(); let Some(metadata) = build_runner.find_build_script_metadata(unit) else { return Ok(()); }; let bcx = &mut build_runner.bcx; if let Some(output) = outputs.get(metadata) { if !output.log_messages.is_empty() && (show_warnings || output .log_messages .iter() .any(|(severity, _)| *severity == Severity::Error)) { let msg_with_package = |msg: &str| format!("{}@{}: {}", unit.pkg.name(), unit.pkg.version(), msg); for (severity, message) in output.log_messages.iter() { match severity { Severity::Error => { bcx.gctx.shell().error(msg_with_package(message))?; } Severity::Warning => { bcx.gctx.shell().warn(msg_with_package(message))?; } } } } } Ok(()) } fn bump_warning_count(&mut self, id: JobId, emitted: bool, fixable: bool) { let cnts = self.warning_count.entry(id).or_default(); cnts.total += 1; if !emitted { cnts.duplicates += 1; // Don't add to fixable if it's already been emitted } else if fixable { // Do not add anything to the fixable warning count if // is `NotAllowed` since that indicates there was an // error while building this `Unit` if cnts.fixable_allowed() { cnts.fixable = match cnts.fixable { FixableWarnings::NotAllowed => FixableWarnings::NotAllowed, FixableWarnings::Zero => FixableWarnings::Positive(1), FixableWarnings::Positive(fixable) => FixableWarnings::Positive(fixable + 1), }; } } } /// Displays a final report of the warnings emitted by a particular job. fn report_warning_count( &mut self, runner: &mut BuildRunner<'_, '_>, id: JobId, rustc_workspace_wrapper: &Option, ) { let gctx = runner.bcx.gctx; let count = match self.warning_count.get(&id) { // An error could add an entry for a `Unit` // with 0 warnings but having fixable // warnings be disallowed Some(count) if count.total > 0 => count, None | Some(_) => return, }; runner.compilation.warning_count += count.total; let unit = &self.active[&id]; let mut message = descriptive_pkg_name(&unit.pkg.name(), &unit.target, &unit.mode); message.push_str(" generated "); match count.total { 1 => message.push_str("1 warning"), n => { let _ = write!(message, "{} warnings", n); } }; match count.duplicates { 0 => {} 1 => message.push_str(" (1 duplicate)"), n => { let _ = write!(message, " ({} duplicates)", n); } } // Only show the `cargo fix` message if its a local `Unit` if unit.is_local() { // Do not show this if there are any errors or no fixable warnings if let FixableWarnings::Positive(fixable) = count.fixable { // `cargo fix` doesn't have an option for custom builds if !unit.target.is_custom_build() { // To make sure the correct command is shown for `clippy` we // check if `RUSTC_WORKSPACE_WRAPPER` is set and pointing towards // `clippy-driver`. let clippy = std::ffi::OsStr::new("clippy-driver"); let command = match rustc_workspace_wrapper.as_ref().and_then(|x| x.file_stem()) { Some(wrapper) if wrapper == clippy => "cargo clippy --fix", _ => "cargo fix", }; let mut args = { let named = unit.target.description_named(); // if its a lib we need to add the package to fix if unit.target.is_lib() { format!("{} -p {}", named, unit.pkg.name()) } else { named } }; if unit.mode.is_rustc_test() && !(unit.target.is_test() || unit.target.is_bench()) { args.push_str(" --tests"); } let mut suggestions = format!("{} suggestion", fixable); if fixable > 1 { suggestions.push_str("s") } let _ = write!( message, " (run `{command} --{args}` to apply {suggestions})" ); } } } // Errors are ignored here because it is tricky to handle them // correctly, and they aren't important. let _ = gctx.shell().warn(message); } fn finish( &mut self, id: JobId, unit: &Unit, artifact: Artifact, build_runner: &mut BuildRunner<'_, '_>, ) -> CargoResult<()> { if unit.mode.is_run_custom_build() { self.emit_log_messages( unit, build_runner, unit.show_warnings(build_runner.bcx.gctx), )?; } let unlocked = self.queue.finish(unit, &artifact); match artifact { Artifact::All => self.timings.unit_finished(id, unlocked), Artifact::Metadata => self.timings.unit_rmeta_finished(id, unlocked), } Ok(()) } // This isn't super trivial because we don't want to print loads and // loads of information to the console, but we also want to produce a // faithful representation of what's happening. This is somewhat nuanced // as a package can start compiling *very* early on because of custom // build commands and such. // // In general, we try to print "Compiling" for the first nontrivial task // run for a package, regardless of when that is. We then don't print // out any more information for a package after we've printed it once. fn note_working_on( &mut self, gctx: &GlobalContext, ws_root: &Path, unit: &Unit, fresh: &Freshness, ) -> CargoResult<()> { if (self.compiled.contains(&unit.pkg.package_id()) && !unit.mode.is_doc() && !unit.mode.is_doc_scrape()) || (self.documented.contains(&unit.pkg.package_id()) && unit.mode.is_doc()) || (self.scraped.contains(&unit.pkg.package_id()) && unit.mode.is_doc_scrape()) { return Ok(()); } match fresh { // Any dirty stage which runs at least one command gets printed as // being a compiled package. Dirty(dirty_reason) => { if !dirty_reason.is_fresh_build() { gctx.shell() .verbose(|shell| dirty_reason.present_to(shell, unit, ws_root))?; } if unit.mode.is_doc() { self.documented.insert(unit.pkg.package_id()); gctx.shell().status("Documenting", &unit.pkg)?; } else if unit.mode.is_doc_test() { // Skip doc test. } else if unit.mode.is_doc_scrape() { self.scraped.insert(unit.pkg.package_id()); gctx.shell().status("Scraping", &unit.pkg)?; } else { self.compiled.insert(unit.pkg.package_id()); if unit.mode.is_check() { gctx.shell().status("Checking", &unit.pkg)?; } else { gctx.shell().status("Compiling", &unit.pkg)?; } } } Fresh => { // If doc test are last, only print "Fresh" if nothing has been printed. if self.counts[&unit.pkg.package_id()] == 0 && !(unit.mode.is_doc_test() && self.compiled.contains(&unit.pkg.package_id())) { self.compiled.insert(unit.pkg.package_id()); gctx.shell().verbose(|c| c.status("Fresh", &unit.pkg))?; } } } Ok(()) } fn back_compat_notice( &self, build_runner: &BuildRunner<'_, '_>, unit: &Unit, ) -> CargoResult<()> { if unit.pkg.name() != "diesel" || unit.pkg.version() >= &Version::new(1, 4, 8) || build_runner.bcx.ws.resolve_behavior() == ResolveBehavior::V1 || !unit.pkg.package_id().source_id().is_registry() || !unit.features.is_empty() { return Ok(()); } if !build_runner .bcx .unit_graph .keys() .any(|unit| unit.pkg.name() == "diesel" && !unit.features.is_empty()) { return Ok(()); } build_runner.bcx.gctx.shell().note( "\ This error may be due to an interaction between diesel and Cargo's new feature resolver. Try updating to diesel 1.4.8 to fix this error. ", )?; Ok(()) } } impl ErrorsDuringDrain { fn to_error(&self) -> Option { match self.count { 0 => None, 1 => Some(format_err!("1 job failed")), n => Some(format_err!("{} jobs failed", n)), } } } cargo-0.86.0/src/cargo/core/compiler/layout.rs000064400000000000000000000217661046102023000173350ustar 00000000000000//! Management of the directory layout of a build //! //! The directory layout is a little tricky at times, hence a separate file to //! house this logic. The current layout looks like this: //! //! ```text //! # This is the root directory for all output, the top-level package //! # places all of its output here. //! target/ //! //! # Cache of `rustc -Vv` output for performance. //! .rustc-info.json //! //! # All final artifacts are linked into this directory from `deps`. //! # Note that named profiles will soon be included as separate directories //! # here. They have a restricted format, similar to Rust identifiers, so //! # Cargo-specific directories added in the future should use some prefix //! # like `.` to avoid name collisions. //! debug/ # or release/ //! //! # File used to lock the directory to prevent multiple cargo processes //! # from using it at the same time. //! .cargo-lock //! //! # Hidden directory that holds all of the fingerprint files for all //! # packages //! .fingerprint/ //! # Each package is in a separate directory. //! # Note that different target kinds have different filename prefixes. //! $pkgname-$META/ //! # Set of source filenames for this package. //! dep-lib-$targetname //! # Timestamp when this package was last built. //! invoked.timestamp //! # The fingerprint hash. //! lib-$targetname //! # Detailed information used for logging the reason why //! # something is being recompiled. //! lib-$targetname.json //! # The console output from the compiler. This is cached //! # so that warnings can be redisplayed for "fresh" units. //! output-lib-$targetname //! //! # This is the root directory for all rustc artifacts except build //! # scripts, examples, and test and bench executables. Almost every //! # artifact should have a metadata hash added to its filename to //! # prevent collisions. One notable exception is dynamic libraries. //! deps/ //! //! # Each artifact dependency gets in its own directory. //! /artifact/$pkgname-$META/$kind //! //! # Root directory for all compiled examples. //! examples/ //! //! # Directory used to store incremental data for the compiler (when //! # incremental is enabled. //! incremental/ //! //! # This is the location at which the output of all custom build //! # commands are rooted. //! build/ //! //! # Each package gets its own directory where its build script and //! # script output are placed //! $pkgname-$META/ # For the build script itself. //! # The build script executable (name may be changed by user). //! build-script-build-$META //! # Hard link to build-script-build-$META. //! build-script-build //! # Dependency information generated by rustc. //! build-script-build-$META.d //! # Debug information, depending on platform and profile //! # settings. //! //! //! # The package shows up twice with two different metadata hashes. //! $pkgname-$META/ # For the output of the build script. //! # Timestamp when the build script was last executed. //! invoked.timestamp //! # Directory where script can output files ($OUT_DIR). //! out/ //! # Output from the build script. //! output //! # Path to `out`, used to help when the target directory is //! # moved. //! root-output //! # Stderr output from the build script. //! stderr //! //! # Output from rustdoc //! doc/ //! //! # Used by `cargo package` and `cargo publish` to build a `.crate` file. //! package/ //! //! # Experimental feature for generated build scripts. //! .metabuild/ //! ``` //! //! When cross-compiling, the layout is the same, except it appears in //! `target/$TRIPLE`. use crate::core::compiler::CompileTarget; use crate::core::Workspace; use crate::util::{CargoResult, FileLock}; use cargo_util::paths; use std::path::{Path, PathBuf}; /// Contains the paths of all target output locations. /// /// See module docs for more information. pub struct Layout { /// The root directory: `/path/to/target`. /// If cross compiling: `/path/to/target/$TRIPLE`. root: PathBuf, /// The final artifact destination: `$root/debug` (or `release`). dest: PathBuf, /// The directory with rustc artifacts: `$dest/deps` deps: PathBuf, /// The directory for build scripts: `$dest/build` build: PathBuf, /// The directory for artifacts, i.e. binaries, cdylibs, staticlibs: `$dest/deps/artifact` artifact: PathBuf, /// The directory for incremental files: `$dest/incremental` incremental: PathBuf, /// The directory for fingerprints: `$dest/.fingerprint` fingerprint: PathBuf, /// The directory for examples: `$dest/examples` examples: PathBuf, /// The directory for rustdoc output: `$root/doc` doc: PathBuf, /// The directory for temporary data of integration tests and benches: `$dest/tmp` tmp: PathBuf, /// The lockfile for a build (`.cargo-lock`). Will be unlocked when this /// struct is `drop`ped. _lock: FileLock, } impl Layout { /// Calculate the paths for build output, lock the build directory, and return as a Layout. /// /// This function will block if the directory is already locked. /// /// `dest` should be the final artifact directory name. Currently either /// "debug" or "release". pub fn new( ws: &Workspace<'_>, target: Option, dest: &str, ) -> CargoResult { let mut root = ws.target_dir(); if let Some(target) = target { root.push(target.short_name()); } let dest = root.join(dest); // If the root directory doesn't already exist go ahead and create it // here. Use this opportunity to exclude it from backups as well if the // system supports it since this is a freshly created folder. // paths::create_dir_all_excluded_from_backups_atomic(root.as_path_unlocked())?; // Now that the excluded from backups target root is created we can create the // actual destination (sub)subdirectory. paths::create_dir_all(dest.as_path_unlocked())?; // For now we don't do any more finer-grained locking on the artifact // directory, so just lock the entire thing for the duration of this // compile. let lock = dest.open_rw_exclusive_create(".cargo-lock", ws.gctx(), "build directory")?; let root = root.into_path_unlocked(); let dest = dest.into_path_unlocked(); let deps = dest.join("deps"); let artifact = deps.join("artifact"); Ok(Layout { deps, build: dest.join("build"), artifact, incremental: dest.join("incremental"), fingerprint: dest.join(".fingerprint"), examples: dest.join("examples"), doc: root.join("doc"), tmp: root.join("tmp"), root, dest, _lock: lock, }) } /// Makes sure all directories stored in the Layout exist on the filesystem. pub fn prepare(&mut self) -> CargoResult<()> { paths::create_dir_all(&self.deps)?; paths::create_dir_all(&self.incremental)?; paths::create_dir_all(&self.fingerprint)?; paths::create_dir_all(&self.examples)?; paths::create_dir_all(&self.build)?; Ok(()) } /// Fetch the destination path for final artifacts (`/…/target/debug`). pub fn dest(&self) -> &Path { &self.dest } /// Fetch the deps path. pub fn deps(&self) -> &Path { &self.deps } /// Fetch the examples path. pub fn examples(&self) -> &Path { &self.examples } /// Fetch the doc path. pub fn doc(&self) -> &Path { &self.doc } /// Fetch the root path (`/…/target`). pub fn root(&self) -> &Path { &self.root } /// Fetch the incremental path. pub fn incremental(&self) -> &Path { &self.incremental } /// Fetch the fingerprint path. pub fn fingerprint(&self) -> &Path { &self.fingerprint } /// Fetch the build script path. pub fn build(&self) -> &Path { &self.build } /// Fetch the artifact path. pub fn artifact(&self) -> &Path { &self.artifact } /// Create and return the tmp path. pub fn prepare_tmp(&self) -> CargoResult<&Path> { paths::create_dir_all(&self.tmp)?; Ok(&self.tmp) } } cargo-0.86.0/src/cargo/core/compiler/links.rs000064400000000000000000000047421046102023000171330ustar 00000000000000use super::unit_graph::UnitGraph; use crate::core::resolver::errors::describe_path; use crate::core::{PackageId, Resolve}; use crate::util::errors::CargoResult; use std::collections::{HashMap, HashSet}; /// Validates [`package.links`] field in the manifest file does not conflict /// between packages. /// /// NOTE: This is the *old* links validator. Links are usually validated in the /// resolver. However, the `links` field was added to the index in early 2018 /// (see [rust-lang/cargo#4978]). However, `links` has been around since 2014, /// so there are still many crates in the index that don't have `links` /// properly set in the index (over 600 at the time of this writing in 2019). /// This can probably be removed at some point in the future, though it might /// be worth considering fixing the index. /// /// [rust-lang/cargo#4978]: https://github.com/rust-lang/cargo/pull/4978 /// [`package.links`]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#the-links-manifest-key pub fn validate_links(resolve: &Resolve, unit_graph: &UnitGraph) -> CargoResult<()> { let mut validated: HashSet = HashSet::new(); let mut links: HashMap = HashMap::new(); let mut units: Vec<_> = unit_graph.keys().collect(); // Sort primarily to make testing easier. units.sort_unstable(); for unit in units { if !validated.insert(unit.pkg.package_id()) { continue; } let Some(lib) = unit.pkg.manifest().links() else { continue; }; if let Some(&prev) = links.get(lib) { let prev_path = resolve .path_to_top(&prev) .into_iter() .map(|(p, d)| (p, d.and_then(|d| d.iter().next()))); let pkg = unit.pkg.package_id(); let path = resolve .path_to_top(&pkg) .into_iter() .map(|(p, d)| (p, d.and_then(|d| d.iter().next()))); anyhow::bail!( "multiple packages link to native library `{}`, \ but a native library can be linked only once\n\ \n\ {}\nlinks to native library `{}`\n\ \n\ {}\nalso links to native library `{}`", lib, describe_path(prev_path), lib, describe_path(path), lib ) } links.insert(lib.to_string(), unit.pkg.package_id()); } Ok(()) } cargo-0.86.0/src/cargo/core/compiler/lto.rs000064400000000000000000000206731046102023000166120ustar 00000000000000use crate::core::compiler::{BuildContext, CompileMode, CrateType, Unit}; use crate::core::profiles; use crate::util::interning::InternedString; use crate::util::errors::CargoResult; use std::collections::hash_map::{Entry, HashMap}; /// Possible ways to run rustc and request various parts of [LTO]. /// /// Variant | Flag | Object Code | Bitcode /// -------------------|------------------------|-------------|-------- /// `Run` | `-C lto=foo` | n/a | n/a /// `Off` | `-C lto=off` | n/a | n/a /// `OnlyBitcode` | `-C linker-plugin-lto` | | βœ“ /// `ObjectAndBitcode` | | βœ“ | βœ“ /// `OnlyObject` | `-C embed-bitcode=no` | βœ“ | /// /// [LTO]: https://doc.rust-lang.org/nightly/cargo/reference/profiles.html#lto #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum Lto { /// LTO is run for this rustc, and it's `-Clto=foo`. If the given value is /// None, that corresponds to `-Clto` with no argument, which means do /// "fat" LTO. Run(Option), /// LTO has been explicitly listed as "off". This means no thin-local-LTO, /// no LTO anywhere, I really mean it! Off, /// This rustc invocation only needs to produce bitcode (it is *only* used /// for LTO), there's no need to produce object files, so we can pass /// `-Clinker-plugin-lto` OnlyBitcode, /// This rustc invocation needs to embed bitcode in object files. This means /// that object files may be used for a normal link, and the crate may be /// loaded for LTO later, so both are required. ObjectAndBitcode, /// This should not include bitcode. This is primarily to reduce disk /// space usage. OnlyObject, } pub fn generate(bcx: &BuildContext<'_, '_>) -> CargoResult> { let mut map = HashMap::new(); for unit in bcx.roots.iter() { let root_lto = match unit.profile.lto { // LTO not requested, no need for bitcode. profiles::Lto::Bool(false) => Lto::OnlyObject, profiles::Lto::Off => Lto::Off, _ => { let crate_types = unit.target.rustc_crate_types(); if unit.target.for_host() { Lto::OnlyObject } else if needs_object(&crate_types) { lto_when_needs_object(&crate_types) } else { // This may or may not participate in LTO, let's start // with the minimum requirements. This may be expanded in // `calculate` below if necessary. Lto::OnlyBitcode } } }; calculate(bcx, &mut map, unit, root_lto)?; } Ok(map) } /// Whether or not any of these crate types need object code. fn needs_object(crate_types: &[CrateType]) -> bool { crate_types.iter().any(|k| k.can_lto() || k.is_dynamic()) } /// Lto setting to use when this unit needs object code. fn lto_when_needs_object(crate_types: &[CrateType]) -> Lto { if crate_types.iter().all(|ct| *ct == CrateType::Dylib) { // A dylib whose parent is running LTO. rustc currently // doesn't support LTO with dylibs, so bitcode is not // needed. Lto::OnlyObject } else { // Mixed rlib with a dylib or cdylib whose parent is running LTO. This // needs both: bitcode for the rlib (for LTO) and object code for the // dylib. Lto::ObjectAndBitcode } } fn calculate( bcx: &BuildContext<'_, '_>, map: &mut HashMap, unit: &Unit, parent_lto: Lto, ) -> CargoResult<()> { let crate_types = match unit.mode { // Note: Doctest ignores LTO, but for now we'll compute it as-if it is // a Bin, in case it is ever supported in the future. CompileMode::Test | CompileMode::Bench | CompileMode::Doctest => vec![CrateType::Bin], // Notes on other modes: // - Check: Treat as the underlying type, it doesn't really matter. // - Doc: LTO is N/A for the Doc unit itself since rustdoc does not // support codegen flags. We still compute the dependencies, which // are mostly `Check`. // - RunCustomBuild is ignored because it is always "for_host". _ => unit.target.rustc_crate_types(), }; // LTO can only be performed if *all* of the crate types support it. // For example, a cdylib/rlib combination won't allow LTO. let all_lto_types = crate_types.iter().all(CrateType::can_lto); // Compute the LTO based on the profile, and what our parent requires. let lto = if unit.target.for_host() { // Disable LTO for host builds since we only really want to perform LTO // for the final binary, and LTO on plugins/build scripts/proc macros is // largely not desired. Lto::OnlyObject } else if all_lto_types { // Note that this ignores the `parent_lto` because this isn't a // linkable crate type; this unit is not being embedded in the parent. match unit.profile.lto { profiles::Lto::Named(s) => Lto::Run(Some(s)), profiles::Lto::Off => Lto::Off, profiles::Lto::Bool(true) => Lto::Run(None), profiles::Lto::Bool(false) => Lto::OnlyObject, } } else { match (parent_lto, needs_object(&crate_types)) { // An rlib whose parent is running LTO, we only need bitcode. (Lto::Run(_), false) => Lto::OnlyBitcode, // LTO when something needs object code. (Lto::Run(_), true) | (Lto::OnlyBitcode, true) => lto_when_needs_object(&crate_types), // LTO is disabled, continue to disable it. (Lto::Off, _) => Lto::Off, // If this doesn't have any requirements, or the requirements are // already satisfied, then stay with our parent. (_, false) | (Lto::OnlyObject, true) | (Lto::ObjectAndBitcode, true) => parent_lto, } }; // Merge the computed LTO. If this unit appears multiple times in the // graph, the merge may expand the requirements. let merged_lto = match map.entry(unit.clone()) { // If we haven't seen this unit before then insert our value and keep // going. Entry::Vacant(v) => *v.insert(lto), Entry::Occupied(mut v) => { let result = match (lto, v.get()) { // No change in requirements. (Lto::OnlyBitcode, Lto::OnlyBitcode) => Lto::OnlyBitcode, (Lto::OnlyObject, Lto::OnlyObject) => Lto::OnlyObject, // Once we're running LTO we keep running LTO. We should always // calculate the same thing here each iteration because if we // see this twice then it means, for example, two unit tests // depend on a binary, which is normal. (Lto::Run(s), _) | (_, &Lto::Run(s)) => Lto::Run(s), // Off means off! This has the same reasoning as `Lto::Run`. (Lto::Off, _) | (_, Lto::Off) => Lto::Off, // Once a target has requested both, that's the maximal amount // of work that can be done, so we just keep doing that work. (Lto::ObjectAndBitcode, _) | (_, Lto::ObjectAndBitcode) => Lto::ObjectAndBitcode, // Upgrade so that both requirements can be met. // // This is where the trickiness happens. This unit needs // bitcode and the previously calculated value for this unit // says it didn't need bitcode (or vice versa). This means that // we're a shared dependency between some targets which require // LTO and some which don't. This means that instead of being // either only-objects or only-bitcode we have to embed both in // rlibs (used for different compilations), so we switch to // including both. (Lto::OnlyObject, Lto::OnlyBitcode) | (Lto::OnlyBitcode, Lto::OnlyObject) => { Lto::ObjectAndBitcode } }; // No need to recurse if we calculated the same value as before. if result == *v.get() { return Ok(()); } v.insert(result); result } }; for dep in &bcx.unit_graph[unit] { calculate(bcx, map, &dep.unit, merged_lto)?; } Ok(()) } cargo-0.86.0/src/cargo/core/compiler/mod.rs000064400000000000000000002213521046102023000165700ustar 00000000000000//! # Interact with the compiler //! //! If you consider [`ops::cargo_compile::compile`] as a `rustc` driver but on //! Cargo side, this module is kinda the `rustc_interface` for that merits. //! It contains all the interaction between Cargo and the rustc compiler, //! from preparing the context for the entire build process, to scheduling //! and executing each unit of work (e.g. running `rustc`), to managing and //! caching the output artifact of a build. //! //! However, it hasn't yet exposed a clear definition of each phase or session, //! like what rustc has done[^1]. Also, no one knows if Cargo really needs that. //! To be pragmatic, here we list a handful of items you may want to learn: //! //! * [`BuildContext`] is a static context containing all information you need //! before a build gets started. //! * [`BuildRunner`] is the center of the world, coordinating a running build and //! collecting information from it. //! * [`custom_build`] is the home of build script executions and output parsing. //! * [`fingerprint`] not only defines but also executes a set of rules to //! determine if a re-compile is needed. //! * [`job_queue`] is where the parallelism, job scheduling, and communication //! machinery happen between Cargo and the compiler. //! * [`layout`] defines and manages output artifacts of a build in the filesystem. //! * [`unit_dependencies`] is for building a dependency graph for compilation //! from a result of dependency resolution. //! * [`Unit`] contains sufficient information to build something, usually //! turning into a compiler invocation in a later phase. //! //! [^1]: Maybe [`-Zbuild-plan`](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-plan) //! was designed to serve that purpose but still [in flux](https://github.com/rust-lang/cargo/issues/7614). //! //! [`ops::cargo_compile::compile`]: crate::ops::compile pub mod artifact; mod build_config; pub(crate) mod build_context; mod build_plan; pub(crate) mod build_runner; mod compilation; mod compile_kind; mod crate_type; mod custom_build; pub(crate) mod fingerprint; pub mod future_incompat; pub(crate) mod job_queue; pub(crate) mod layout; mod links; mod lto; mod output_depinfo; pub mod rustdoc; pub mod standard_lib; mod timings; mod unit; pub mod unit_dependencies; pub mod unit_graph; use std::borrow::Cow; use std::collections::{HashMap, HashSet}; use std::env; use std::ffi::{OsStr, OsString}; use std::fmt::Display; use std::fs::{self, File}; use std::io::{BufRead, Write}; use std::path::{Path, PathBuf}; use std::sync::Arc; use anyhow::{Context as _, Error}; use lazycell::LazyCell; use tracing::{debug, trace}; pub use self::build_config::{BuildConfig, CompileMode, MessageFormat, TimingOutput}; pub use self::build_context::{ BuildContext, FileFlavor, FileType, RustDocFingerprint, RustcTargetData, TargetInfo, }; use self::build_plan::BuildPlan; pub use self::build_runner::{BuildRunner, Metadata, UnitHash}; pub use self::compilation::{Compilation, Doctest, UnitOutput}; pub use self::compile_kind::{CompileKind, CompileTarget}; 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; use self::job_queue::{Job, JobQueue, JobState, Work}; pub(crate) use self::layout::Layout; pub use self::lto::Lto; use self::output_depinfo::output_depinfo; use self::unit_graph::UnitDep; use crate::core::compiler::future_incompat::FutureIncompatReport; pub use crate::core::compiler::unit::{Unit, UnitInterner}; use crate::core::manifest::TargetSourcePath; use crate::core::profiles::{PanicStrategy, Profile, StripInner}; use crate::core::{Feature, PackageId, Target, Verbosity}; use crate::util::context::WarningHandling; use crate::util::errors::{CargoResult, VerboseError}; use crate::util::interning::InternedString; use crate::util::machine_message::{self, Message}; use crate::util::{add_path_args, internal}; use cargo_util::{paths, ProcessBuilder, ProcessError}; use cargo_util_schemas::manifest::TomlDebugInfo; use cargo_util_schemas::manifest::TomlTrimPaths; use cargo_util_schemas::manifest::TomlTrimPathsValue; use rustfix::diagnostics::Applicability; const RUSTDOC_CRATE_VERSION_FLAG: &str = "--crate-version"; /// 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. pub trait Executor: Send + Sync + 'static { /// Called after a rustc process invocation is prepared up-front for a given /// unit of work (may still be modified for runtime-known dependencies, when /// the work is actually executed). fn init(&self, _build_runner: &BuildRunner<'_, '_>, _unit: &Unit) {} /// In case of an `Err`, Cargo will not continue with the build process for /// this package. fn exec( &self, cmd: &ProcessBuilder, id: PackageId, target: &Target, mode: CompileMode, on_stdout_line: &mut dyn FnMut(&str) -> CargoResult<()>, on_stderr_line: &mut dyn FnMut(&str) -> CargoResult<()>, ) -> CargoResult<()>; /// Queried when queuing each unit of work. If it returns true, then the /// unit will always be rebuilt, independent of whether it needs to be. fn force_rebuild(&self, _unit: &Unit) -> bool { false } } /// A `DefaultExecutor` calls rustc without doing anything else. It is Cargo's /// default behaviour. #[derive(Copy, Clone)] pub struct DefaultExecutor; impl Executor for DefaultExecutor { fn exec( &self, cmd: &ProcessBuilder, _id: PackageId, _target: &Target, _mode: CompileMode, on_stdout_line: &mut dyn FnMut(&str) -> CargoResult<()>, on_stderr_line: &mut dyn FnMut(&str) -> CargoResult<()>, ) -> CargoResult<()> { cmd.exec_with_streaming(on_stdout_line, on_stderr_line, false) .map(drop) } } /// Builds up and enqueue a list of pending jobs onto the `job` queue. /// /// Starting from the `unit`, this function recursively calls itself to build /// all jobs for dependencies of the `unit`. Each of these jobs represents /// compiling a particular package. /// /// Note that **no actual work is executed as part of this**, that's all done /// next as part of [`JobQueue::execute`] function which will run everything /// in order with proper parallelism. #[tracing::instrument(skip(build_runner, jobs, plan, exec))] fn compile<'gctx>( build_runner: &mut BuildRunner<'_, 'gctx>, jobs: &mut JobQueue<'gctx>, plan: &mut BuildPlan, unit: &Unit, exec: &Arc, force_rebuild: bool, ) -> CargoResult<()> { let bcx = build_runner.bcx; let build_plan = bcx.build_config.build_plan; if !build_runner.compiled.insert(unit.clone()) { return Ok(()); } // Build up the work to be done to compile this unit, enqueuing it once // we've got everything constructed. fingerprint::prepare_init(build_runner, unit)?; let job = if unit.mode.is_run_custom_build() { custom_build::prepare(build_runner, unit)? } else if unit.mode.is_doc_test() { // We run these targets later, so this is just a no-op for now. Job::new_fresh() } else if build_plan { Job::new_dirty( rustc(build_runner, unit, &exec.clone())?, DirtyReason::FreshBuild, ) } else { let force = exec.force_rebuild(unit) || force_rebuild; let mut job = fingerprint::prepare_target(build_runner, unit, force)?; job.before(if job.freshness().is_dirty() { let work = if unit.mode.is_doc() || unit.mode.is_doc_scrape() { rustdoc(build_runner, unit)? } else { rustc(build_runner, unit, exec)? }; work.then(link_targets(build_runner, unit, false)?) } else { // We always replay the output cache, // since it might contain future-incompat-report messages let show_diagnostics = unit.show_warnings(bcx.gctx) && build_runner.bcx.gctx.warning_handling()? != WarningHandling::Allow; let work = replay_output_cache( unit.pkg.package_id(), PathBuf::from(unit.pkg.manifest_path()), &unit.target, build_runner.files().message_cache_path(unit), build_runner.bcx.build_config.message_format, show_diagnostics, ); // Need to link targets on both the dirty and fresh. work.then(link_targets(build_runner, unit, true)?) }); job }; jobs.enqueue(build_runner, unit, job)?; // Be sure to compile all dependencies of this target as well. let deps = Vec::from(build_runner.unit_deps(unit)); // Create vec due to mutable borrow. for dep in deps { compile(build_runner, jobs, plan, &dep.unit, exec, false)?; } if build_plan { plan.add(build_runner, unit)?; } Ok(()) } /// Generates the warning message used when fallible doc-scrape units fail, /// either for rustdoc or rustc. fn make_failed_scrape_diagnostic( build_runner: &BuildRunner<'_, '_>, unit: &Unit, top_line: impl Display, ) -> String { let manifest_path = unit.pkg.manifest_path(); let relative_manifest_path = manifest_path .strip_prefix(build_runner.bcx.ws.root()) .unwrap_or(&manifest_path); format!( "\ {top_line} Try running with `--verbose` to see the error message. If an example should not be scanned, then consider adding `doc-scrape-examples = false` to its `[[example]]` definition in {}", relative_manifest_path.display() ) } /// Creates a unit of work invoking `rustc` for building the `unit`. fn rustc( build_runner: &mut BuildRunner<'_, '_>, unit: &Unit, exec: &Arc, ) -> CargoResult { let mut rustc = prepare_rustc(build_runner, unit)?; let build_plan = build_runner.bcx.build_config.build_plan; let name = unit.pkg.name(); let buildkey = unit.buildkey(); let outputs = build_runner.outputs(unit)?; let root = build_runner.files().out_dir(unit); // Prepare the native lib state (extra `-L` and `-l` flags). let build_script_outputs = Arc::clone(&build_runner.build_script_outputs); let current_id = unit.pkg.package_id(); let manifest_path = PathBuf::from(unit.pkg.manifest_path()); let build_scripts = build_runner.build_scripts.get(unit).cloned(); // If we are a binary and the package also contains a library, then we // don't pass the `-l` flags. let pass_l_flag = unit.target.is_lib() || !unit.pkg.targets().iter().any(|t| t.is_lib()); let dep_info_name = if let Some(c_extra_filename) = build_runner.files().metadata(unit).c_extra_filename() { format!("{}-{}.d", unit.target.crate_name(), c_extra_filename) } else { format!("{}.d", unit.target.crate_name()) }; let rustc_dep_info_loc = root.join(dep_info_name); let dep_info_loc = fingerprint::dep_info_loc(build_runner, unit); let mut output_options = OutputOptions::new(build_runner, unit); let package_id = unit.pkg.package_id(); let target = Target::clone(&unit.target); let mode = unit.mode; exec.init(build_runner, unit); let exec = exec.clone(); let root_output = build_runner.files().host_dest().to_path_buf(); let target_dir = build_runner.bcx.ws.target_dir().into_path_unlocked(); let pkg_root = unit.pkg.root().to_path_buf(); let cwd = rustc .get_cwd() .unwrap_or_else(|| build_runner.bcx.gctx.cwd()) .to_path_buf(); let fingerprint_dir = build_runner.files().fingerprint_dir(unit); let script_metadata = build_runner.find_build_script_metadata(unit); let is_local = unit.is_local(); let artifact = unit.artifact; let hide_diagnostics_for_scrape_unit = build_runner.bcx.unit_can_fail_for_docscraping(unit) && !matches!( build_runner.bcx.gctx.shell().verbosity(), Verbosity::Verbose ); let failed_scrape_diagnostic = hide_diagnostics_for_scrape_unit.then(|| { // If this unit is needed for doc-scraping, then we generate a diagnostic that // describes the set of reverse-dependencies that cause the unit to be needed. let target_desc = unit.target.description_named(); let mut for_scrape_units = build_runner .bcx .scrape_units_have_dep_on(unit) .into_iter() .map(|unit| unit.target.description_named()) .collect::>(); for_scrape_units.sort(); let for_scrape_units = for_scrape_units.join(", "); make_failed_scrape_diagnostic(build_runner, unit, format_args!("failed to check {target_desc} in package `{name}` as a prerequisite for scraping examples from: {for_scrape_units}")) }); if hide_diagnostics_for_scrape_unit { output_options.show_diagnostics = false; } let env_config = Arc::clone(build_runner.bcx.gctx.env_config()?); return Ok(Work::new(move |state| { // Artifacts are in a different location than typical units, // hence we must assure the crate- and target-dependent // directory is present. if artifact.is_true() { paths::create_dir_all(&root)?; } // Only at runtime have we discovered what the extra -L and -l // arguments are for native libraries, so we process those here. We // also need to be sure to add any -L paths for our plugins to the // dynamic library load path as a plugin's dynamic library may be // located somewhere in there. // Finally, if custom environment variables have been produced by // previous build scripts, we include them in the rustc invocation. if let Some(build_scripts) = build_scripts { let script_outputs = build_script_outputs.lock().unwrap(); if !build_plan { add_native_deps( &mut rustc, &script_outputs, &build_scripts, pass_l_flag, &target, current_id, )?; add_plugin_deps(&mut rustc, &script_outputs, &build_scripts, &root_output)?; } add_custom_flags(&mut rustc, &script_outputs, script_metadata)?; } for output in outputs.iter() { // If there is both an rmeta and rlib, rustc will prefer to use the // rlib, even if it is older. Therefore, we must delete the rlib to // force using the new rmeta. if output.path.extension() == Some(OsStr::new("rmeta")) { let dst = root.join(&output.path).with_extension("rlib"); if dst.exists() { paths::remove_file(&dst)?; } } // Some linkers do not remove the executable, but truncate and modify it. // That results in the old hard-link being modified even after renamed. // We delete the old artifact here to prevent this behavior from confusing users. // See rust-lang/cargo#8348. if output.hardlink.is_some() && output.path.exists() { _ = paths::remove_file(&output.path).map_err(|e| { tracing::debug!( "failed to delete previous output file `{:?}`: {e:?}", output.path ); }); } } state.running(&rustc); let timestamp = paths::set_invocation_time(&fingerprint_dir)?; if build_plan { state.build_plan(buildkey, rustc.clone(), outputs.clone()); } else { let result = exec .exec( &rustc, package_id, &target, mode, &mut |line| on_stdout_line(state, line, package_id, &target), &mut |line| { on_stderr_line( state, line, package_id, &manifest_path, &target, &mut output_options, ) }, ) .map_err(|e| { if output_options.errors_seen == 0 { // If we didn't expect an error, do not require --verbose to fail. // This is intended to debug // https://github.com/rust-lang/crater/issues/733, where we are seeing // Cargo exit unsuccessfully while seeming to not show any errors. e } else { verbose_if_simple_exit_code(e) } }) .with_context(|| { // adapted from rustc_errors/src/lib.rs let warnings = match output_options.warnings_seen { 0 => String::new(), 1 => "; 1 warning emitted".to_string(), count => format!("; {} warnings emitted", count), }; let errors = match output_options.errors_seen { 0 => String::new(), 1 => " due to 1 previous error".to_string(), count => format!(" due to {} previous errors", count), }; let name = descriptive_pkg_name(&name, &target, &mode); format!("could not compile {name}{errors}{warnings}") }); if let Err(e) = result { if let Some(diagnostic) = failed_scrape_diagnostic { state.warning(diagnostic)?; } return Err(e); } // Exec should never return with success *and* generate an error. debug_assert_eq!(output_options.errors_seen, 0); } if rustc_dep_info_loc.exists() { fingerprint::translate_dep_info( &rustc_dep_info_loc, &dep_info_loc, &cwd, &pkg_root, &target_dir, &rustc, // Do not track source files in the fingerprint for registry dependencies. is_local, &env_config, ) .with_context(|| { internal(format!( "could not parse/generate dep info at: {}", rustc_dep_info_loc.display() )) })?; // This mtime shift allows Cargo to detect if a source file was // modified in the middle of the build. paths::set_file_time_no_err(dep_info_loc, timestamp); } Ok(()) })); // Add all relevant `-L` and `-l` flags from dependencies (now calculated and // present in `state`) to the command provided. fn add_native_deps( rustc: &mut ProcessBuilder, build_script_outputs: &BuildScriptOutputs, build_scripts: &BuildScripts, pass_l_flag: bool, target: &Target, current_id: PackageId, ) -> CargoResult<()> { for key in build_scripts.to_link.iter() { let output = build_script_outputs.get(key.1).ok_or_else(|| { internal(format!( "couldn't find build script output for {}/{}", key.0, key.1 )) })?; for path in output.library_paths.iter() { rustc.arg("-L").arg(path); } if key.0 == current_id { if pass_l_flag { for name in output.library_links.iter() { rustc.arg("-l").arg(name); } } } for (lt, arg) in &output.linker_args { // There was an unintentional change where cdylibs were // allowed to be passed via transitive dependencies. This // clause should have been kept in the `if` block above. For // now, continue allowing it for cdylib only. // See https://github.com/rust-lang/cargo/issues/9562 if lt.applies_to(target) && (key.0 == current_id || *lt == LinkArgTarget::Cdylib) { rustc.arg("-C").arg(format!("link-arg={}", arg)); } } } Ok(()) } } fn verbose_if_simple_exit_code(err: Error) -> Error { // If a signal on unix (`code == None`) or an abnormal termination // on Windows (codes like `0xC0000409`), don't hide the error details. match err .downcast_ref::() .as_ref() .and_then(|perr| perr.code) { Some(n) if cargo_util::is_simple_exit_code(n) => VerboseError::new(err).into(), _ => err, } } /// Link the compiled target (often of form `foo-{metadata_hash}`) to the /// final target. This must happen during both "Fresh" and "Compile". fn link_targets( build_runner: &mut BuildRunner<'_, '_>, unit: &Unit, fresh: bool, ) -> CargoResult { let bcx = build_runner.bcx; let outputs = build_runner.outputs(unit)?; let export_dir = build_runner.files().export_dir(); let package_id = unit.pkg.package_id(); let manifest_path = PathBuf::from(unit.pkg.manifest_path()); let profile = unit.profile.clone(); let unit_mode = unit.mode; let features = unit.features.iter().map(|s| s.to_string()).collect(); let json_messages = bcx.build_config.emit_json(); let executable = build_runner.get_executable(unit)?; let mut target = Target::clone(&unit.target); if let TargetSourcePath::Metabuild = target.src_path() { // Give it something to serialize. let path = unit .pkg .manifest() .metabuild_path(build_runner.bcx.ws.target_dir()); target.set_src_path(TargetSourcePath::Path(path)); } Ok(Work::new(move |state| { // If we're a "root crate", e.g., the target of this compilation, then we // hard link our outputs out of the `deps` directory into the directory // above. This means that `cargo build` will produce binaries in // `target/debug` which one probably expects. let mut destinations = vec![]; for output in outputs.iter() { let src = &output.path; // This may have been a `cargo rustc` command which changes the // output, so the source may not actually exist. if !src.exists() { continue; } let Some(dst) = output.hardlink.as_ref() else { destinations.push(src.clone()); continue; }; destinations.push(dst.clone()); paths::link_or_copy(src, dst)?; if let Some(ref path) = output.export_path { let export_dir = export_dir.as_ref().unwrap(); paths::create_dir_all(export_dir)?; paths::link_or_copy(src, path)?; } } if json_messages { 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), TomlDebugInfo::LineDirectivesOnly => { machine_message::ArtifactDebuginfo::Named("line-directives-only") } TomlDebugInfo::LineTablesOnly => { machine_message::ArtifactDebuginfo::Named("line-tables-only") } }; let art_profile = machine_message::ArtifactProfile { opt_level: profile.opt_level.as_str(), debuginfo: Some(debuginfo), debug_assertions: profile.debug_assertions, overflow_checks: profile.overflow_checks, test: unit_mode.is_any_test(), }; let msg = machine_message::Artifact { package_id: package_id.to_spec(), manifest_path, target: &target, profile: art_profile, features, filenames: destinations, executable, fresh, } .to_json_string(); state.stdout(msg)?; } Ok(()) })) } // For all plugin dependencies, add their -L paths (now calculated and present // in `build_script_outputs`) to the dynamic library load path for the command // to execute. fn add_plugin_deps( rustc: &mut ProcessBuilder, build_script_outputs: &BuildScriptOutputs, build_scripts: &BuildScripts, root_output: &Path, ) -> CargoResult<()> { let var = paths::dylib_path_envvar(); let search_path = rustc.get_env(var).unwrap_or_default(); let mut search_path = env::split_paths(&search_path).collect::>(); for (pkg_id, metadata) in &build_scripts.plugins { let output = build_script_outputs .get(*metadata) .ok_or_else(|| internal(format!("couldn't find libs for plugin dep {}", pkg_id)))?; search_path.append(&mut filter_dynamic_search_path( output.library_paths.iter(), root_output, )); } let search_path = paths::join_paths(&search_path, var)?; rustc.env(var, &search_path); Ok(()) } // Determine paths to add to the dynamic search path from -L entries // // Strip off prefixes like "native=" or "framework=" and filter out directories // **not** inside our output directory since they are likely spurious and can cause // clashes with system shared libraries (issue #3366). fn filter_dynamic_search_path<'a, I>(paths: I, root_output: &Path) -> Vec where I: Iterator, { let mut search_path = vec![]; for dir in paths { let dir = match dir.to_str().and_then(|s| s.split_once("=")) { Some(("native" | "crate" | "dependency" | "framework" | "all", path)) => path.into(), _ => dir.clone(), }; if dir.starts_with(&root_output) { search_path.push(dir); } else { debug!( "Not including path {} in runtime library search path because it is \ outside target root {}", dir.display(), root_output.display() ); } } search_path } /// 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(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult { let is_primary = build_runner.is_primary_package(unit); let is_workspace = build_runner.bcx.ws.is_member(&unit.pkg); let mut base = build_runner .compilation .rustc_process(unit, is_primary, is_workspace)?; build_base_args(build_runner, &mut base, unit)?; base.inherit_jobserver(&build_runner.jobserver); build_deps_args(&mut base, build_runner, unit)?; add_cap_lints(build_runner.bcx, unit, &mut base); if let Some(args) = build_runner.bcx.extra_args_for(unit) { base.args(args); } base.args(&unit.rustflags); if build_runner.bcx.gctx.cli_unstable().binary_dep_depinfo { base.arg("-Z").arg("binary-dep-depinfo"); } if build_runner.bcx.gctx.cli_unstable().checksum_freshness { base.arg("-Z").arg("checksum-hash-algorithm=blake3"); } if is_primary { base.env("CARGO_PRIMARY_PACKAGE", "1"); } if unit.target.is_test() || unit.target.is_bench() { let tmp = build_runner.files().layout(unit.kind).prepare_tmp()?; base.env("CARGO_TARGET_TMPDIR", tmp.display().to_string()); } Ok(base) } /// 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(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult { let bcx = build_runner.bcx; // script_metadata is not needed here, it is only for tests. let mut rustdoc = build_runner.compilation.rustdoc_process(unit, None)?; rustdoc.inherit_jobserver(&build_runner.jobserver); let crate_name = unit.target.crate_name(); rustdoc.arg("--crate-name").arg(&crate_name); add_path_args(bcx.ws, unit, &mut rustdoc); add_cap_lints(bcx, unit, &mut rustdoc); if let CompileKind::Target(target) = unit.kind { rustdoc.arg("--target").arg(target.rustc_target()); } let doc_dir = build_runner.files().out_dir(unit); rustdoc.arg("-o").arg(&doc_dir); rustdoc.args(&features_args(unit)); rustdoc.args(&check_cfg_args(unit)); add_error_format_and_color(build_runner, &mut rustdoc); add_allow_features(build_runner, &mut rustdoc); if let Some(trim_paths) = unit.profile.trim_paths.as_ref() { trim_paths_args_rustdoc(&mut rustdoc, build_runner, unit, trim_paths)?; } rustdoc.args(unit.pkg.manifest().lint_rustflags()); let metadata = build_runner.metadata_for_doc_units[unit]; rustdoc .arg("-C") .arg(format!("metadata={}", metadata.c_metadata())); if unit.mode.is_doc_scrape() { debug_assert!(build_runner.bcx.scrape_units.contains(unit)); if unit.target.is_test() { rustdoc.arg("--scrape-tests"); } rustdoc.arg("-Zunstable-options"); rustdoc .arg("--scrape-examples-output-path") .arg(scrape_output_path(build_runner, unit)?); // Only scrape example for items from crates in the workspace, to reduce generated file size for pkg in build_runner.bcx.packages.packages() { let names = pkg .targets() .iter() .map(|target| target.crate_name()) .collect::>(); for name in names { rustdoc.arg("--scrape-examples-target-crate").arg(name); } } } if should_include_scrape_units(build_runner.bcx, unit) { rustdoc.arg("-Zunstable-options"); } build_deps_args(&mut rustdoc, build_runner, unit)?; rustdoc::add_root_urls(build_runner, unit, &mut rustdoc)?; rustdoc::add_output_format(build_runner, unit, &mut rustdoc)?; if let Some(args) = build_runner.bcx.extra_args_for(unit) { rustdoc.args(args); } rustdoc.args(&unit.rustdocflags); if !crate_version_flag_already_present(&rustdoc) { append_crate_version_flag(unit, &mut rustdoc); } Ok(rustdoc) } /// Creates a unit of work invoking `rustdoc` for documenting the `unit`. fn rustdoc(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult { let mut rustdoc = prepare_rustdoc(build_runner, unit)?; let crate_name = unit.target.crate_name(); let doc_dir = build_runner.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(); let build_script_outputs = Arc::clone(&build_runner.build_script_outputs); let package_id = unit.pkg.package_id(); let manifest_path = PathBuf::from(unit.pkg.manifest_path()); let target = Target::clone(&unit.target); let mut output_options = OutputOptions::new(build_runner, unit); let script_metadata = build_runner.find_build_script_metadata(unit); let scrape_outputs = if should_include_scrape_units(build_runner.bcx, unit) { Some( build_runner .bcx .scrape_units .iter() .map(|unit| { Ok(( build_runner.files().metadata(unit).unit_id(), scrape_output_path(build_runner, unit)?, )) }) .collect::>>()?, ) } else { None }; let failed_scrape_units = Arc::clone(&build_runner.failed_scrape_units); let hide_diagnostics_for_scrape_unit = build_runner.bcx.unit_can_fail_for_docscraping(unit) && !matches!( build_runner.bcx.gctx.shell().verbosity(), Verbosity::Verbose ); let failed_scrape_diagnostic = hide_diagnostics_for_scrape_unit.then(|| { make_failed_scrape_diagnostic( build_runner, unit, format_args!("failed to scan {target_desc} in package `{name}` for example code usage"), ) }); if hide_diagnostics_for_scrape_unit { output_options.show_diagnostics = false; } Ok(Work::new(move |state| { add_custom_flags( &mut rustdoc, &build_script_outputs.lock().unwrap(), script_metadata, )?; // Add the output of scraped examples to the rustdoc command. // This action must happen after the unit's dependencies have finished, // because some of those deps may be Docscrape units which have failed. // So we dynamically determine which `--with-examples` flags to pass here. if let Some(scrape_outputs) = scrape_outputs { let failed_scrape_units = failed_scrape_units.lock().unwrap(); for (metadata, output_path) in &scrape_outputs { if !failed_scrape_units.contains(metadata) { rustdoc.arg("--with-examples").arg(output_path); } } } let crate_dir = doc_dir.join(&crate_name); if crate_dir.exists() { // Remove output from a previous build. This ensures that stale // files for removed items are removed. debug!("removing pre-existing doc directory {:?}", crate_dir); paths::remove_dir_all(crate_dir)?; } state.running(&rustdoc); let result = rustdoc .exec_with_streaming( &mut |line| on_stdout_line(state, line, package_id, &target), &mut |line| { on_stderr_line( state, line, package_id, &manifest_path, &target, &mut output_options, ) }, false, ) .map_err(verbose_if_simple_exit_code) .with_context(|| format!("could not document `{}`", name)); if let Err(e) = result { if let Some(diagnostic) = failed_scrape_diagnostic { state.warning(diagnostic)?; } return Err(e); } Ok(()) })) } // The --crate-version flag could have already been passed in RUSTDOCFLAGS // or as an extra compiler argument for rustdoc fn crate_version_flag_already_present(rustdoc: &ProcessBuilder) -> bool { rustdoc.get_args().any(|flag| { flag.to_str() .map_or(false, |flag| flag.starts_with(RUSTDOC_CRATE_VERSION_FLAG)) }) } fn append_crate_version_flag(unit: &Unit, rustdoc: &mut ProcessBuilder) { rustdoc .arg(RUSTDOC_CRATE_VERSION_FLAG) .arg(unit.pkg.version().to_string()); } /// Adds [`--cap-lints`] to the command to execute. /// /// [`--cap-lints`]: https://doc.rust-lang.org/nightly/rustc/lints/levels.html#capping-lints fn add_cap_lints(bcx: &BuildContext<'_, '_>, unit: &Unit, cmd: &mut ProcessBuilder) { // If this is an upstream dep we don't want warnings from, turn off all // lints. if !unit.show_warnings(bcx.gctx) { cmd.arg("--cap-lints").arg("allow"); // If this is an upstream dep but we *do* want warnings, make sure that they // don't fail compilation. } else if !unit.is_local() { cmd.arg("--cap-lints").arg("warn"); } } /// Forwards [`-Zallow-features`] if it is set for cargo. /// /// [`-Zallow-features`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#allow-features fn add_allow_features(build_runner: &BuildRunner<'_, '_>, cmd: &mut ProcessBuilder) { if let Some(allow) = &build_runner.bcx.gctx.cli_unstable().allow_features { use std::fmt::Write; let mut arg = String::from("-Zallow-features="); for f in allow { let _ = write!(&mut arg, "{f},"); } cmd.arg(arg.trim_end_matches(',')); } } /// Adds [`--error-format`] to the command to execute. /// /// Cargo always uses JSON output. This has several benefits, such as being /// easier to parse, handles changing formats (for replaying cached messages), /// ensures atomic output (so messages aren't interleaved), allows for /// intercepting messages like rmeta artifacts, etc. rustc includes a /// "rendered" field in the JSON message with the message properly formatted, /// which Cargo will extract and display to the user. /// /// [`--error-format`]: https://doc.rust-lang.org/nightly/rustc/command-line-arguments.html#--error-format-control-how-errors-are-produced fn add_error_format_and_color(build_runner: &BuildRunner<'_, '_>, cmd: &mut ProcessBuilder) { cmd.arg("--error-format=json"); let mut json = String::from("--json=diagnostic-rendered-ansi,artifacts,future-incompat"); match build_runner.bcx.build_config.message_format { MessageFormat::Short | MessageFormat::Json { short: true, .. } => { json.push_str(",diagnostic-short"); } _ => {} } cmd.arg(json); let gctx = build_runner.bcx.gctx; if let Some(width) = gctx.shell().err_width().diagnostic_terminal_width() { cmd.arg(format!("--diagnostic-width={width}")); } } /// Adds essential rustc flags and environment variables to the command to execute. fn build_base_args( build_runner: &BuildRunner<'_, '_>, cmd: &mut ProcessBuilder, unit: &Unit, ) -> CargoResult<()> { assert!(!unit.mode.is_run_custom_build()); let bcx = build_runner.bcx; let Profile { ref opt_level, codegen_backend, codegen_units, debuginfo, debug_assertions, split_debuginfo, overflow_checks, rpath, ref panic, incremental, strip, rustflags: profile_rustflags, trim_paths, .. } = unit.profile.clone(); let test = unit.mode.is_any_test(); cmd.arg("--crate-name").arg(&unit.target.crate_name()); let edition = unit.target.edition(); edition.cmd_edition_arg(cmd); add_path_args(bcx.ws, unit, cmd); add_error_format_and_color(build_runner, cmd); add_allow_features(build_runner, cmd); let mut contains_dy_lib = false; if !test { 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; } } if unit.mode.is_check() { cmd.arg("--emit=dep-info,metadata"); } else if !unit.requires_upstream_objects() { // Always produce metadata files for rlib outputs. Metadata may be used // in this session for a pipelined compilation, or it may be used in a // future Cargo session as part of a pipelined compile. cmd.arg("--emit=dep-info,metadata,link"); } else { cmd.arg("--emit=dep-info,link"); } let prefer_dynamic = (unit.target.for_host() && !unit.target.is_custom_build()) || (contains_dy_lib && !build_runner.is_primary_package(unit)); if prefer_dynamic { cmd.arg("-C").arg("prefer-dynamic"); } if opt_level.as_str() != "0" { cmd.arg("-C").arg(&format!("opt-level={}", opt_level)); } if *panic != PanicStrategy::Unwind { cmd.arg("-C").arg(format!("panic={}", panic)); } cmd.args(<o_args(build_runner, unit)); if let Some(backend) = codegen_backend { cmd.arg("-Z").arg(&format!("codegen-backend={}", backend)); } if let Some(n) = codegen_units { cmd.arg("-C").arg(&format!("codegen-units={}", n)); } 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 build_runner .bcx .target_data .info(unit.kind) .supports_debuginfo_split(split) { cmd.arg("-C").arg(format!("split-debuginfo={split}")); } } } if let Some(trim_paths) = trim_paths { trim_paths_args(cmd, build_runner, unit, &trim_paths)?; } cmd.args(unit.pkg.manifest().lint_rustflags()); cmd.args(&profile_rustflags); // `-C overflow-checks` is implied by the setting of `-C debug-assertions`, // so we only need to provide `-C overflow-checks` if it differs from // the value of `-C debug-assertions` we would provide. if opt_level.as_str() != "0" { if debug_assertions { cmd.args(&["-C", "debug-assertions=on"]); if !overflow_checks { cmd.args(&["-C", "overflow-checks=off"]); } } else if overflow_checks { cmd.args(&["-C", "overflow-checks=on"]); } } else if !debug_assertions { cmd.args(&["-C", "debug-assertions=off"]); if overflow_checks { cmd.args(&["-C", "overflow-checks=on"]); } } else if !overflow_checks { cmd.args(&["-C", "overflow-checks=off"]); } if test && unit.target.harness() { cmd.arg("--test"); // Cargo has historically never compiled `--test` binaries with // `panic=abort` because the `test` crate itself didn't support it. // Support is now upstream, however, but requires an unstable flag to be // passed when compiling the test. We require, in Cargo, an unstable // flag to pass to rustc, so register that here. Eventually this flag // will simply not be needed when the behavior is stabilized in the Rust // compiler itself. if *panic == PanicStrategy::Abort { cmd.arg("-Z").arg("panic-abort-tests"); } } else if test { cmd.arg("--cfg").arg("test"); } cmd.args(&features_args(unit)); cmd.args(&check_cfg_args(unit)); let meta = build_runner.files().metadata(unit); cmd.arg("-C") .arg(&format!("metadata={}", meta.c_metadata())); if let Some(c_extra_filename) = meta.c_extra_filename() { cmd.arg("-C") .arg(&format!("extra-filename=-{c_extra_filename}")); } if rpath { cmd.arg("-C").arg("rpath"); } cmd.arg("--out-dir") .arg(&build_runner.files().out_dir(unit)); fn opt(cmd: &mut ProcessBuilder, key: &str, prefix: &str, val: Option<&OsStr>) { if let Some(val) = val { let mut joined = OsString::from(prefix); joined.push(val); cmd.arg(key).arg(joined); } } if let CompileKind::Target(n) = unit.kind { cmd.arg("--target").arg(n.rustc_target()); } opt( cmd, "-C", "linker=", build_runner .compilation .target_linker(unit.kind) .as_ref() .map(|s| s.as_ref()), ); if incremental { let dir = build_runner .files() .layout(unit.kind) .incremental() .as_os_str(); opt(cmd, "-C", "incremental=", Some(dir)); } let strip = strip.into_inner(); if strip != StripInner::None { cmd.arg("-C").arg(format!("strip={}", strip)); } if unit.is_std { // -Zforce-unstable-if-unmarked prevents the accidental use of // unstable crates within the sysroot (such as "extern crate libc" or // any non-public crate in the sysroot). // // RUSTC_BOOTSTRAP allows unstable features on stable. cmd.arg("-Z") .arg("force-unstable-if-unmarked") .env("RUSTC_BOOTSTRAP", "1"); } // Add `CARGO_BIN_EXE_` environment variables for building tests. if unit.target.is_test() || unit.target.is_bench() { for bin_target in unit .pkg .manifest() .targets() .iter() .filter(|target| target.is_bin()) { let exe_path = build_runner.files().bin_link_for_target( bin_target, unit.kind, build_runner.bcx, )?; let name = bin_target .binary_filename() .unwrap_or(bin_target.name().to_string()); let key = format!("CARGO_BIN_EXE_{}", name); cmd.env(&key, exe_path); } } Ok(()) } /// All active features for the unit passed as `--cfg features=`. fn features_args(unit: &Unit) -> Vec { let mut args = Vec::with_capacity(unit.features.len() * 2); for feat in &unit.features { args.push(OsString::from("--cfg")); args.push(OsString::from(format!("feature=\"{}\"", feat))); } args } /// Like [`trim_paths_args`] but for rustdoc invocations. fn trim_paths_args_rustdoc( cmd: &mut ProcessBuilder, build_runner: &BuildRunner<'_, '_>, unit: &Unit, trim_paths: &TomlTrimPaths, ) -> CargoResult<()> { match trim_paths { // rustdoc supports diagnostics trimming only. TomlTrimPaths::Values(values) if !values.contains(&TomlTrimPathsValue::Diagnostics) => { return Ok(()) } _ => {} } // feature gate was checked during manifest/config parsing. cmd.arg("-Zunstable-options"); // Order of `--remap-path-prefix` flags is important for `-Zbuild-std`. // We want to show `/rustc//library/std` instead of `std-0.0.0`. cmd.arg(package_remap(build_runner, unit)); cmd.arg(sysroot_remap(build_runner, unit)); Ok(()) } /// Generates the `--remap-path-scope` and `--remap-path-prefix` for [RFC 3127]. /// See also unstable feature [`-Ztrim-paths`]. /// /// [RFC 3127]: https://rust-lang.github.io/rfcs/3127-trim-paths.html /// [`-Ztrim-paths`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#profile-trim-paths-option fn trim_paths_args( cmd: &mut ProcessBuilder, build_runner: &BuildRunner<'_, '_>, unit: &Unit, trim_paths: &TomlTrimPaths, ) -> CargoResult<()> { if trim_paths.is_none() { return Ok(()); } // feature gate was checked during manifest/config parsing. cmd.arg("-Zunstable-options"); cmd.arg(format!("-Zremap-path-scope={trim_paths}")); // Order of `--remap-path-prefix` flags is important for `-Zbuild-std`. // We want to show `/rustc//library/std` instead of `std-0.0.0`. cmd.arg(package_remap(build_runner, unit)); cmd.arg(sysroot_remap(build_runner, unit)); Ok(()) } /// Path prefix remap rules for sysroot. /// /// This remap logic aligns with rustc: /// fn sysroot_remap(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> OsString { let mut remap = OsString::from("--remap-path-prefix="); remap.push({ // See also `detect_sysroot_src_path()`. let mut sysroot = build_runner.bcx.target_data.info(unit.kind).sysroot.clone(); sysroot.push("lib"); sysroot.push("rustlib"); sysroot.push("src"); sysroot.push("rust"); sysroot }); remap.push("="); remap.push("/rustc/"); if let Some(commit_hash) = build_runner.bcx.rustc().commit_hash.as_ref() { remap.push(commit_hash); } else { remap.push(build_runner.bcx.rustc().version.to_string()); } remap } /// Path prefix remap rules for dependencies. /// /// * Git dependencies: remove `~/.cargo/git/checkouts` prefix. /// * Registry dependencies: remove `~/.cargo/registry/src` prefix. /// * Others (e.g. path dependencies): /// * relative paths to workspace root if inside the workspace directory. /// * otherwise remapped to `-`. fn package_remap(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> OsString { let pkg_root = unit.pkg.root(); let ws_root = build_runner.bcx.ws.root(); let mut remap = OsString::from("--remap-path-prefix="); let source_id = unit.pkg.package_id().source_id(); if source_id.is_git() { remap.push( build_runner .bcx .gctx .git_checkouts_path() .as_path_unlocked(), ); remap.push("="); } else if source_id.is_registry() { remap.push( build_runner .bcx .gctx .registry_source_path() .as_path_unlocked(), ); remap.push("="); } else if pkg_root.strip_prefix(ws_root).is_ok() { remap.push(ws_root); remap.push("=."); // remap to relative rustc work dir explicitly } else { remap.push(pkg_root); remap.push("="); remap.push(unit.pkg.name()); remap.push("-"); remap.push(unit.pkg.version().to_string()); } remap } /// Generates the `--check-cfg` arguments for the `unit`. fn check_cfg_args(unit: &Unit) -> Vec { // The routine below generates the --check-cfg arguments. Our goals here are to // enable the checking of conditionals and pass the list of declared features. // // In the simplified case, it would resemble something like this: // // --check-cfg=cfg() --check-cfg=cfg(feature, values(...)) // // but having `cfg()` is redundant with the second argument (as well-known names // and values are implicitly enabled when one or more `--check-cfg` argument is // passed) so we don't emit it and just pass: // // --check-cfg=cfg(feature, values(...)) // // This way, even if there are no declared features, the config `feature` will // still be expected, meaning users would get "unexpected value" instead of name. // This wasn't always the case, see rust-lang#119930 for some details. let gross_cap_estimation = unit.pkg.summary().features().len() * 7 + 25; let mut arg_feature = OsString::with_capacity(gross_cap_estimation); arg_feature.push("cfg(feature, values("); for (i, feature) in unit.pkg.summary().features().keys().enumerate() { if i != 0 { arg_feature.push(", "); } arg_feature.push("\""); arg_feature.push(feature); arg_feature.push("\""); } arg_feature.push("))"); // In addition to the package features, we also include the `test` cfg (since // compiler-team#785, as to be able to someday apply yt conditionaly), as well // the `docsrs` cfg from the docs.rs service. // // We include `docsrs` here (in Cargo) instead of rustc, since there is a much closer // relationship between Cargo and docs.rs than rustc and docs.rs. In particular, all // users of docs.rs use Cargo, but not all users of rustc (like Rust-for-Linux) use docs.rs. vec![ OsString::from("--check-cfg"), OsString::from("cfg(docsrs,test)"), OsString::from("--check-cfg"), arg_feature, ] } /// Adds LTO related codegen flags. fn lto_args(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> Vec { let mut result = Vec::new(); let mut push = |arg: &str| { result.push(OsString::from("-C")); result.push(OsString::from(arg)); }; match build_runner.lto[unit] { lto::Lto::Run(None) => push("lto"), lto::Lto::Run(Some(s)) => push(&format!("lto={}", s)), lto::Lto::Off => { push("lto=off"); push("embed-bitcode=no"); } lto::Lto::ObjectAndBitcode => {} // this is rustc's default lto::Lto::OnlyBitcode => push("linker-plugin-lto"), lto::Lto::OnlyObject => push("embed-bitcode=no"), } result } /// Adds dependency-relevant rustc flags and environment variables /// to the command to execute, such as [`-L`] and [`--extern`]. /// /// [`-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, build_runner: &BuildRunner<'_, '_>, unit: &Unit, ) -> CargoResult<()> { let bcx = build_runner.bcx; cmd.arg("-L").arg(&{ let mut deps = OsString::from("dependency="); deps.push(build_runner.files().deps_dir(unit)); deps }); // Be sure that the host path is also listed. This'll ensure that proc macro // dependencies are correctly found (for reexported macros). if !unit.kind.is_host() { cmd.arg("-L").arg(&{ let mut deps = OsString::from("dependency="); deps.push(build_runner.files().host_deps()); deps }); } let deps = build_runner.unit_deps(unit); // If there is not one linkable target but should, rustc fails later // on if there is an `extern crate` for it. This may turn into a hard // error in the future (see PR #4797). if !deps .iter() .any(|dep| !dep.unit.mode.is_doc() && dep.unit.target.is_linkable()) { if let Some(dep) = deps.iter().find(|dep| { !dep.unit.mode.is_doc() && dep.unit.target.is_lib() && !dep.unit.artifact.is_true() }) { bcx.gctx.shell().warn(format!( "The package `{}` \ provides no linkable target. The compiler might raise an error while compiling \ `{}`. Consider adding 'dylib' or 'rlib' to key `crate-type` in `{}`'s \ Cargo.toml. This warning might turn into a hard error in the future.", dep.unit.target.crate_name(), unit.target.crate_name(), dep.unit.target.crate_name() ))?; } } let mut unstable_opts = false; for dep in deps { if dep.unit.mode.is_run_custom_build() { cmd.env( "OUT_DIR", &build_runner.files().build_script_out_dir(&dep.unit), ); } } for arg in extern_args(build_runner, unit, &mut unstable_opts)? { cmd.arg(arg); } for (var, env) in artifact::get_env(build_runner, deps)? { cmd.env(&var, env); } // This will only be set if we're already using a feature // requiring nightly rust if unstable_opts { cmd.arg("-Z").arg("unstable-options"); } Ok(()) } /// Adds extra rustc flags and environment variables collected from the output /// of a build-script to the command to execute, include custom environment /// variables and `cfg`. fn add_custom_flags( cmd: &mut ProcessBuilder, build_script_outputs: &BuildScriptOutputs, metadata: Option, ) -> CargoResult<()> { if let Some(metadata) = metadata { if let Some(output) = build_script_outputs.get(metadata) { for cfg in output.cfgs.iter() { cmd.arg("--cfg").arg(cfg); } for check_cfg in &output.check_cfgs { cmd.arg("--check-cfg").arg(check_cfg); } for (name, value) in output.env.iter() { cmd.env(name, value); } } } Ok(()) } /// Generates a list of `--extern` arguments. pub fn extern_args( build_runner: &BuildRunner<'_, '_>, unit: &Unit, unstable_opts: &mut bool, ) -> CargoResult> { let mut result = Vec::new(); let deps = build_runner.unit_deps(unit); // Closure to add one dependency to `result`. let mut link_to = |dep: &UnitDep, extern_crate_name: InternedString, noprelude: bool| -> CargoResult<()> { let mut value = OsString::new(); let mut opts = Vec::new(); let is_public_dependency_enabled = unit .pkg .manifest() .unstable_features() .require(Feature::public_dependency()) .is_ok() || build_runner.bcx.gctx.cli_unstable().public_dependency; if !dep.public && unit.target.is_lib() && is_public_dependency_enabled { opts.push("priv"); *unstable_opts = true; } if noprelude { opts.push("noprelude"); *unstable_opts = true; } if !opts.is_empty() { value.push(opts.join(",")); value.push(":"); } value.push(extern_crate_name.as_str()); value.push("="); let mut pass = |file| { let mut value = value.clone(); value.push(file); result.push(OsString::from("--extern")); result.push(value); }; let outputs = build_runner.outputs(&dep.unit)?; if build_runner.only_requires_rmeta(unit, &dep.unit) || dep.unit.mode.is_check() { // Example: rlib dependency for an rlib, rmeta is all that is required. let output = outputs .iter() .find(|output| output.flavor == FileFlavor::Rmeta) .expect("failed to find rmeta dep for pipelined dep"); pass(&output.path); } else { // Example: a bin needs `rlib` for dependencies, it cannot use rmeta. for output in outputs.iter() { if output.flavor == FileFlavor::Linkable { pass(&output.path); } } } Ok(()) }; for dep in deps { if dep.unit.target.is_linkable() && !dep.unit.mode.is_doc() { link_to(dep, dep.extern_crate_name, dep.noprelude)?; } } if unit.target.proc_macro() { // Automatically import `proc_macro`. result.push(OsString::from("--extern")); result.push(OsString::from("proc_macro")); } Ok(result) } fn envify(s: &str) -> String { s.chars() .flat_map(|c| c.to_uppercase()) .map(|c| if c == '-' { '_' } else { c }) .collect() } /// Configuration of the display of messages emitted by the compiler, /// e.g. diagnostics, warnings, errors, and message caching. struct OutputOptions { /// What format we're emitting from Cargo itself. format: MessageFormat, /// Where to write the JSON messages to support playback later if the unit /// is fresh. The file is created lazily so that in the normal case, lots /// of empty files are not created. If this is None, the output will not /// be cached (such as when replaying cached messages). cache_cell: Option<(PathBuf, LazyCell)>, /// If `true`, display any diagnostics. /// Other types of JSON messages are processed regardless /// of the value of this flag. /// /// This is used primarily for cache replay. If you build with `-vv`, the /// cache will be filled with diagnostics from dependencies. When the /// cache is replayed without `-vv`, we don't want to show them. show_diagnostics: bool, /// Tracks the number of warnings we've seen so far. warnings_seen: usize, /// Tracks the number of errors we've seen so far. errors_seen: usize, } impl OutputOptions { fn new(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> OutputOptions { let path = build_runner.files().message_cache_path(unit); // Remove old cache, ignore ENOENT, which is the common case. drop(fs::remove_file(&path)); let cache_cell = Some((path, LazyCell::new())); let show_diagnostics = build_runner.bcx.gctx.warning_handling().unwrap_or_default() != WarningHandling::Allow; OutputOptions { format: build_runner.bcx.build_config.message_format, cache_cell, show_diagnostics, warnings_seen: 0, errors_seen: 0, } } } fn on_stdout_line( state: &JobState<'_, '_>, line: &str, _package_id: PackageId, _target: &Target, ) -> CargoResult<()> { state.stdout(line.to_string())?; Ok(()) } fn on_stderr_line( state: &JobState<'_, '_>, line: &str, package_id: PackageId, manifest_path: &std::path::Path, target: &Target, options: &mut OutputOptions, ) -> CargoResult<()> { if on_stderr_line_inner(state, line, package_id, manifest_path, target, options)? { // Check if caching is enabled. if let Some((path, cell)) = &mut options.cache_cell { // Cache the output, which will be replayed later when Fresh. let f = cell.try_borrow_mut_with(|| paths::create(path))?; debug_assert!(!line.contains('\n')); f.write_all(line.as_bytes())?; f.write_all(&[b'\n'])?; } } Ok(()) } /// Returns true if the line should be cached. fn on_stderr_line_inner( state: &JobState<'_, '_>, line: &str, package_id: PackageId, manifest_path: &std::path::Path, target: &Target, options: &mut OutputOptions, ) -> CargoResult { // We primarily want to use this function to process JSON messages from // rustc. The compiler should always print one JSON message per line, and // otherwise it may have other output intermingled (think RUST_LOG or // something like that), so skip over everything that doesn't look like a // JSON message. if !line.starts_with('{') { state.stderr(line.to_string())?; return Ok(true); } let mut compiler_message: Box = match serde_json::from_str(line) { Ok(msg) => msg, // If the compiler produced a line that started with `{` but it wasn't // valid JSON, maybe it wasn't JSON in the first place! Forward it along // to stderr. Err(e) => { debug!("failed to parse json: {:?}", e); state.stderr(line.to_string())?; return Ok(true); } }; let count_diagnostic = |level, options: &mut OutputOptions| { if level == "warning" { options.warnings_seen += 1; } else if level == "error" { options.errors_seen += 1; } }; if let Ok(report) = serde_json::from_str::(compiler_message.get()) { for item in &report.future_incompat_report { count_diagnostic(&*item.diagnostic.level, options); } state.future_incompat_report(report.future_incompat_report); return Ok(true); } // Depending on what we're emitting from Cargo itself, we figure out what to // do with this JSON message. match options.format { // In the "human" output formats (human/short) or if diagnostic messages // from rustc aren't being included in the output of Cargo's JSON // messages then we extract the diagnostic (if present) here and handle // it ourselves. MessageFormat::Human | MessageFormat::Short | MessageFormat::Json { render_diagnostics: true, .. } => { #[derive(serde::Deserialize)] struct CompilerMessage<'a> { // `rendered` contains escape sequences, which can't be // zero-copy deserialized by serde_json. // See https://github.com/serde-rs/json/issues/742 rendered: String, #[serde(borrow)] message: Cow<'a, str>, #[serde(borrow)] level: Cow<'a, str>, children: Vec, } // A partial rustfix::diagnostics::Diagnostic. We deserialize only a // subset of the fields because rustc's output can be extremely // deeply nested JSON in pathological cases involving macro // expansion. Rustfix's Diagnostic struct is recursive containing a // field `children: Vec`, and it can cause deserialization to // hit serde_json's default recursion limit, or overflow the stack // if we turn that off. Cargo only cares about the 1 field listed // here. #[derive(serde::Deserialize)] struct PartialDiagnostic { spans: Vec, } // A partial rustfix::diagnostics::DiagnosticSpan. #[derive(serde::Deserialize)] struct PartialDiagnosticSpan { suggestion_applicability: Option, } if let Ok(mut msg) = serde_json::from_str::>(compiler_message.get()) { if msg.message.starts_with("aborting due to") || msg.message.ends_with("warning emitted") || msg.message.ends_with("warnings emitted") { // Skip this line; we'll print our own summary at the end. return Ok(true); } // state.stderr will add a newline if msg.rendered.ends_with('\n') { msg.rendered.pop(); } let rendered = msg.rendered; if options.show_diagnostics { let machine_applicable: bool = msg .children .iter() .map(|child| { child .spans .iter() .filter_map(|span| span.suggestion_applicability) .any(|app| app == Applicability::MachineApplicable) }) .any(|b| b); count_diagnostic(&msg.level, options); state.emit_diag(&msg.level, rendered, machine_applicable)?; } return Ok(true); } } // Remove color information from the rendered string if color is not // enabled. Cargo always asks for ANSI colors from rustc. This allows // cached replay to enable/disable colors without re-invoking rustc. MessageFormat::Json { ansi: false, .. } => { #[derive(serde::Deserialize, serde::Serialize)] struct CompilerMessage<'a> { rendered: String, #[serde(flatten, borrow)] other: std::collections::BTreeMap, serde_json::Value>, } if let Ok(mut error) = serde_json::from_str::>(compiler_message.get()) { error.rendered = anstream::adapter::strip_str(&error.rendered).to_string(); let new_line = serde_json::to_string(&error)?; compiler_message = serde_json::value::RawValue::from_string(new_line)?; } } // If ansi colors are desired then we should be good to go! We can just // pass through this message as-is. MessageFormat::Json { ansi: true, .. } => {} } // We always tell rustc to emit messages about artifacts being produced. // These messages feed into pipelined compilation, as well as timing // information. // // Look for a matching directive and inform Cargo internally that a // metadata file has been produced. #[derive(serde::Deserialize)] struct ArtifactNotification<'a> { #[serde(borrow)] artifact: Cow<'a, str>, } if let Ok(artifact) = serde_json::from_str::>(compiler_message.get()) { trace!("found directive from rustc: `{}`", artifact.artifact); if artifact.artifact.ends_with(".rmeta") { debug!("looks like metadata finished early!"); state.rmeta_produced(); } return Ok(false); } // And failing all that above we should have a legitimate JSON diagnostic // from the compiler, so wrap it in an external Cargo JSON message // indicating which package it came from and then emit it. if !options.show_diagnostics { return Ok(true); } #[derive(serde::Deserialize)] struct CompilerMessage<'a> { #[serde(borrow)] message: Cow<'a, str>, #[serde(borrow)] level: Cow<'a, str>, } if let Ok(msg) = serde_json::from_str::>(compiler_message.get()) { if msg.message.starts_with("aborting due to") || msg.message.ends_with("warning emitted") || msg.message.ends_with("warnings emitted") { // Skip this line; we'll print our own summary at the end. return Ok(true); } count_diagnostic(&msg.level, options); } let msg = machine_message::FromCompiler { package_id: package_id.to_spec(), manifest_path, target, message: compiler_message, } .to_json_string(); // Switch json lines from rustc/rustdoc that appear on stderr to stdout // instead. We want the stdout of Cargo to always be machine parseable as // stderr has our colorized human-readable messages. state.stdout(msg)?; Ok(true) } /// Creates a unit of work that replays the cached compiler message. /// /// Usually used when a job is fresh and doesn't need to recompile. fn replay_output_cache( package_id: PackageId, manifest_path: PathBuf, target: &Target, path: PathBuf, format: MessageFormat, show_diagnostics: bool, ) -> Work { let target = target.clone(); let mut options = OutputOptions { format, cache_cell: None, show_diagnostics, warnings_seen: 0, errors_seen: 0, }; Work::new(move |state| { if !path.exists() { // No cached output, probably didn't emit anything. return Ok(()); } // We sometimes have gigabytes of output from the compiler, so avoid // loading it all into memory at once, as that can cause OOM where // otherwise there would be none. let file = paths::open(&path)?; let mut reader = std::io::BufReader::new(file); let mut line = String::new(); loop { let length = reader.read_line(&mut line)?; if length == 0 { break; } let trimmed = line.trim_end_matches(&['\n', '\r'][..]); on_stderr_line( state, trimmed, package_id, &manifest_path, &target, &mut options, )?; line.clear(); } Ok(()) }) } /// Provides a package name with descriptive target information, /// e.g., '`foo` (bin "bar" test)', '`foo` (lib doctest)'. fn descriptive_pkg_name(name: &str, target: &Target, mode: &CompileMode) -> String { let desc_name = target.description_named(); let mode = if mode.is_rustc_test() && !(target.is_test() || target.is_bench()) { " test" } else if mode.is_doc_test() { " doctest" } else if mode.is_doc() { " doc" } else { "" }; format!("`{name}` ({desc_name}{mode})") } /// Applies environment variables from config `[env]` to [`ProcessBuilder`]. pub(crate) fn apply_env_config( gctx: &crate::GlobalContext, cmd: &mut ProcessBuilder, ) -> CargoResult<()> { for (key, value) in gctx.env_config()?.iter() { // never override a value that has already been set by cargo if cmd.get_envs().contains_key(key) { continue; } cmd.env(key, value); } 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(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult { assert!(unit.mode.is_doc() || unit.mode.is_doc_scrape()); build_runner .outputs(unit) .map(|outputs| outputs[0].path.clone()) } cargo-0.86.0/src/cargo/core/compiler/output_depinfo.rs000064400000000000000000000151671046102023000210620ustar 00000000000000//! dep-info files for external build system integration. //! See [`output_depinfo`] for more. use cargo_util::paths::normalize_path; use std::collections::{BTreeSet, HashSet}; use std::io::{BufWriter, Write}; use std::path::{Path, PathBuf}; use super::{fingerprint, BuildRunner, FileFlavor, Unit}; use crate::util::{internal, CargoResult}; use cargo_util::paths; use tracing::debug; /// Bacially just normalizes a given path and converts it to a string. fn render_filename>(path: P, basedir: Option<&str>) -> CargoResult { fn wrap_path(path: &Path) -> CargoResult { path.to_str() .ok_or_else(|| internal(format!("path `{:?}` not utf-8", path))) .map(|f| f.replace(" ", "\\ ")) } let path = path.as_ref(); if let Some(basedir) = basedir { let norm_path = normalize_path(path); let norm_basedir = normalize_path(basedir.as_ref()); match norm_path.strip_prefix(norm_basedir) { Ok(relpath) => wrap_path(relpath), _ => wrap_path(path), } } else { wrap_path(path) } } /// Collects all dependencies of the `unit` for the output dep info file. /// /// Dependencies will be stored in `deps`, including: /// /// * dependencies from [fingerprint dep-info] /// * paths from `rerun-if-changed` build script instruction /// * ...and traverse transitive dependencies recursively /// /// [fingerprint dep-info]: super::fingerprint#fingerprint-dep-info-files fn add_deps_for_unit( deps: &mut BTreeSet, build_runner: &mut BuildRunner<'_, '_>, unit: &Unit, visited: &mut HashSet, ) -> CargoResult<()> { if !visited.insert(unit.clone()) { return Ok(()); } // units representing the execution of a build script don't actually // generate a dep info file, so we just keep on going below if !unit.mode.is_run_custom_build() { // Add dependencies from rustc dep-info output (stored in fingerprint directory) let dep_info_loc = fingerprint::dep_info_loc(build_runner, unit); if let Some(paths) = fingerprint::parse_dep_info( unit.pkg.root(), build_runner.files().host_root(), &dep_info_loc, )? { for path in paths.files.into_keys() { deps.insert(path); } } else { debug!( "can't find dep_info for {:?} {}", unit.pkg.package_id(), unit.target ); return Err(internal("dep_info missing")); } } // Add rerun-if-changed dependencies if let Some(metadata) = build_runner.find_build_script_metadata(unit) { if let Some(output) = build_runner .build_script_outputs .lock() .unwrap() .get(metadata) { for path in &output.rerun_if_changed { // The paths we have saved from the unit are of arbitrary relativeness and may be // relative to the crate root of the dependency. let path = unit.pkg.root().join(path); deps.insert(path); } } } // Recursively traverse all transitive dependencies let unit_deps = Vec::from(build_runner.unit_deps(unit)); // Create vec due to mutable borrow. for dep in unit_deps { if dep.unit.is_local() { add_deps_for_unit(deps, build_runner, &dep.unit, visited)?; } } Ok(()) } /// Save a `.d` dep-info file for the given unit. This is the third kind of /// dep-info mentioned in [`fingerprint`] module. /// /// Argument `unit` is expected to be the root unit, which will be uplifted. /// /// Cargo emits its own dep-info files in the output directory. This is /// only done for every "uplifted" artifact. These are intended to be used /// with external build systems so that they can detect if Cargo needs to be /// re-executed. /// /// It includes all the entries from the `rustc` dep-info file, and extends it /// with any `rerun-if-changed` entries from build scripts. It also includes /// sources from any path dependencies. Registry dependencies are not included /// under the assumption that changes to them can be detected via changes to /// `Cargo.lock`. /// /// [`fingerprint`]: super::fingerprint#dep-info-files pub fn output_depinfo(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<()> { let bcx = build_runner.bcx; let mut deps = BTreeSet::new(); let mut visited = HashSet::new(); let success = add_deps_for_unit(&mut deps, build_runner, unit, &mut visited).is_ok(); let basedir_string; let basedir = match bcx.gctx.build_config()?.dep_info_basedir.clone() { Some(value) => { basedir_string = value .resolve_path(bcx.gctx) .as_os_str() .to_str() .ok_or_else(|| anyhow::format_err!("build.dep-info-basedir path not utf-8"))? .to_string(); Some(basedir_string.as_str()) } None => None, }; let deps = deps .iter() .map(|f| render_filename(f, basedir)) .collect::>>()?; for output in build_runner .outputs(unit)? .iter() .filter(|o| !matches!(o.flavor, FileFlavor::DebugInfo | FileFlavor::Auxiliary)) { if let Some(ref link_dst) = output.hardlink { let output_path = link_dst.with_extension("d"); if success { let target_fn = render_filename(link_dst, basedir)?; // If nothing changed don't recreate the file which could alter // its mtime if let Ok(previous) = fingerprint::parse_rustc_dep_info(&output_path) { if previous .files .iter() .map(|(path, _checksum)| path) .eq(deps.iter().map(Path::new)) { continue; } } // Otherwise write it all out let mut outfile = BufWriter::new(paths::create(output_path)?); write!(outfile, "{}:", target_fn)?; for dep in &deps { write!(outfile, " {}", dep)?; } writeln!(outfile)?; // dep-info generation failed, so delete output file. This will // usually cause the build system to always rerun the build // rule, which is correct if inefficient. } else if output_path.exists() { paths::remove_file(output_path)?; } } } Ok(()) } cargo-0.86.0/src/cargo/core/compiler/rustdoc.rs000064400000000000000000000262221046102023000174730ustar 00000000000000//! Utilities for building with rustdoc. use crate::core::compiler::build_runner::BuildRunner; use crate::core::compiler::unit::Unit; use crate::core::compiler::{BuildContext, CompileKind}; use crate::sources::CRATES_IO_REGISTRY; use crate::util::errors::{internal, CargoResult}; use cargo_util::ProcessBuilder; use std::collections::HashMap; use std::collections::HashSet; use std::fmt; use std::hash; use url::Url; use super::CompileMode; const DOCS_RS_URL: &'static str = "https://docs.rs/"; /// Mode used for `std`. This is for unstable feature [`-Zrustdoc-map`][1]. /// /// [1]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#rustdoc-map #[derive(Debug, Hash)] pub enum RustdocExternMode { /// Use a local `file://` URL. Local, /// Use a remote URL to (default). Remote, /// An arbitrary URL. Url(String), } impl From for RustdocExternMode { fn from(s: String) -> RustdocExternMode { match s.as_ref() { "local" => RustdocExternMode::Local, "remote" => RustdocExternMode::Remote, _ => RustdocExternMode::Url(s), } } } impl fmt::Display for RustdocExternMode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { RustdocExternMode::Local => "local".fmt(f), RustdocExternMode::Remote => "remote".fmt(f), RustdocExternMode::Url(s) => s.fmt(f), } } } impl<'de> serde::de::Deserialize<'de> for RustdocExternMode { fn deserialize(deserializer: D) -> Result where D: serde::de::Deserializer<'de>, { let s = String::deserialize(deserializer)?; Ok(s.into()) } } /// A map of registry names to URLs where documentations are hosted. /// This is for unstable feature [`-Zrustdoc-map`][1]. /// /// [1]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#rustdoc-map #[derive(serde::Deserialize, Debug)] #[serde(default)] pub struct RustdocExternMap { #[serde(deserialize_with = "default_crates_io_to_docs_rs")] /// * Key is the registry name in the configuration `[registries.]`. /// * Value is the URL where the documentation is hosted. registries: HashMap, std: Option, } impl Default for RustdocExternMap { fn default() -> Self { Self { registries: HashMap::from([(CRATES_IO_REGISTRY.into(), DOCS_RS_URL.into())]), std: None, } } } fn default_crates_io_to_docs_rs<'de, D: serde::Deserializer<'de>>( de: D, ) -> Result, D::Error> { use serde::Deserialize; let mut registries = HashMap::deserialize(de)?; if !registries.contains_key(CRATES_IO_REGISTRY) { registries.insert(CRATES_IO_REGISTRY.into(), DOCS_RS_URL.into()); } Ok(registries) } impl hash::Hash for RustdocExternMap { fn hash(&self, into: &mut H) { self.std.hash(into); for (key, value) in &self.registries { key.hash(into); value.hash(into); } } } /// Recursively generate html root url for all units and their children. /// /// This is needed because in case there is a reexport of foreign reexport, you /// need to have information about grand-children deps level (deps of your deps). fn build_all_urls( build_runner: &BuildRunner<'_, '_>, rustdoc: &mut ProcessBuilder, unit: &Unit, name2url: &HashMap<&String, Url>, map: &RustdocExternMap, unstable_opts: &mut bool, seen: &mut HashSet, ) { for dep in build_runner.unit_deps(unit) { if !seen.insert(dep.unit.clone()) { continue; } if !dep.unit.target.is_linkable() || dep.unit.mode.is_doc() { continue; } for (registry, location) in &map.registries { let sid = dep.unit.pkg.package_id().source_id(); let matches_registry = || -> bool { if !sid.is_registry() { return false; } if sid.is_crates_io() { return registry == CRATES_IO_REGISTRY; } if let Some(index_url) = name2url.get(registry) { return index_url == sid.url(); } false }; if matches_registry() { let mut url = location.clone(); if !url.contains("{pkg_name}") && !url.contains("{version}") { if !url.ends_with('/') { url.push('/'); } url.push_str("{pkg_name}/{version}/"); } let url = url .replace("{pkg_name}", &dep.unit.pkg.name()) .replace("{version}", &dep.unit.pkg.version().to_string()); rustdoc.arg("--extern-html-root-url"); rustdoc.arg(format!("{}={}", dep.unit.target.crate_name(), url)); *unstable_opts = true; } } build_all_urls( build_runner, rustdoc, &dep.unit, name2url, map, unstable_opts, seen, ); } } /// Adds unstable flag [`--extern-html-root-url`][1] to the given `rustdoc` /// invocation. This is for unstable feature [`-Zrustdoc-map`][2]. /// /// [1]: https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html#--extern-html-root-url-control-how-rustdoc-links-to-non-local-crates /// [2]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#rustdoc-map pub fn add_root_urls( build_runner: &BuildRunner<'_, '_>, unit: &Unit, rustdoc: &mut ProcessBuilder, ) -> CargoResult<()> { let gctx = build_runner.bcx.gctx; if !gctx.cli_unstable().rustdoc_map { tracing::debug!("`doc.extern-map` ignored, requires -Zrustdoc-map flag"); return Ok(()); } let map = gctx.doc_extern_map()?; let mut unstable_opts = false; // Collect mapping of registry name -> index url. let name2url: HashMap<&String, Url> = map .registries .keys() .filter_map(|name| { if let Ok(index_url) = gctx.get_registry_index(name) { Some((name, index_url)) } else { tracing::warn!( "`doc.extern-map.{}` specifies a registry that is not defined", name ); None } }) .collect(); build_all_urls( build_runner, rustdoc, unit, &name2url, map, &mut unstable_opts, &mut HashSet::new(), ); let std_url = match &map.std { None | Some(RustdocExternMode::Remote) => None, Some(RustdocExternMode::Local) => { let sysroot = &build_runner.bcx.target_data.info(CompileKind::Host).sysroot; let html_root = sysroot.join("share").join("doc").join("rust").join("html"); if html_root.exists() { let url = Url::from_file_path(&html_root).map_err(|()| { internal(format!( "`{}` failed to convert to URL", html_root.display() )) })?; Some(url.to_string()) } else { tracing::warn!( "`doc.extern-map.std` is \"local\", but local docs don't appear to exist at {}", html_root.display() ); None } } Some(RustdocExternMode::Url(s)) => Some(s.to_string()), }; if let Some(url) = std_url { for name in &["std", "core", "alloc", "proc_macro"] { rustdoc.arg("--extern-html-root-url"); rustdoc.arg(format!("{}={}", name, url)); unstable_opts = true; } } if unstable_opts { rustdoc.arg("-Zunstable-options"); } Ok(()) } /// Adds unstable flag [`--output-format`][1] to the given `rustdoc` /// invocation. This is for unstable feature [`-Zunstable-features`]. /// /// [1]: https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html?highlight=output-format#-w--output-format-output-format pub fn add_output_format( build_runner: &BuildRunner<'_, '_>, unit: &Unit, rustdoc: &mut ProcessBuilder, ) -> CargoResult<()> { let gctx = build_runner.bcx.gctx; if !gctx.cli_unstable().unstable_options { tracing::debug!("`unstable-options` is ignored, required -Zunstable-options flag"); return Ok(()); } if let CompileMode::Doc { json: true, .. } = unit.mode { rustdoc.arg("-Zunstable-options"); rustdoc.arg("--output-format=json"); } Ok(()) } /// Indicates whether a target should have examples scraped from it by rustdoc. /// Configured within Cargo.toml and only for unstable feature /// [`-Zrustdoc-scrape-examples`][1]. /// /// [1]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#scrape-examples #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Copy)] pub enum RustdocScrapeExamples { Enabled, Disabled, Unset, } impl RustdocScrapeExamples { pub fn is_enabled(&self) -> bool { matches!(self, RustdocScrapeExamples::Enabled) } pub fn is_unset(&self) -> bool { matches!(self, RustdocScrapeExamples::Unset) } } impl BuildContext<'_, '_> { /// Returns the set of [`Docscrape`] units that have a direct dependency on `unit`. /// /// [`RunCustomBuild`] units are excluded because we allow failures /// from type checks but not build script executions. /// A plain old `cargo doc` would just die if a build script execution fails, /// there is no reason for `-Zrustdoc-scrape-examples` to keep going. /// /// [`Docscrape`]: crate::core::compiler::CompileMode::Docscrape /// [`RunCustomBuild`]: crate::core::compiler::CompileMode::Docscrape pub fn scrape_units_have_dep_on<'a>(&'a self, unit: &'a Unit) -> Vec<&'a Unit> { self.scrape_units .iter() .filter(|scrape_unit| { self.unit_graph[scrape_unit] .iter() .any(|dep| &dep.unit == unit && !dep.unit.mode.is_run_custom_build()) }) .collect() } /// Returns true if this unit is needed for doing doc-scraping and is also /// allowed to fail without killing the build. pub fn unit_can_fail_for_docscraping(&self, unit: &Unit) -> bool { // If the unit is not a Docscrape unit, e.g. a Lib target that is // checked to scrape an Example target, then we need to get the doc-scrape-examples // configuration for the reverse-dependent Example target. let for_scrape_units = if unit.mode.is_doc_scrape() { vec![unit] } else { self.scrape_units_have_dep_on(unit) }; if for_scrape_units.is_empty() { false } else { // All Docscrape units must have doc-scrape-examples unset. If any are true, // then the unit is not allowed to fail. for_scrape_units .iter() .all(|unit| unit.target.doc_scrape_examples().is_unset()) } } } cargo-0.86.0/src/cargo/core/compiler/standard_lib.rs000064400000000000000000000207461046102023000204430ustar 00000000000000//! Code for building the standard library. use crate::core::compiler::unit_dependencies::IsArtifact; use crate::core::compiler::UnitInterner; use crate::core::compiler::{CompileKind, CompileMode, RustcTargetData, Unit}; use crate::core::profiles::{Profiles, UnitFor}; use crate::core::resolver::features::{CliFeatures, FeaturesFor, ResolvedFeatures}; use crate::core::resolver::HasDevUnits; use crate::core::{PackageId, PackageSet, Resolve, Workspace}; use crate::ops::{self, Packages}; use crate::util::errors::CargoResult; use std::collections::{HashMap, HashSet}; use std::path::PathBuf; use super::BuildConfig; fn std_crates<'a>(crates: &'a [String], default: &'static str, units: &[Unit]) -> HashSet<&'a str> { let mut crates = HashSet::from_iter(crates.iter().map(|s| s.as_str())); // This is a temporary hack until there is a more principled way to // declare dependencies in Cargo.toml. if crates.is_empty() { crates.insert(default); } if crates.contains("std") { crates.insert("core"); crates.insert("alloc"); crates.insert("proc_macro"); crates.insert("panic_unwind"); crates.insert("compiler_builtins"); // Only build libtest if it looks like it is needed (libtest depends on libstd) // If we know what units we're building, we can filter for libtest depending on the jobs. if units .iter() .any(|unit| unit.mode.is_rustc_test() && unit.target.harness()) { crates.insert("test"); } } else if crates.contains("core") { crates.insert("compiler_builtins"); } crates } /// Resolve the standard library dependencies. /// /// * `crates` is the arg value from `-Zbuild-std`. pub fn resolve_std<'gctx>( ws: &Workspace<'gctx>, target_data: &mut RustcTargetData<'gctx>, build_config: &BuildConfig, crates: &[String], kinds: &[CompileKind], ) -> CargoResult<(PackageSet<'gctx>, Resolve, ResolvedFeatures)> { if build_config.build_plan { ws.gctx() .shell() .warn("-Zbuild-std does not currently fully support --build-plan")?; } let src_path = detect_sysroot_src_path(target_data)?; let std_ws_manifest_path = src_path.join("Cargo.toml"); let gctx = ws.gctx(); // TODO: Consider doing something to enforce --locked? Or to prevent the // lock file from being written, such as setting ephemeral. let mut std_ws = Workspace::new(&std_ws_manifest_path, gctx)?; // Don't require optional dependencies in this workspace, aka std's own // `[dev-dependencies]`. No need for us to generate a `Resolve` which has // those included because we'll never use them anyway. std_ws.set_require_optional_deps(false); let specs = { // If there is anything looks like needing std, resolve with it. // If not, we assume only `core` maye be needed, as `core the most fundamental crate. // // This may need a UI overhaul if `build-std` wants to fully support multi-targets. let maybe_std = kinds .iter() .any(|kind| target_data.info(*kind).maybe_support_std()); let mut crates = std_crates(crates, if maybe_std { "std" } else { "core" }, &[]); // `sysroot` is not in the default set because it is optional, but it needs // to be part of the resolve in case we do need it or `libtest`. crates.insert("sysroot"); let specs = Packages::Packages(crates.into_iter().map(Into::into).collect()); specs.to_package_id_specs(&std_ws)? }; let features = match &gctx.cli_unstable().build_std_features { Some(list) => list.clone(), None => vec![ "panic-unwind".to_string(), "backtrace".to_string(), "default".to_string(), ], }; let cli_features = CliFeatures::from_command_line( &features, /*all_features*/ false, /*uses_default_features*/ false, )?; let dry_run = false; let resolve = ops::resolve_ws_with_opts( &std_ws, target_data, &build_config.requested_kinds, &cli_features, &specs, HasDevUnits::No, crate::core::resolver::features::ForceAllTargets::No, dry_run, )?; Ok(( resolve.pkg_set, resolve.targeted_resolve, resolve.resolved_features, )) } /// Generates a map of root units for the standard library for each kind requested. /// /// * `crates` is the arg value from `-Zbuild-std`. /// * `units` is the root units of the build. pub fn generate_std_roots( crates: &[String], units: &[Unit], std_resolve: &Resolve, std_features: &ResolvedFeatures, kinds: &[CompileKind], package_set: &PackageSet<'_>, interner: &UnitInterner, profiles: &Profiles, target_data: &RustcTargetData<'_>, ) -> CargoResult>> { // Generate a map of Units for each kind requested. let mut ret = HashMap::new(); let (maybe_std, maybe_core): (Vec<&CompileKind>, Vec<_>) = kinds .iter() .partition(|kind| target_data.info(**kind).maybe_support_std()); for (default_crate, kinds) in [("core", maybe_core), ("std", maybe_std)] { if kinds.is_empty() { continue; } generate_roots( &mut ret, default_crate, crates, units, std_resolve, std_features, &kinds, package_set, interner, profiles, target_data, )?; } Ok(ret) } fn generate_roots( ret: &mut HashMap>, default: &'static str, crates: &[String], units: &[Unit], std_resolve: &Resolve, std_features: &ResolvedFeatures, kinds: &[&CompileKind], package_set: &PackageSet<'_>, interner: &UnitInterner, profiles: &Profiles, target_data: &RustcTargetData<'_>, ) -> CargoResult<()> { let std_ids = std_crates(crates, default, units) .iter() .map(|crate_name| std_resolve.query(crate_name)) .collect::>>()?; let std_pkgs = package_set.get_many(std_ids)?; for pkg in std_pkgs { let lib = pkg .targets() .iter() .find(|t| t.is_lib()) .expect("std has a lib"); // I don't think we need to bother with Check here, the difference // in time is minimal, and the difference in caching is // significant. let mode = CompileMode::Build; let features = std_features.activated_features(pkg.package_id(), FeaturesFor::NormalOrDev); for kind in kinds { let kind = **kind; let list = ret.entry(kind).or_insert_with(Vec::new); let unit_for = UnitFor::new_normal(kind); let profile = profiles.get_profile( pkg.package_id(), /*is_member*/ false, /*is_local*/ false, unit_for, kind, ); list.push(interner.intern( pkg, lib, profile, kind, mode, features.clone(), target_data.info(kind).rustflags.clone(), target_data.info(kind).rustdocflags.clone(), target_data.target_config(kind).links_overrides.clone(), /*is_std*/ true, /*dep_hash*/ 0, IsArtifact::No, None, )); } } Ok(()) } fn detect_sysroot_src_path(target_data: &RustcTargetData<'_>) -> CargoResult { if let Some(s) = target_data.gctx.get_env_os("__CARGO_TESTS_ONLY_SRC_ROOT") { return Ok(s.into()); } // NOTE: This is temporary until we figure out how to acquire the source. let src_path = target_data .info(CompileKind::Host) .sysroot .join("lib") .join("rustlib") .join("src") .join("rust") .join("library"); let lock = src_path.join("Cargo.lock"); if !lock.exists() { let msg = format!( "{:?} does not exist, unable to build with the standard \ library, try:\n rustup component add rust-src", lock ); match target_data.gctx.get_env("RUSTUP_TOOLCHAIN") { Ok(rustup_toolchain) => { anyhow::bail!("{} --toolchain {}", msg, rustup_toolchain); } Err(_) => { anyhow::bail!(msg); } } } Ok(src_path) } cargo-0.86.0/src/cargo/core/compiler/timings.js000064400000000000000000000355261046102023000174610ustar 00000000000000// Position of the vertical axis. const X_LINE = 50; // General-use margin size. const MARGIN = 5; // Position of the horizontal axis, relative to the bottom. const Y_LINE = 35; // Minimum distance between time tick labels. const MIN_TICK_DIST = 50; // Radius for rounded rectangle corners. const RADIUS = 3; // Height of unit boxes. const BOX_HEIGHT = 25; // Distance between Y tick marks on the unit graph. const Y_TICK_DIST = BOX_HEIGHT + 2; // Rects used for mouseover detection. // Objects of {x, y, x2, y2, i} where `i` is the index into UNIT_DATA. let HIT_BOXES = []; // Index into UNIT_DATA of the last unit hovered over by mouse. let LAST_HOVER = null; // Key is unit index, value is {x, y, width, rmeta_x} of the box. let UNIT_COORDS = {}; // Map of unit index to the index it was unlocked by. let REVERSE_UNIT_DEPS = {}; let REVERSE_UNIT_RMETA_DEPS = {}; // Colors from css const getCssColor = name => getComputedStyle(document.body).getPropertyValue(name); const TEXT_COLOR = getCssColor('--text'); const BG_COLOR = getCssColor('--background'); const CANVAS_BG = getCssColor('--canvas-background'); const AXES_COLOR = getCssColor('--canvas-axes'); const GRID_COLOR = getCssColor('--canvas-grid'); const BLOCK_COLOR = getCssColor('--canvas-block'); const CUSTOM_BUILD_COLOR = getCssColor('--canvas-custom-build'); const NOT_CUSTOM_BUILD_COLOR = getCssColor('--canvas-not-custom-build'); const DEP_LINE_COLOR = getCssColor('--canvas-dep-line'); const DEP_LINE_HIGHLIGHTED_COLOR = getCssColor('--canvas-dep-line-highlighted'); const CPU_COLOR = getCssColor('--canvas-cpu'); for (let n=0; n unit.duration >= min_time); const graph_height = Y_TICK_DIST * units.length; const {ctx, graph_width, canvas_width, canvas_height, px_per_sec} = draw_graph_axes('pipeline-graph', graph_height); const container = document.getElementById('pipeline-container'); container.style.width = canvas_width; container.style.height = canvas_height; // Canvas for hover highlights. This is a separate layer to improve performance. const linectx = setup_canvas('pipeline-graph-lines', canvas_width, canvas_height); linectx.clearRect(0, 0, canvas_width, canvas_height); ctx.strokeStyle = AXES_COLOR; // Draw Y tick marks. for (let n=1; n 1 ? `${unit.name} (v${unit.version})${unit.target}` : `${unit.name}${unit.target}`; const label = `${labelName}: ${unit.duration}s`; const text_info = ctx.measureText(label); const label_x = Math.min(x + 5.0, canvas_width - text_info.width - X_LINE); ctx.fillText(label, label_x, y + BOX_HEIGHT / 2); draw_dep_lines(ctx, unit.i, false); } ctx.restore(); } // Draws lines from the given unit to the units it unlocks. function draw_dep_lines(ctx, unit_idx, highlighted) { const unit = UNIT_DATA[unit_idx]; const {x, y, rmeta_x} = UNIT_COORDS[unit_idx]; ctx.save(); for (const unlocked of unit.unlocked_units) { draw_one_dep_line(ctx, x, y, unlocked, highlighted); } for (const unlocked of unit.unlocked_rmeta_units) { draw_one_dep_line(ctx, rmeta_x, y, unlocked, highlighted); } ctx.restore(); } function draw_one_dep_line(ctx, from_x, from_y, to_unit, highlighted) { if (to_unit in UNIT_COORDS) { let {x: u_x, y: u_y} = UNIT_COORDS[to_unit]; ctx.strokeStyle = highlighted ? DEP_LINE_HIGHLIGHTED_COLOR: DEP_LINE_COLOR; ctx.setLineDash([2]); ctx.beginPath(); ctx.moveTo(from_x, from_y+BOX_HEIGHT/2); ctx.lineTo(from_x-5, from_y+BOX_HEIGHT/2); ctx.lineTo(from_x-5, u_y+BOX_HEIGHT/2); ctx.lineTo(u_x, u_y+BOX_HEIGHT/2); ctx.stroke(); } } function render_timing_graph() { if (CONCURRENCY_DATA.length == 0) { return; } const HEIGHT = 400; const AXIS_HEIGHT = HEIGHT - MARGIN - Y_LINE; const TOP_MARGIN = 10; const GRAPH_HEIGHT = AXIS_HEIGHT - TOP_MARGIN; const {canvas_width, graph_width, ctx} = draw_graph_axes('timing-graph', AXIS_HEIGHT); // Draw Y tick marks and labels. let max_v = 0; for (c of CONCURRENCY_DATA) { max_v = Math.max(max_v, c.active, c.waiting, c.inactive); } const px_per_v = GRAPH_HEIGHT / max_v; const {step, tick_dist, num_ticks} = split_ticks(max_v, px_per_v, GRAPH_HEIGHT); ctx.textAlign = 'end'; for (n=0; n 1) { ctx.beginPath(); ctx.fillStyle = cpuFillStyle; let bottomLeft = coord(CPU_USAGE[0][0], 0); ctx.moveTo(bottomLeft.x, bottomLeft.y); for (let i=0; i < CPU_USAGE.length; i++) { let [time, usage] = CPU_USAGE[i]; let {x, y} = coord(time, usage / 100.0 * max_v); ctx.lineTo(x, y); } let bottomRight = coord(CPU_USAGE[CPU_USAGE.length - 1][0], 0); ctx.lineTo(bottomRight.x, bottomRight.y); ctx.fill(); } function draw_line(style, key) { let first = CONCURRENCY_DATA[0]; let last = coord(first.t, key(first)); ctx.strokeStyle = style; ctx.beginPath(); ctx.moveTo(last.x, last.y); for (let i=1; i 100) { throw Error("tick loop too long"); } count += 1; if (max_value <= max_ticks * step) { break; } step += 10; } } const tick_dist = px_per_v * step; const num_ticks = Math.floor(max_value / step); return {step, tick_dist, num_ticks}; } function codegen_time(unit) { if (unit.rmeta_time == null) { return null; } let ctime = unit.duration - unit.rmeta_time; return [unit.rmeta_time, ctime]; } function roundedRect(ctx, x, y, width, height, r) { r = Math.min(r, width, height); ctx.beginPath(); ctx.moveTo(x+r, y); ctx.lineTo(x+width-r, y); ctx.arc(x+width-r, y+r, r, 3*Math.PI/2, 0); ctx.lineTo(x+width, y+height-r); ctx.arc(x+width-r, y+height-r, r, 0, Math.PI/2); ctx.lineTo(x+r, y+height); ctx.arc(x+r, y+height-r, r, Math.PI/2, Math.PI); ctx.lineTo(x, y-r); ctx.arc(x+r, y+r, r, Math.PI, 3*Math.PI/2); ctx.closePath(); } function pipeline_mouse_hit(event) { // This brute-force method can be optimized if needed. for (let box of HIT_BOXES) { if (event.offsetX >= box.x && event.offsetX <= box.x2 && event.offsetY >= box.y && event.offsetY <= box.y2) { return box; } } } function pipeline_mousemove(event) { // Highlight dependency lines on mouse hover. let box = pipeline_mouse_hit(event); if (box) { if (box.i != LAST_HOVER) { LAST_HOVER = box.i; let g = document.getElementById('pipeline-graph-lines'); let ctx = g.getContext('2d'); ctx.clearRect(0, 0, g.width, g.height); ctx.save(); ctx.translate(X_LINE, MARGIN); ctx.lineWidth = 2; draw_dep_lines(ctx, box.i, true); if (box.i in REVERSE_UNIT_DEPS) { const dep_unit = REVERSE_UNIT_DEPS[box.i]; if (dep_unit in UNIT_COORDS) { const {x, y, rmeta_x} = UNIT_COORDS[dep_unit]; draw_one_dep_line(ctx, x, y, box.i, true); } } if (box.i in REVERSE_UNIT_RMETA_DEPS) { const dep_unit = REVERSE_UNIT_RMETA_DEPS[box.i]; if (dep_unit in UNIT_COORDS) { const {x, y, rmeta_x} = UNIT_COORDS[dep_unit]; draw_one_dep_line(ctx, rmeta_x, y, box.i, true); } } ctx.restore(); } } } render_pipeline_graph(); render_timing_graph(); // Set up and handle controls. { const range = document.getElementById('min-unit-time'); const time_output = document.getElementById('min-unit-time-output'); time_output.innerHTML = `${range.value}s`; range.oninput = event => { time_output.innerHTML = `${range.value}s`; render_pipeline_graph(); }; const scale = document.getElementById('scale'); const scale_output = document.getElementById('scale-output'); scale_output.innerHTML = `${scale.value}`; scale.oninput = event => { scale_output.innerHTML = `${scale.value}`; render_pipeline_graph(); render_timing_graph(); }; } cargo-0.86.0/src/cargo/core/compiler/timings.rs000064400000000000000000000600741046102023000174650ustar 00000000000000//! Timing tracking. //! //! This module implements some simple tracking information for timing of how //! long it takes for different units to compile. use super::{CompileMode, Unit}; use crate::core::compiler::job_queue::JobId; use crate::core::compiler::{BuildContext, BuildRunner, TimingOutput}; use crate::core::PackageId; use crate::util::cpu::State; use crate::util::machine_message::{self, Message}; use crate::util::style; use crate::util::{CargoResult, GlobalContext}; use anyhow::Context as _; use cargo_util::paths; use std::collections::HashMap; use std::io::{BufWriter, Write}; use std::thread::available_parallelism; use std::time::{Duration, Instant, SystemTime}; /// Tracking information for the entire build. /// /// Methods on this structure are generally called from the main thread of a /// running [`JobQueue`] instance (`DrainState` in specific) when the queue /// receives messages from spawned off threads. /// /// [`JobQueue`]: super::JobQueue pub struct Timings<'gctx> { gctx: &'gctx GlobalContext, /// Whether or not timings should be captured. enabled: bool, /// If true, saves an HTML report to disk. report_html: bool, /// If true, emits JSON information with timing information. report_json: bool, /// When Cargo started. start: Instant, /// A rendered string of when compilation started. start_str: String, /// A summary of the root units. /// /// Tuples of `(package_description, target_descriptions)`. root_targets: Vec<(String, Vec)>, /// The build profile. profile: String, /// Total number of fresh units. total_fresh: u32, /// Total number of dirty units. total_dirty: u32, /// Time tracking for each individual unit. unit_times: Vec, /// Units that are in the process of being built. /// When they finished, they are moved to `unit_times`. active: HashMap, /// Concurrency-tracking information. This is periodically updated while /// compilation progresses. concurrency: Vec, /// Last recorded state of the system's CPUs and when it happened last_cpu_state: Option, last_cpu_recording: Instant, /// Recorded CPU states, stored as tuples. First element is when the /// recording was taken and second element is percentage usage of the /// system. cpu_usage: Vec<(f64, f64)>, } /// Tracking information for an individual unit. struct UnitTime { unit: Unit, /// A string describing the cargo target. target: String, /// The time when this unit started as an offset in seconds from `Timings::start`. start: f64, /// Total time to build this unit in seconds. duration: f64, /// The time when the `.rmeta` file was generated, an offset in seconds /// from `start`. rmeta_time: Option, /// Reverse deps that are freed to run after this unit finished. unlocked_units: Vec, /// Same as `unlocked_units`, but unlocked by rmeta. unlocked_rmeta_units: Vec, } /// Periodic concurrency tracking information. #[derive(serde::Serialize)] struct Concurrency { /// Time as an offset in seconds from `Timings::start`. t: f64, /// Number of units currently running. active: usize, /// Number of units that could run, but are waiting for a jobserver token. waiting: usize, /// Number of units that are not yet ready, because they are waiting for /// dependencies to finish. inactive: usize, } impl<'gctx> Timings<'gctx> { pub fn new(bcx: &BuildContext<'_, 'gctx>, root_units: &[Unit]) -> Timings<'gctx> { let has_report = |what| bcx.build_config.timing_outputs.contains(&what); let report_html = has_report(TimingOutput::Html); let report_json = has_report(TimingOutput::Json); let enabled = report_html | report_json; let mut root_map: HashMap> = HashMap::new(); for unit in root_units { let target_desc = unit.target.description_named(); root_map .entry(unit.pkg.package_id()) .or_default() .push(target_desc); } let root_targets = root_map .into_iter() .map(|(pkg_id, targets)| { let pkg_desc = format!("{} {}", pkg_id.name(), pkg_id.version()); (pkg_desc, targets) }) .collect(); let start_str = humantime::format_rfc3339_seconds(SystemTime::now()).to_string(); let profile = bcx.build_config.requested_profile.to_string(); let last_cpu_state = if enabled { match State::current() { Ok(state) => Some(state), Err(e) => { tracing::info!("failed to get CPU state, CPU tracking disabled: {:?}", e); None } } } else { None }; Timings { gctx: bcx.gctx, enabled, report_html, report_json, start: bcx.gctx.creation_time(), start_str, root_targets, profile, total_fresh: 0, total_dirty: 0, unit_times: Vec::new(), active: HashMap::new(), concurrency: Vec::new(), last_cpu_state, last_cpu_recording: Instant::now(), cpu_usage: Vec::new(), } } /// Mark that a unit has started running. pub fn unit_start(&mut self, id: JobId, unit: Unit) { if !self.enabled { return; } let mut target = if unit.target.is_lib() && unit.mode == CompileMode::Build { // Special case for brevity, since most dependencies hit // this path. "".to_string() } else { format!(" {}", unit.target.description_named()) }; match unit.mode { CompileMode::Test => target.push_str(" (test)"), CompileMode::Build => {} CompileMode::Check { test: true } => target.push_str(" (check-test)"), CompileMode::Check { test: false } => target.push_str(" (check)"), CompileMode::Bench => target.push_str(" (bench)"), CompileMode::Doc { .. } => target.push_str(" (doc)"), CompileMode::Doctest => target.push_str(" (doc test)"), CompileMode::Docscrape => target.push_str(" (doc scrape)"), CompileMode::RunCustomBuild => target.push_str(" (run)"), } let unit_time = UnitTime { unit, target, start: self.start.elapsed().as_secs_f64(), duration: 0.0, rmeta_time: None, unlocked_units: Vec::new(), unlocked_rmeta_units: Vec::new(), }; assert!(self.active.insert(id, unit_time).is_none()); } /// Mark that the `.rmeta` file as generated. pub fn unit_rmeta_finished(&mut self, id: JobId, unlocked: Vec<&Unit>) { if !self.enabled { return; } // `id` may not always be active. "fresh" units unconditionally // generate `Message::Finish`, but this active map only tracks dirty // units. let Some(unit_time) = self.active.get_mut(&id) else { return; }; let t = self.start.elapsed().as_secs_f64(); unit_time.rmeta_time = Some(t - unit_time.start); assert!(unit_time.unlocked_rmeta_units.is_empty()); unit_time .unlocked_rmeta_units .extend(unlocked.iter().cloned().cloned()); } /// Mark that a unit has finished running. pub fn unit_finished(&mut self, id: JobId, unlocked: Vec<&Unit>) { if !self.enabled { return; } // See note above in `unit_rmeta_finished`, this may not always be active. let Some(mut unit_time) = self.active.remove(&id) else { return; }; let t = self.start.elapsed().as_secs_f64(); unit_time.duration = t - unit_time.start; assert!(unit_time.unlocked_units.is_empty()); unit_time .unlocked_units .extend(unlocked.iter().cloned().cloned()); if self.report_json { let msg = machine_message::TimingInfo { package_id: unit_time.unit.pkg.package_id().to_spec(), target: &unit_time.unit.target, mode: unit_time.unit.mode, duration: unit_time.duration, rmeta_time: unit_time.rmeta_time, } .to_json_string(); crate::drop_println!(self.gctx, "{}", msg); } self.unit_times.push(unit_time); } /// This is called periodically to mark the concurrency of internal structures. pub fn mark_concurrency(&mut self, active: usize, waiting: usize, inactive: usize) { if !self.enabled { return; } let c = Concurrency { t: self.start.elapsed().as_secs_f64(), active, waiting, inactive, }; self.concurrency.push(c); } /// Mark that a fresh unit was encountered. (No re-compile needed) pub fn add_fresh(&mut self) { self.total_fresh += 1; } /// Mark that a dirty unit was encountered. (Re-compile needed) pub fn add_dirty(&mut self) { self.total_dirty += 1; } /// Take a sample of CPU usage pub fn record_cpu(&mut self) { if !self.enabled { return; } let Some(prev) = &mut self.last_cpu_state else { return; }; // Don't take samples too frequently, even if requested. let now = Instant::now(); if self.last_cpu_recording.elapsed() < Duration::from_millis(100) { return; } let current = match State::current() { Ok(s) => s, Err(e) => { tracing::info!("failed to get CPU state: {:?}", e); return; } }; let pct_idle = current.idle_since(prev); *prev = current; self.last_cpu_recording = now; let dur = now.duration_since(self.start).as_secs_f64(); self.cpu_usage.push((dur, 100.0 - pct_idle)); } /// Call this when all units are finished. pub fn finished( &mut self, build_runner: &BuildRunner<'_, '_>, error: &Option, ) -> CargoResult<()> { if !self.enabled { return Ok(()); } self.mark_concurrency(0, 0, 0); self.unit_times .sort_unstable_by(|a, b| a.start.partial_cmp(&b.start).unwrap()); if self.report_html { self.report_html(build_runner, error) .context("failed to save timing report")?; } Ok(()) } /// Save HTML report to disk. fn report_html( &self, build_runner: &BuildRunner<'_, '_>, error: &Option, ) -> CargoResult<()> { let duration = self.start.elapsed().as_secs_f64(); let timestamp = self.start_str.replace(&['-', ':'][..], ""); let timings_path = build_runner.files().host_root().join("cargo-timings"); paths::create_dir_all(&timings_path)?; let filename = timings_path.join(format!("cargo-timing-{}.html", timestamp)); let mut f = BufWriter::new(paths::create(&filename)?); let roots: Vec<&str> = self .root_targets .iter() .map(|(name, _targets)| name.as_str()) .collect(); f.write_all(HTML_TMPL.replace("{ROOTS}", &roots.join(", ")).as_bytes())?; self.write_summary_table(&mut f, duration, build_runner.bcx, error)?; f.write_all(HTML_CANVAS.as_bytes())?; self.write_unit_table(&mut f)?; // It helps with pixel alignment to use whole numbers. writeln!( f, "\n\ \n\ \n\ ", include_str!("timings.js") )?; drop(f); let unstamped_filename = timings_path.join("cargo-timing.html"); paths::link_or_copy(&filename, &unstamped_filename)?; let mut shell = self.gctx.shell(); let timing_path = std::env::current_dir().unwrap_or_default().join(&filename); let link = shell.err_file_hyperlink(&timing_path); let msg = format!("report saved to {link}{}{link:#}", timing_path.display(),); shell.status_with_color("Timing", msg, &style::NOTE)?; Ok(()) } /// Render the summary table. fn write_summary_table( &self, f: &mut impl Write, duration: f64, bcx: &BuildContext<'_, '_>, error: &Option, ) -> CargoResult<()> { let targets: Vec = self .root_targets .iter() .map(|(name, targets)| format!("{} ({})", name, targets.join(", "))) .collect(); let targets = targets.join("
"); let time_human = if duration > 60.0 { format!(" ({}m {:.1}s)", duration as u32 / 60, duration % 60.0) } else { "".to_string() }; let total_time = format!("{:.1}s{}", duration, time_human); let max_concurrency = self.concurrency.iter().map(|c| c.active).max().unwrap(); let num_cpus = available_parallelism() .map(|x| x.get().to_string()) .unwrap_or_else(|_| "n/a".into()); let rustc_info = render_rustc_info(bcx); let error_msg = match error { Some(e) => format!(r#"Error:{e}"#), None => "".to_string(), }; write!( f, r#" {}
Targets:{}
Profile:{}
Fresh units:{}
Dirty units:{}
Total units:{}
Max concurrency:{} (jobs={} ncpu={})
Build start:{}
Total time:{}
rustc:{}
"#, targets, self.profile, self.total_fresh, self.total_dirty, self.total_fresh + self.total_dirty, max_concurrency, bcx.jobs(), num_cpus, self.start_str, total_time, rustc_info, error_msg, )?; Ok(()) } /// Write timing data in JavaScript. Primarily for `timings.js` to put data /// in a ` cargo-0.86.0/src/doc/src/reference/overriding-dependencies.md000064400000000000000000000340731046102023000222200ustar 00000000000000# Overriding Dependencies The desire to override a dependency can arise through a number of scenarios. Most of them, however, boil down to the ability to work with a crate before it's been published to [crates.io]. For example: * A crate you're working on is also used in a much larger application you're working on, and you'd like to test a bug fix to the library inside of the larger application. * An upstream crate you don't work on has a new feature or a bug fix on the master branch of its git repository which you'd like to test out. * You're about to publish a new major version of your crate, but you'd like to do integration testing across an entire package to ensure the new major version works. * You've submitted a fix to an upstream crate for a bug you found, but you'd like to immediately have your application start depending on the fixed version of the crate to avoid blocking on the bug fix getting merged. These scenarios can be solved with the [`[patch]` manifest section](#the-patch-section). This chapter walks through a few different use cases, and includes details on the different ways to override a dependency. * Example use cases * [Testing a bugfix](#testing-a-bugfix) * [Working with an unpublished minor version](#working-with-an-unpublished-minor-version) * [Overriding repository URL](#overriding-repository-url) * [Prepublishing a breaking change](#prepublishing-a-breaking-change) * [Using `[patch]` with multiple versions](#using-patch-with-multiple-versions) * Reference * [The `[patch]` section](#the-patch-section) * [The `[replace]` section](#the-replace-section) * [`paths` overrides](#paths-overrides) > **Note**: See also specifying a dependency with [multiple locations], which > can be used to override the source for a single dependency declaration in a > local package. ## Testing a bugfix Let's say you're working with the [`uuid` crate] but while you're working on it you discover a bug. You are, however, quite enterprising so you decide to also try to fix the bug! Originally your manifest will look like: [`uuid` crate]: https://crates.io/crates/uuid ```toml [package] name = "my-library" version = "0.1.0" [dependencies] uuid = "1.0" ``` First thing we'll do is to clone the [`uuid` repository][uuid-repository] locally via: ```console $ git clone https://github.com/uuid-rs/uuid.git ``` Next we'll edit the manifest of `my-library` to contain: ```toml [patch.crates-io] uuid = { path = "../path/to/uuid" } ``` Here we declare that we're *patching* the source `crates-io` with a new dependency. This will effectively add the local checked out version of `uuid` to the crates.io registry for our local package. Next up we need to ensure that our lock file is updated to use this new version of `uuid` so our package uses the locally checked out copy instead of one from crates.io. The way `[patch]` works is that it'll load the dependency at `../path/to/uuid` and then whenever crates.io is queried for versions of `uuid` it'll *also* return the local version. This means that the version number of the local checkout is significant and will affect whether the patch is used. Our manifest declared `uuid = "1.0"` which means we'll only resolve to `>= 1.0.0, < 2.0.0`, and Cargo's greedy resolution algorithm also means that we'll resolve to the maximum version within that range. Typically this doesn't matter as the version of the git repository will already be greater or match the maximum version published on crates.io, but it's important to keep this in mind! In any case, typically all you need to do now is: ```console $ cargo build Compiling uuid v1.0.0 (.../uuid) Compiling my-library v0.1.0 (.../my-library) Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs ``` And that's it! You're now building with the local version of `uuid` (note the path in parentheses in the build output). If you don't see the local path version getting built then you may need to run `cargo update uuid --precise $version` where `$version` is the version of the locally checked out copy of `uuid`. Once you've fixed the bug you originally found the next thing you'll want to do is to likely submit that as a pull request to the `uuid` crate itself. Once you've done this then you can also update the `[patch]` section. The listing inside of `[patch]` is just like the `[dependencies]` section, so once your pull request is merged you could change your `path` dependency to: ```toml [patch.crates-io] uuid = { git = 'https://github.com/uuid-rs/uuid.git' } ``` [uuid-repository]: https://github.com/uuid-rs/uuid ## Working with an unpublished minor version Let's now shift gears a bit from bug fixes to adding features. While working on `my-library` you discover that a whole new feature is needed in the `uuid` crate. You've implemented this feature, tested it locally above with `[patch]`, and submitted a pull request. Let's go over how you continue to use and test it before it's actually published. Let's also say that the current version of `uuid` on crates.io is `1.0.0`, but since then the master branch of the git repository has updated to `1.0.1`. This branch includes your new feature you submitted previously. To use this repository we'll edit our `Cargo.toml` to look like ```toml [package] name = "my-library" version = "0.1.0" [dependencies] uuid = "1.0.1" [patch.crates-io] uuid = { git = 'https://github.com/uuid-rs/uuid.git' } ``` Note that our local dependency on `uuid` has been updated to `1.0.1` as it's what we'll actually require once the crate is published. This version doesn't exist on crates.io, though, so we provide it with the `[patch]` section of the manifest. Now when our library is built it'll fetch `uuid` from the git repository and resolve to 1.0.1 inside the repository instead of trying to download a version from crates.io. Once 1.0.1 is published on crates.io the `[patch]` section can be deleted. It's also worth noting that `[patch]` applies *transitively*. Let's say you use `my-library` in a larger package, such as: ```toml [package] name = "my-binary" version = "0.1.0" [dependencies] my-library = { git = 'https://example.com/git/my-library' } uuid = "1.0" [patch.crates-io] uuid = { git = 'https://github.com/uuid-rs/uuid.git' } ``` Remember that `[patch]` is applicable *transitively* but can only be defined at the *top level* so we consumers of `my-library` have to repeat the `[patch]` section if necessary. Here, though, the new `uuid` crate applies to *both* our dependency on `uuid` and the `my-library -> uuid` dependency. The `uuid` crate will be resolved to one version for this entire crate graph, 1.0.1, and it'll be pulled from the git repository. ### Overriding repository URL In case the dependency you want to override isn't loaded from `crates.io`, you'll have to change a bit how you use `[patch]`. For example, if the dependency is a git dependency, you can override it to a local path with: ```toml [patch."https://github.com/your/repository"] my-library = { path = "../my-library/path" } ``` And that's it! ## Prepublishing a breaking change Let's take a look at working with a new major version of a crate, typically accompanied with breaking changes. Sticking with our previous crates, this means that we're going to be creating version 2.0.0 of the `uuid` crate. After we've submitted all changes upstream we can update our manifest for `my-library` to look like: ```toml [dependencies] uuid = "2.0" [patch.crates-io] uuid = { git = "https://github.com/uuid-rs/uuid.git", branch = "2.0.0" } ``` And that's it! Like with the previous example the 2.0.0 version doesn't actually exist on crates.io but we can still put it in through a git dependency through the usage of the `[patch]` section. As a thought exercise let's take another look at the `my-binary` manifest from above again as well: ```toml [package] name = "my-binary" version = "0.1.0" [dependencies] my-library = { git = 'https://example.com/git/my-library' } uuid = "1.0" [patch.crates-io] uuid = { git = 'https://github.com/uuid-rs/uuid.git', branch = '2.0.0' } ``` Note that this will actually resolve to two versions of the `uuid` crate. The `my-binary` crate will continue to use the 1.x.y series of the `uuid` crate but the `my-library` crate will use the `2.0.0` version of `uuid`. This will allow you to gradually roll out breaking changes to a crate through a dependency graph without being forced to update everything all at once. ## Using `[patch]` with multiple versions You can patch in multiple versions of the same crate with the `package` key used to rename dependencies. For example let's say that the `serde` crate has a bugfix that we'd like to use to its `1.*` series but we'd also like to prototype using a `2.0.0` version of serde we have in our git repository. To configure this we'd do: ```toml [patch.crates-io] serde = { git = 'https://github.com/serde-rs/serde.git' } serde2 = { git = 'https://github.com/example/serde.git', package = 'serde', branch = 'v2' } ``` The first `serde = ...` directive indicates that serde `1.*` should be used from the git repository (pulling in the bugfix we need) and the second `serde2 = ...` directive indicates that the `serde` package should also be pulled from the `v2` branch of `https://github.com/example/serde`. We're assuming here that `Cargo.toml` on that branch mentions version `2.0.0`. Note that when using the `package` key the `serde2` identifier here is actually ignored. We simply need a unique name which doesn't conflict with other patched crates. ## The `[patch]` section The `[patch]` section of `Cargo.toml` can be used to override dependencies with other copies. The syntax is similar to the [`[dependencies]`][dependencies] section: ```toml [patch.crates-io] foo = { git = 'https://github.com/example/foo.git' } bar = { path = 'my/local/bar' } [dependencies.baz] git = 'https://github.com/example/baz.git' [patch.'https://github.com/example/baz'] baz = { git = 'https://github.com/example/patched-baz.git', branch = 'my-branch' } ``` > **Note**: The `[patch]` table can also be specified as a [configuration > option](config.md), such as in a `.cargo/config.toml` file or a CLI option > like `--config 'patch.crates-io.rand.path="rand"'`. This can be useful for > local-only changes that you don't want to commit, or temporarily testing a > patch. The `[patch]` table is made of dependency-like sub-tables. Each key after `[patch]` is a URL of the source that is being patched, or the name of a registry. The name `crates-io` may be used to override the default registry [crates.io]. The first `[patch]` in the example above demonstrates overriding [crates.io], and the second `[patch]` demonstrates overriding a git source. Each entry in these tables is a normal dependency specification, the same as found in the `[dependencies]` section of the manifest. The dependencies listed in the `[patch]` section are resolved and used to patch the source at the URL specified. The above manifest snippet patches the `crates-io` source (e.g. crates.io itself) with the `foo` crate and `bar` crate. It also patches the `https://github.com/example/baz` source with a `my-branch` that comes from elsewhere. Sources can be patched with versions of crates that do not exist, and they can also be patched with versions of crates that already exist. If a source is patched with a crate version that already exists in the source, then the source's original crate is replaced. Cargo only looks at the patch settings in the `Cargo.toml` manifest at the root of the workspace. Patch settings defined in dependencies will be ignored. ## The `[replace]` section > **Note**: `[replace]` is deprecated. You should use the > [`[patch]`](#the-patch-section) table instead. This section of Cargo.toml can be used to override dependencies with other copies. The syntax is similar to the `[dependencies]` section: ```toml [replace] "foo:0.1.0" = { git = 'https://github.com/example/foo.git' } "bar:1.0.2" = { path = 'my/local/bar' } ``` Each key in the `[replace]` table is a [package ID specification](pkgid-spec.md), which allows arbitrarily choosing a node in the dependency graph to override (the 3-part version number is required). The value of each key is the same as the `[dependencies]` syntax for specifying dependencies, except that you can't specify features. Note that when a crate is overridden the copy it's overridden with must have both the same name and version, but it can come from a different source (e.g., git or a local path). Cargo only looks at the replace settings in the `Cargo.toml` manifest at the root of the workspace. Replace settings defined in dependencies will be ignored. ## `paths` overrides Sometimes you're only temporarily working on a crate and you don't want to have to modify `Cargo.toml` like with the `[patch]` section above. For this use case Cargo offers a much more limited version of overrides called **path overrides**. Path overrides are specified through [`.cargo/config.toml`](config.md) instead of `Cargo.toml`. Inside of `.cargo/config.toml` you'll specify a key called `paths`: ```toml paths = ["/path/to/uuid"] ``` This array should be filled with directories that contain a `Cargo.toml`. In this instance, we’re just adding `uuid`, so it will be the only one that’s overridden. This path can be either absolute or relative to the directory that contains the `.cargo` folder. Path overrides are more restricted than the `[patch]` section, however, in that they cannot change the structure of the dependency graph. When a path replacement is used then the previous set of dependencies must all match exactly to the new `Cargo.toml` specification. For example this means that path overrides cannot be used to test out adding a dependency to a crate, instead `[patch]` must be used in that situation. As a result usage of a path override is typically isolated to quick bug fixes rather than larger changes. > **Note**: using a local configuration to override paths will only work for > crates that have been published to [crates.io]. You cannot use this feature > to tell Cargo how to find local unpublished crates. [crates.io]: https://crates.io/ [multiple locations]: specifying-dependencies.md#multiple-locations [dependencies]: specifying-dependencies.md cargo-0.86.0/src/doc/src/reference/pkgid-spec.md000064400000000000000000000073511046102023000174510ustar 00000000000000# Package ID Specifications ## Package ID specifications Subcommands of Cargo frequently need to refer to a particular package within a dependency graph for various operations like updating, cleaning, building, etc. To solve this problem, Cargo supports *Package ID Specifications*. A specification is a string which is used to uniquely refer to one package within a graph of packages. The specification may be fully qualified, such as `https://github.com/rust-lang/crates.io-index#regex@1.4.3` or it may be abbreviated, such as `regex`. The abbreviated form may be used as long as it uniquely identifies a single package in the dependency graph. If there is ambiguity, additional qualifiers can be added to make it unique. For example, if there are two versions of the `regex` package in the graph, then it can be qualified with a version to make it unique, such as `regex@1.4.3`. ### Specification grammar The formal grammar for a Package Id Specification is: ```notrust spec := pkgname | [ kind "+" ] proto "://" hostname-and-path [ "?" query] [ "#" ( pkgname | semver ) ] query = ( "branch" | "tag" | "rev" ) "=" ref pkgname := name [ ("@" | ":" ) semver ] semver := digits [ "." digits [ "." digits [ "-" prerelease ] [ "+" build ]]] kind = "registry" | "git" | "file" proto := "http" | "git" | ... ``` Here, brackets indicate that the contents are optional. The URL form can be used for git dependencies, or to differentiate packages that come from different sources such as different registries. ### Example specifications The following are references to the `regex` package on `crates.io`: | Spec | Name | Version | |:------------------------------------------------------------------|:-------:|:-------:| | `regex` | `regex` | `*` | | `regex@1.4` | `regex` | `1.4.*` | | `regex@1.4.3` | `regex` | `1.4.3` | | `https://github.com/rust-lang/crates.io-index#regex` | `regex` | `*` | | `https://github.com/rust-lang/crates.io-index#regex@1.4.3` | `regex` | `1.4.3` | | `registry+https://github.com/rust-lang/crates.io-index#regex@1.4.3` | `regex` | `1.4.3` | The following are some examples of specs for several different git dependencies: | Spec | Name | Version | |:-----------------------------------------------------------|:----------------:|:--------:| | `https://github.com/rust-lang/cargo#0.52.0` | `cargo` | `0.52.0` | | `https://github.com/rust-lang/cargo#cargo-platform@0.1.2` | `cargo-platform` | `0.1.2` | | `ssh://git@github.com/rust-lang/regex.git#regex@1.4.3` | `regex` | `1.4.3` | | `git+ssh://git@github.com/rust-lang/regex.git#regex@1.4.3` | `regex` | `1.4.3` | | `git+ssh://git@github.com/rust-lang/regex.git?branch=dev#regex@1.4.3` | `regex` | `1.4.3` | Local packages on the filesystem can use `file://` URLs to reference them: | Spec | Name | Version | |:--------------------------------------------|:-----:|:-------:| | `file:///path/to/my/project/foo` | `foo` | `*` | | `file:///path/to/my/project/foo#1.1.8` | `foo` | `1.1.8` | | `path+file:///path/to/my/project/foo#1.1.8` | `foo` | `1.1.8` | ### Brevity of specifications The goal of this is to enable both succinct and exhaustive syntaxes for referring to packages in a dependency graph. Ambiguous references may refer to one or more packages. Most commands generate an error if more than one package could be referred to with the same specification. cargo-0.86.0/src/doc/src/reference/profiles.md000064400000000000000000000433761046102023000172550ustar 00000000000000# Profiles Profiles provide a way to alter the compiler settings, influencing things like optimizations and debugging symbols. Cargo has 4 built-in profiles: `dev`, `release`, `test`, and `bench`. The profile is automatically chosen based on which command is being run if a profile is not specified on the command-line. In addition to the built-in profiles, custom user-defined profiles can also be specified. Profile settings can be changed in [`Cargo.toml`](manifest.md) with the `[profile]` table. Within each named profile, individual settings can be changed with key/value pairs like this: ```toml [profile.dev] opt-level = 1 # Use slightly better optimizations. overflow-checks = false # Disable integer overflow checks. ``` Cargo only looks at the profile settings in the `Cargo.toml` manifest at the root of the workspace. Profile settings defined in dependencies will be ignored. Additionally, profiles can be overridden from a [config] definition. Specifying a profile in a config file or environment variable will override the settings from `Cargo.toml`. [config]: config.md ## Profile settings The following is a list of settings that can be controlled in a profile. ### opt-level The `opt-level` setting controls the [`-C opt-level` flag] which controls the level of optimization. Higher optimization levels may produce faster runtime code at the expense of longer compiler times. Higher levels may also change and rearrange the compiled code which may make it harder to use with a debugger. The valid options are: * `0`: no optimizations * `1`: basic optimizations * `2`: some optimizations * `3`: all optimizations * `"s"`: optimize for binary size * `"z"`: optimize for binary size, but also turn off loop vectorization. It is recommended to experiment with different levels to find the right balance for your project. There may be surprising results, such as level `3` being slower than `2`, or the `"s"` and `"z"` levels not being necessarily smaller. You may also want to reevaluate your settings over time as newer versions of `rustc` change optimization behavior. See also [Profile Guided Optimization] for more advanced optimization techniques. [`-C opt-level` flag]: ../../rustc/codegen-options/index.html#opt-level [Profile Guided Optimization]: ../../rustc/profile-guided-optimization.html ### debug The `debug` setting controls the [`-C debuginfo` flag] which controls the amount of debug information included in the compiled binary. The valid options are: * `0`, `false`, or `"none"`: no debug info at all, default for [`release`](#release) * `"line-directives-only"`: line info directives only. For the nvptx* targets this enables [profiling]. For other use cases, `line-tables-only` is the better, more compatible choice. * `"line-tables-only"`: line tables only. Generates the minimal amount of debug info for backtraces with filename/line number info, but not anything else, i.e. no variable or function parameter info. * `1` or `"limited"`: debug info without type or variable-level information. Generates more detailed module-level info than `line-tables-only`. * `2`, `true`, or `"full"`: full debug info, default for [`dev`](#dev) For more information on what each option does see `rustc`'s docs on [debuginfo]. You may wish to also configure the [`split-debuginfo`](#split-debuginfo) option depending on your needs as well. > **MSRV:** 1.71 is required for `none`, `limited`, `full`, `line-directives-only`, and `line-tables-only` [`-C debuginfo` flag]: ../../rustc/codegen-options/index.html#debuginfo [debuginfo]: ../../rustc/codegen-options/index.html#debuginfo [profiling]: https://reviews.llvm.org/D46061 ### split-debuginfo The `split-debuginfo` setting controls the [`-C split-debuginfo` flag] which controls whether debug information, if generated, is either placed in the executable itself or adjacent to it. This option is a string and acceptable values are the same as those the [compiler accepts][`-C split-debuginfo` flag]. The default value for this option is `unpacked` on macOS for profiles that have debug information otherwise enabled. Otherwise the default for this option is [documented with rustc][`-C split-debuginfo` flag] and is platform-specific. Some options are only available on the [nightly channel]. The Cargo default may change in the future once more testing has been performed, and support for DWARF is stabilized. Be aware that Cargo and rustc have different defaults for this option. This option exists to allow Cargo to experiment on different combinations of flags thus providing better debugging and developer experience. [nightly channel]: ../../book/appendix-07-nightly-rust.html [`-C split-debuginfo` flag]: ../../rustc/codegen-options/index.html#split-debuginfo ### strip The `strip` option controls the [`-C strip` flag], which directs rustc to strip either symbols or debuginfo from a binary. This can be enabled like so: ```toml [package] # ... [profile.release] strip = "debuginfo" ``` Possible string values of `strip` are `"none"`, `"debuginfo"`, and `"symbols"`. The default is `"none"`. You can also configure this option with the boolean values `true` or `false`. `strip = true` is equivalent to `strip = "symbols"`. `strip = false` is equivalent to `strip = "none"` and disables `strip` completely. [`-C strip` flag]: ../../rustc/codegen-options/index.html#strip ### debug-assertions The `debug-assertions` setting controls the [`-C debug-assertions` flag] which turns `cfg(debug_assertions)` [conditional compilation] on or off. Debug assertions are intended to include runtime validation which is only available in debug/development builds. These may be things that are too expensive or otherwise undesirable in a release build. Debug assertions enables the [`debug_assert!` macro] in the standard library. The valid options are: * `true`: enabled * `false`: disabled [`-C debug-assertions` flag]: ../../rustc/codegen-options/index.html#debug-assertions [conditional compilation]: ../../reference/conditional-compilation.md#debug_assertions [`debug_assert!` macro]: ../../std/macro.debug_assert.html ### overflow-checks The `overflow-checks` setting controls the [`-C overflow-checks` flag] which controls the behavior of [runtime integer overflow]. When overflow-checks are enabled, a panic will occur on overflow. The valid options are: * `true`: enabled * `false`: disabled [`-C overflow-checks` flag]: ../../rustc/codegen-options/index.html#overflow-checks [runtime integer overflow]: ../../reference/expressions/operator-expr.md#overflow ### lto The `lto` setting controls `rustc`'s [`-C lto`], [`-C linker-plugin-lto`], and [`-C embed-bitcode`] options, which control LLVM's [link time optimizations]. LTO can produce better optimized code, using whole-program analysis, at the cost of longer linking time. The valid options are: * `false`: Performs "thin local LTO" which performs "thin" LTO on the local crate only across its [codegen units](#codegen-units). No LTO is performed if codegen units is 1 or [opt-level](#opt-level) is 0. * `true` or `"fat"`: Performs "fat" LTO which attempts to perform optimizations across all crates within the dependency graph. * `"thin"`: Performs ["thin" LTO]. This is similar to "fat", but takes substantially less time to run while still achieving performance gains similar to "fat". * `"off"`: Disables LTO. See the [linker-plugin-lto chapter] if you are interested in cross-language LTO. This is not yet supported natively in Cargo, but can be performed via `RUSTFLAGS`. [`-C lto`]: ../../rustc/codegen-options/index.html#lto [link time optimizations]: https://llvm.org/docs/LinkTimeOptimization.html [`-C linker-plugin-lto`]: ../../rustc/codegen-options/index.html#linker-plugin-lto [`-C embed-bitcode`]: ../../rustc/codegen-options/index.html#embed-bitcode [linker-plugin-lto chapter]: ../../rustc/linker-plugin-lto.html ["thin" LTO]: http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html ### panic The `panic` setting controls the [`-C panic` flag] which controls which panic strategy to use. The valid options are: * `"unwind"`: Unwind the stack upon panic. * `"abort"`: Terminate the process upon panic. When set to `"unwind"`, the actual value depends on the default of the target platform. For example, the NVPTX platform does not support unwinding, so it always uses `"abort"`. Tests, benchmarks, build scripts, and proc macros ignore the `panic` setting. The `rustc` test harness currently requires `unwind` behavior. See the [`panic-abort-tests`] unstable flag which enables `abort` behavior. Additionally, when using the `abort` strategy and building a test, all of the dependencies will also be forced to build with the `unwind` strategy. [`-C panic` flag]: ../../rustc/codegen-options/index.html#panic [`panic-abort-tests`]: unstable.md#panic-abort-tests ### incremental The `incremental` setting controls the [`-C incremental` flag] which controls whether or not incremental compilation is enabled. Incremental compilation causes `rustc` to save additional information to disk which will be reused when recompiling the crate, improving re-compile times. The additional information is stored in the `target` directory. The valid options are: * `true`: enabled * `false`: disabled Incremental compilation is only used for workspace members and "path" dependencies. The incremental value can be overridden globally with the `CARGO_INCREMENTAL` [environment variable] or the [`build.incremental`] config variable. [`-C incremental` flag]: ../../rustc/codegen-options/index.html#incremental [environment variable]: environment-variables.md [`build.incremental`]: config.md#buildincremental ### codegen-units The `codegen-units` setting controls the [`-C codegen-units` flag] which controls how many "code generation units" a crate will be split into. More code generation units allows more of a crate to be processed in parallel possibly reducing compile time, but may produce slower code. This option takes an integer greater than 0. The default is 256 for [incremental](#incremental) builds, and 16 for non-incremental builds. [`-C codegen-units` flag]: ../../rustc/codegen-options/index.html#codegen-units ### rpath The `rpath` setting controls the [`-C rpath` flag] which controls whether or not [`rpath`] is enabled. [`-C rpath` flag]: ../../rustc/codegen-options/index.html#rpath [`rpath`]: https://en.wikipedia.org/wiki/Rpath ## Default profiles ### dev The `dev` profile is used for normal development and debugging. It is the default for build commands like [`cargo build`], and is used for `cargo install --debug`. The default settings for the `dev` profile are: ```toml [profile.dev] opt-level = 0 debug = true split-debuginfo = '...' # Platform-specific. strip = "none" debug-assertions = true overflow-checks = true lto = false panic = 'unwind' incremental = true codegen-units = 256 rpath = false ``` ### release The `release` profile is intended for optimized artifacts used for releases and in production. This profile is used when the `--release` flag is used, and is the default for [`cargo install`]. The default settings for the `release` profile are: ```toml [profile.release] opt-level = 3 debug = false split-debuginfo = '...' # Platform-specific. strip = "none" debug-assertions = false overflow-checks = false lto = false panic = 'unwind' incremental = false codegen-units = 16 rpath = false ``` ### test The `test` profile is the default profile used by [`cargo test`]. The `test` profile inherits the settings from the [`dev`](#dev) profile. ### bench The `bench` profile is the default profile used by [`cargo bench`]. The `bench` profile inherits the settings from the [`release`](#release) profile. ### Build Dependencies To compile quickly, all profiles, by default, do not optimize build dependencies (build scripts, proc macros, and their dependencies), and avoid computing debug info when a build dependency is not used as a runtime dependency. The default settings for build overrides are: ```toml [profile.dev.build-override] opt-level = 0 codegen-units = 256 debug = false # when possible [profile.release.build-override] opt-level = 0 codegen-units = 256 ``` However, if errors occur while running build dependencies, turning full debug info on will improve backtraces and debuggability when needed: ```toml debug = true ``` Build dependencies otherwise inherit settings from the active profile in use, as described in [Profile selection](#profile-selection). ## Custom profiles In addition to the built-in profiles, additional custom profiles can be defined. These may be useful for setting up multiple workflows and build modes. When defining a custom profile, you must specify the `inherits` key to specify which profile the custom profile inherits settings from when the setting is not specified. For example, let's say you want to compare a normal release build with a release build with [LTO](#lto) optimizations, you can specify something like the following in `Cargo.toml`: ```toml [profile.release-lto] inherits = "release" lto = true ``` The `--profile` flag can then be used to choose this custom profile: ```console cargo build --profile release-lto ``` The output for each profile will be placed in a directory of the same name as the profile in the [`target` directory]. As in the example above, the output would go into the `target/release-lto` directory. [`target` directory]: build-cache.md ## Profile selection The profile used depends on the command, the command-line flags like `--release` or `--profile`, and the package (in the case of [overrides](#overrides)). The default profile if none is specified is: | Command | Default Profile | |---------|-----------------| | [`cargo run`], [`cargo build`],
[`cargo check`], [`cargo rustc`] | [`dev` profile](#dev) | | [`cargo test`] | [`test` profile](#test) | [`cargo bench`] | [`bench` profile](#bench) | [`cargo install`] | [`release` profile](#release) You can switch to a different profile using the `--profile=NAME` option which will used the given profile. The `--release` flag is equivalent to `--profile=release`. The selected profile applies to all Cargo targets, including [library](./cargo-targets.md#library), [binary](./cargo-targets.md#binaries), [example](./cargo-targets.md#examples), [test](./cargo-targets.md#tests), and [benchmark](./cargo-targets.md#benchmarks). The profile for specific packages can be specified with [overrides](#overrides), described below. [`cargo bench`]: ../commands/cargo-bench.md [`cargo build`]: ../commands/cargo-build.md [`cargo check`]: ../commands/cargo-check.md [`cargo install`]: ../commands/cargo-install.md [`cargo run`]: ../commands/cargo-run.md [`cargo rustc`]: ../commands/cargo-rustc.md [`cargo test`]: ../commands/cargo-test.md ## Overrides Profile settings can be overridden for specific packages and build-time crates. To override the settings for a specific package, use the `package` table to change the settings for the named package: ```toml # The `foo` package will use the -Copt-level=3 flag. [profile.dev.package.foo] opt-level = 3 ``` The package name is actually a [Package ID Spec](pkgid-spec.md), so you can target individual versions of a package with syntax such as `[profile.dev.package."foo:2.1.0"]`. To override the settings for all dependencies (but not any workspace member), use the `"*"` package name: ```toml # Set the default for dependencies. [profile.dev.package."*"] opt-level = 2 ``` To override the settings for build scripts, proc macros, and their dependencies, use the `build-override` table: ```toml # Set the settings for build scripts and proc-macros. [profile.dev.build-override] opt-level = 3 ``` > Note: When a dependency is both a normal dependency and a build dependency, > Cargo will try to only build it once when `--target` is not specified. When > using `build-override`, the dependency may need to be built twice, once as a > normal dependency and once with the overridden build settings. This may > increase initial build times. The precedence for which value is used is done in the following order (first match wins): 1. `[profile.dev.package.name]` --- A named package. 2. `[profile.dev.package."*"]` --- For any non-workspace member. 3. `[profile.dev.build-override]` --- Only for build scripts, proc macros, and their dependencies. 4. `[profile.dev]` --- Settings in `Cargo.toml`. 5. Default values built-in to Cargo. Overrides cannot specify the `panic`, `lto`, or `rpath` settings. ### Overrides and generics The location where generic code is instantiated will influence the optimization settings used for that generic code. This can cause subtle interactions when using profile overrides to change the optimization level of a specific crate. If you attempt to raise the optimization level of a dependency which defines generic functions, those generic functions may not be optimized when used in your local crate. This is because the code may be generated in the crate where it is instantiated, and thus may use the optimization settings of that crate. For example, [nalgebra] is a library which defines vectors and matrices making heavy use of generic parameters. If your local code defines concrete nalgebra types like `Vector4` and uses their methods, the corresponding nalgebra code will be instantiated and built within your crate. Thus, if you attempt to increase the optimization level of `nalgebra` using a profile override, it may not result in faster performance. Further complicating the issue, `rustc` has some optimizations where it will attempt to share monomorphized generics between crates. If the opt-level is 2 or 3, then a crate will not use monomorphized generics from other crates, nor will it export locally defined monomorphized items to be shared with other crates. When experimenting with optimizing dependencies for development, consider trying opt-level 1, which will apply some optimizations while still allowing monomorphized items to be shared. [nalgebra]: https://crates.io/crates/nalgebra cargo-0.86.0/src/doc/src/reference/publishing.md000064400000000000000000000301051046102023000175600ustar 00000000000000# Publishing on crates.io Once you've got a library that you'd like to share with the world, it's time to publish it on [crates.io]! Publishing a crate is when a specific version is uploaded to be hosted on [crates.io]. Take care when publishing a crate, because a publish is **permanent**. The version can never be overwritten, and the code cannot be deleted. There is no limit to the number of versions which can be published, however. ## Before your first publish First things first, you’ll need an account on [crates.io] to acquire an API token. To do so, [visit the home page][crates.io] and log in via a GitHub account (required for now). You will also need to provide and verify your email address on the [Account Settings](https://crates.io/settings/profile) page. Once that is done [create an API token](https://crates.io/settings/tokens), make sure you copy it. Once you leave the page you will not be able to see it again. Then run the [`cargo login`] command. ```console $ cargo login ``` Then at the prompt put in the token specified. ```console please paste the API Token found on https://crates.io/me below abcdefghijklmnopqrstuvwxyz012345 ``` This command will inform Cargo of your API token and store it locally in your `~/.cargo/credentials.toml`. Note that this token is a **secret** and should not be shared with anyone else. If it leaks for any reason, you should revoke it immediately. > **Note**: The [`cargo logout`] command can be used to remove the token from > `credentials.toml`. This can be useful if you no longer need it stored on > the local machine. ## Before publishing a new crate Keep in mind that crate names on [crates.io] are allocated on a first-come-first-serve basis. Once a crate name is taken, it cannot be used for another crate. Check out the [metadata you can specify](manifest.md) in `Cargo.toml` to ensure your crate can be discovered more easily! Before publishing, make sure you have filled out the following fields: - [`license` or `license-file`] - [`description`] - [`homepage`] - [`repository`] - [`readme`] It would also be a good idea to include some [`keywords`] and [`categories`], though they are not required. If you are publishing a library, you may also want to consult the [Rust API Guidelines]. ### Packaging a crate The next step is to package up your crate and upload it to [crates.io]. For this we’ll use the [`cargo publish`] subcommand. This command performs the following steps: 1. Perform some verification checks on your package. 2. Compress your source code into a `.crate` file. 3. Extract the `.crate` file into a temporary directory and verify that it compiles. 4. Upload the `.crate` file to [crates.io]. 5. The registry will perform some additional checks on the uploaded package before adding it. It is recommended that you first run `cargo publish --dry-run` (or [`cargo package`] which is equivalent) to ensure there aren't any warnings or errors before publishing. This will perform the first three steps listed above. ```console $ cargo publish --dry-run ``` You can inspect the generated `.crate` file in the `target/package` directory. [crates.io] currently has a 10MB size limit on the `.crate` file. You may want to check the size of the `.crate` file to ensure you didn't accidentally package up large assets that are not required to build your package, such as test data, website documentation, or code generation. You can check which files are included with the following command: ```console $ cargo package --list ``` Cargo will automatically ignore files ignored by your version control system when packaging, but if you want to specify an extra set of files to ignore you can use the [`exclude` key](manifest.md#the-exclude-and-include-fields) in the manifest: ```toml [package] # ... exclude = [ "public/assets/*", "videos/*", ] ``` If you’d rather explicitly list the files to include, Cargo also supports an `include` key, which if set, overrides the `exclude` key: ```toml [package] # ... include = [ "**/*.rs", "Cargo.toml", ] ``` ## Uploading the crate When you are ready to publish, use the [`cargo publish`] command to upload to [crates.io]: ```console $ cargo publish ``` And that’s it, you’ve now published your first crate! ## Publishing a new version of an existing crate In order to release a new version, change [the `version` value](manifest.md#the-version-field) specified in your `Cargo.toml` manifest. Keep in mind [the SemVer rules](semver.md) which provide guidelines on what is a compatible change. Then run [`cargo publish`] as described above to upload the new version. > **Recommendation:** Consider the full release process and automate what you can. > > Each version should include: > - A changelog entry, preferably [manually curated](https://keepachangelog.com/en/1.0.0/) though a generated one is better than nothing > - A [git tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging) pointing to the published commit > > Examples of third-party tools that are representative of different workflows include (in alphabetical order): > - [cargo-release](https://crates.io/crates/cargo-release) > - [cargo-smart-release](https://crates.io/crates/cargo-smart-release) > - [release-plz](https://crates.io/crates/release-plz) > > For more, see [crates.io](https://crates.io/search?q=cargo%20release). ## Managing a crates.io-based crate Management of crates is primarily done through the command line `cargo` tool rather than the [crates.io] web interface. For this, there are a few subcommands to manage a crate. ### `cargo yank` Occasions may arise where you publish a version of a crate that actually ends up being broken for one reason or another (syntax error, forgot to include a file, etc.). For situations such as this, Cargo supports a β€œyank” of a version of a crate. ```console $ cargo yank --version 1.0.1 $ cargo yank --version 1.0.1 --undo ``` A yank **does not** delete any code. This feature is not intended for deleting accidentally uploaded secrets, for example. If that happens, you must reset those secrets immediately. The semantics of a yanked version are that no new dependencies can be created against that version, but all existing dependencies continue to work. One of the major goals of [crates.io] is to act as a permanent archive of crates that does not change over time, and allowing deletion of a version would go against this goal. Essentially a yank means that all packages with a `Cargo.lock` will not break, while any future `Cargo.lock` files generated will not list the yanked version. ### `cargo owner` A crate is often developed by more than one person, or the primary maintainer may change over time! The owner of a crate is the only person allowed to publish new versions of the crate, but an owner may designate additional owners. ```console $ cargo owner --add github-handle $ cargo owner --remove github-handle $ cargo owner --add github:rust-lang:owners $ cargo owner --remove github:rust-lang:owners ``` The owner IDs given to these commands must be GitHub user names or GitHub teams. If a user name is given to `--add`, that user is invited as a β€œnamed” owner, with full rights to the crate. In addition to being able to publish or yank versions of the crate, they have the ability to add or remove owners, *including* the owner that made *them* an owner. Needless to say, you shouldn’t make people you don’t fully trust into a named owner. In order to become a named owner, a user must have logged into [crates.io] previously. If a team name is given to `--add`, that team is invited as a β€œteam” owner, with restricted right to the crate. While they have permission to publish or yank versions of the crate, they *do not* have the ability to add or remove owners. In addition to being more convenient for managing groups of owners, teams are just a bit more secure against owners becoming malicious. The syntax for teams is currently `github:org:team` (see examples above). In order to invite a team as an owner one must be a member of that team. No such restriction applies to removing a team as an owner. ## GitHub permissions Team membership is not something GitHub provides simple public access to, and it is likely for you to encounter the following message when working with them: > It looks like you don’t have permission to query a necessary property from GitHub to complete this request. You may need to re-authenticate on [crates.io] to grant permission to read GitHub org memberships. This is basically a catch-all for β€œyou tried to query a team, and one of the five levels of membership access control denied this”. That is not an exaggeration. GitHub’s support for team access control is Enterprise Grade. The most likely cause of this is simply that you last logged in before this feature was added. We originally requested *no* permissions from GitHub when authenticating users, because we didn’t actually ever use the user’s token for anything other than logging them in. However to query team membership on your behalf, we now require [the `read:org` scope][oauth-scopes]. You are free to deny us this scope, and everything that worked before teams were introduced will keep working. However you will never be able to add a team as an owner, or publish a crate as a team owner. If you ever attempt to do this, you will get the error above. You may also see this error if you ever try to publish a crate that you don’t own at all, but otherwise happens to have a team. If you ever change your mind, or just aren’t sure if [crates.io] has sufficient permission, you can always go to and re-authenticate, which will prompt you for permission if [crates.io] doesn’t have all the scopes it would like to. An additional barrier to querying GitHub is that the organization may be actively denying third party access. To check this, you can go to: ```text https://github.com/organizations/:org/settings/oauth_application_policy ``` where `:org` is the name of the organization (e.g., `rust-lang`). You may see something like: ![Organization Access Control](../images/org-level-acl.png) Where you may choose to explicitly remove [crates.io] from your organization’s blacklist, or simply press the β€œRemove Restrictions” button to allow all third party applications to access this data. Alternatively, when [crates.io] requested the `read:org` scope, you could have explicitly whitelisted [crates.io] querying the org in question by pressing the β€œGrant Access” button next to its name: ![Authentication Access Control](../images/auth-level-acl.png) ### Troubleshooting GitHub team access errors When trying to add a GitHub team as crate owner, you may see an error like: ```text error: failed to invite owners to crate : api errors (status 200 OK): could not find the github team org/repo ``` In that case, you should go to [the GitHub Application settings page] and check if crates.io is listed in the `Authorized OAuth Apps` tab. If it isn't, you should go to and authorize it. Then go back to the Application Settings page on GitHub, click on the crates.io application in the list, and make sure you or your organization is listed in the "Organization access" list with a green check mark. If there's a button labeled `Grant` or `Request`, you should grant the access or request the org owner to do so. [Rust API Guidelines]: https://rust-lang.github.io/api-guidelines/ [`cargo login`]: ../commands/cargo-login.md [`cargo logout`]: ../commands/cargo-logout.md [`cargo package`]: ../commands/cargo-package.md [`cargo publish`]: ../commands/cargo-publish.md [`categories`]: manifest.md#the-categories-field [`description`]: manifest.md#the-description-field [`documentation`]: manifest.md#the-documentation-field [`homepage`]: manifest.md#the-homepage-field [`keywords`]: manifest.md#the-keywords-field [`license` or `license-file`]: manifest.md#the-license-and-license-file-fields [`readme`]: manifest.md#the-readme-field [`repository`]: manifest.md#the-repository-field [crates.io]: https://crates.io/ [oauth-scopes]: https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/ [the GitHub Application settings page]: https://github.com/settings/applications cargo-0.86.0/src/doc/src/reference/registries.md000064400000000000000000000131561046102023000176030ustar 00000000000000# Registries Cargo installs crates and fetches dependencies from a "registry". The default registry is [crates.io]. A registry contains an "index" which contains a searchable list of available crates. A registry may also provide a web API to support publishing new crates directly from Cargo. > Note: If you are interested in mirroring or vendoring an existing registry, > take a look at [Source Replacement]. If you are implementing a registry server, see [Running a Registry] for more details about the protocol between Cargo and a registry. If you're using a registry that requires authentication, see [Registry Authentication]. If you are implementing a credential provider, see [Credential Provider Protocol] for details. ## Using an Alternate Registry To use a registry other than [crates.io], the name and index URL of the registry must be added to a [`.cargo/config.toml` file][config]. The `registries` table has a key for each registry, for example: ```toml [registries] my-registry = { index = "https://my-intranet:8080/git/index" } ``` The `index` key should be a URL to a git repository with the registry's index or a Cargo sparse registry URL with the `sparse+` prefix. A crate can then depend on a crate from another registry by specifying the `registry` key and a value of the registry's name in that dependency's entry in `Cargo.toml`: ```toml # Sample Cargo.toml [package] name = "my-project" version = "0.1.0" edition = "2024" [dependencies] other-crate = { version = "1.0", registry = "my-registry" } ``` As with most config values, the index may be specified with an environment variable instead of a config file. For example, setting the following environment variable will accomplish the same thing as defining a config file: ```ignore CARGO_REGISTRIES_MY_REGISTRY_INDEX=https://my-intranet:8080/git/index ``` > Note: [crates.io] does not accept packages that depend on crates from other > registries. ## Publishing to an Alternate Registry If the registry supports web API access, then packages can be published directly to the registry from Cargo. Several of Cargo's commands such as [`cargo publish`] take a `--registry` command-line flag to indicate which registry to use. For example, to publish the package in the current directory: 1. `cargo login --registry=my-registry` This only needs to be done once. You must enter the secret API token retrieved from the registry's website. Alternatively the token may be passed directly to the `publish` command with the `--token` command-line flag or an environment variable with the name of the registry such as `CARGO_REGISTRIES_MY_REGISTRY_TOKEN`. 2. `cargo publish --registry=my-registry` Instead of always passing the `--registry` command-line option, the default registry may be set in [`.cargo/config.toml`][config] with the `registry.default` key. For example: ```toml [registry] default = "my-registry" ``` Setting the `package.publish` key in the `Cargo.toml` manifest restricts which registries the package is allowed to be published to. This is useful to prevent accidentally publishing a closed-source package to [crates.io]. The value may be a list of registry names, for example: ```toml [package] # ... publish = ["my-registry"] ``` The `publish` value may also be `false` to restrict all publishing, which is the same as an empty list. The authentication information saved by [`cargo login`] is stored in the `credentials.toml` file in the Cargo home directory (default `$HOME/.cargo`). It has a separate table for each registry, for example: ```toml [registries.my-registry] token = "854DvwSlUwEHtIo3kWy6x7UCPKHfzCmy" ``` ## Registry Protocols Cargo supports two remote registry protocols: `git` and `sparse`. If the registry index URL starts with `sparse+`, Cargo uses the sparse protocol. Otherwise Cargo uses the `git` protocol. The `git` protocol stores index metadata in a git repository and requires Cargo to clone the entire repo. The `sparse` protocol fetches individual metadata files using plain HTTP requests. Since Cargo only downloads the metadata for relevant crates, the `sparse` protocol can save significant time and bandwidth. The [crates.io] registry supports both protocols. The protocol for crates.io is controlled via the [`registries.crates-io.protocol`] config key. [Source Replacement]: source-replacement.md [Running a Registry]: running-a-registry.md [Credential Provider Protocol]: credential-provider-protocol.md [Registry Authentication]: registry-authentication.md [`cargo publish`]: ../commands/cargo-publish.md [`cargo package`]: ../commands/cargo-package.md [`cargo login`]: ../commands/cargo-login.md [config]: config.md [crates.io]: https://crates.io/ [`registries.crates-io.protocol`]: config.md#registriescrates-ioprotocol cargo-0.86.0/src/doc/src/reference/registry-authentication.md000064400000000000000000000110101046102023000222730ustar 00000000000000# Registry Authentication Cargo authenticates to registries with credential providers. These credential providers are external executables or built-in providers that Cargo uses to store and retrieve credentials. Using alternative registries with authentication *requires* a credential provider to be configured to avoid unknowingly storing unencrypted credentials on disk. For historical reasons, public (non-authenticated) registries do not require credential provider configuration, and the `cargo:token` provider is used if no providers are configured. Cargo also includes platform-specific providers that use the operating system to securely store tokens. The `cargo:token` provider is also included which stores credentials in unencrypted plain text in the [credentials](config.md#credentials) file. ## Recommended configuration It's recommended to configure a global credential provider list in `$CARGO_HOME/config.toml` which defaults to: * Windows: `%USERPROFILE%\.cargo\config.toml` * Unix: `~/.cargo/config.toml` This recommended configuration uses the operating system provider, with a fallback to `cargo:token` to look in Cargo's [credentials](config.md#credentials) file or environment variables: ```toml # ~/.cargo/config.toml [registry] global-credential-providers = ["cargo:token", "cargo:libsecret", "cargo:macos-keychain", "cargo:wincred"] ``` *Note that later entries have higher precedence. See [`registry.global-credential-providers`](config.md#registryglobal-credential-providers) for more details.* Some private registries may also recommend a registry-specific credential-provider. Check your registry's documentation to see if this is the case. ## Built-in providers Cargo includes several built-in credential providers. The available built-in providers may change in future Cargo releases (though there are currently no plans to do so). ### `cargo:token` Uses Cargo's [credentials](config.md#credentials) file to store tokens unencrypted in plain text. When retrieving tokens, checks the `CARGO_REGISTRIES__TOKEN` environment variable. If this credential provider is not listed, then the `*_TOKEN` environment variables will not work. ### `cargo:wincred` Uses the Windows Credential Manager to store tokens. The credentials are stored as `cargo-registry:` in the Credential Manager under "Windows Credentials". ### `cargo:macos-keychain` Uses the macOS Keychain to store tokens. The Keychain Access app can be used to view stored tokens. ### `cargo:libsecret` Uses [libsecret](https://wiki.gnome.org/Projects/Libsecret) to store tokens. Any password manager with libsecret support can be used to view stored tokens. The following are a few examples (non-exhaustive): - [GNOME Keyring](https://wiki.gnome.org/Projects/GnomeKeyring) - [KDE Wallet Manager](https://apps.kde.org/kwalletmanager5/) (since KDE Frameworks 5.97.0) - [KeePassXC](https://keepassxc.org/) (since 2.5.0) ### `cargo:token-from-stdout ` Launch a subprocess that returns a token on stdout. Newlines will be trimmed. * The process inherits the user's stdin and stderr. * It should exit 0 on success, and nonzero on error. * [`cargo login`] and [`cargo logout`] are not supported and return an error if used. The following environment variables will be provided to the executed command: * `CARGO` --- Path to the `cargo` binary executing the command. * `CARGO_REGISTRY_INDEX_URL` --- The URL of the registry index. * `CARGO_REGISTRY_NAME_OPT` --- Optional name of the registry. Should not be used as a lookup key. Arguments will be passed on to the subcommand. [`cargo login`]: ../commands/cargo-login.md [`cargo logout`]: ../commands/cargo-logout.md ## Credential plugins For credential provider plugins that follow Cargo's [credential provider protocol](credential-provider-protocol.md), the configuration value should be a string with the path to the executable (or the executable name if on the `PATH`). For example, to install [cargo-credential-1password](https://crates.io/crates/cargo-credential-1password) from crates.io do the following: Install the provider with `cargo install cargo-credential-1password` In the config, add to (or create) `registry.global-credential-providers`: ```toml [registry] global-credential-providers = ["cargo:token", "cargo-credential-1password --account my.1password.com"] ``` The values in `global-credential-providers` are split on spaces into path and command-line arguments. To define a global credential provider where the path or arguments contain spaces, use the [`[credential-alias]` table](config.md#credential-alias). cargo-0.86.0/src/doc/src/reference/registry-index.md000064400000000000000000000405401046102023000203750ustar 00000000000000# Index Format The following defines the format of the index. New features are occasionally added, which are only understood starting with the version of Cargo that introduced them. Older versions of Cargo may not be able to use packages that make use of new features. However, the format for older packages should not change, so older versions of Cargo should be able to use them. ## Index Configuration The root of the index contains a file named `config.json` which contains JSON information used by Cargo for accessing the registry. This is an example of what the [crates.io] config file looks like: ```javascript { "dl": "https://crates.io/api/v1/crates", "api": "https://crates.io" } ``` The keys are: - `dl`: This is the URL for downloading crates listed in the index. The value may have the following markers which will be replaced with their corresponding value: - `{crate}`: The name of crate. - `{version}`: The crate version. - `{prefix}`: A directory prefix computed from the crate name. For example, a crate named `cargo` has a prefix of `ca/rg`. See below for details. - `{lowerprefix}`: Lowercase variant of `{prefix}`. - `{sha256-checksum}`: The crate's sha256 checksum. If none of the markers are present, then the value `/{crate}/{version}/download` is appended to the end. - `api`: This is the base URL for the web API. This key is optional, but if it is not specified, commands such as [`cargo publish`] will not work. The web API is described below. - `auth-required`: indicates whether this is a private registry that requires all operations to be authenticated including API requests, crate downloads and sparse index updates. ## Download Endpoint The download endpoint should send the `.crate` file for the requested package. Cargo supports https, http, and file URLs, HTTP redirects, HTTP1 and HTTP2. The exact specifics of TLS support depend on the platform that Cargo is running on, the version of Cargo, and how it was compiled. If `auth-required: true` is set in `config.json`, the `Authorization` header will be included with http(s) download requests. ## Index files The rest of the index repository contains one file for each package, where the filename is the name of the package in lowercase. Each version of the package has a separate line in the file. The files are organized in a tier of directories: - Packages with 1 character names are placed in a directory named `1`. - Packages with 2 character names are placed in a directory named `2`. - Packages with 3 character names are placed in the directory `3/{first-character}` where `{first-character}` is the first character of the package name. - All other packages are stored in directories named `{first-two}/{second-two}` where the top directory is the first two characters of the package name, and the next subdirectory is the third and fourth characters of the package name. For example, `cargo` would be stored in a file named `ca/rg/cargo`. > Note: Although the index filenames are in lowercase, the fields that contain > package names in `Cargo.toml` and the index JSON data are case-sensitive and > may contain upper and lower case characters. The directory name above is calculated based on the package name converted to lowercase; it is represented by the marker `{lowerprefix}`. When the original package name is used without case conversion, the resulting directory name is represented by the marker `{prefix}`. For example, the package `MyCrate` would have a `{prefix}` of `My/Cr` and a `{lowerprefix}` of `my/cr`. In general, using `{prefix}` is recommended over `{lowerprefix}`, but there are pros and cons to each choice. Using `{prefix}` on case-insensitive filesystems results in (harmless-but-inelegant) directory aliasing. For example, `crate` and `CrateTwo` have `{prefix}` values of `cr/at` and `Cr/at`; these are distinct on Unix machines but alias to the same directory on Windows. Using directories with normalized case avoids aliasing, but on case-sensitive filesystems it's 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: - Only allows ASCII characters. - Only alphanumeric, `-`, and `_` characters. - First character must be alphabetic. - Case-insensitive collision detection. - Prevent differences of `-` vs `_`. - Under a specific length (max 64). - Rejects reserved names, such as Windows special filenames like "nul". Registries should consider incorporating similar restrictions, and consider the security implications, such as [IDN homograph 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. ```javascript { // The name of the package. // This must only contain alphanumeric, `-`, or `_` characters. "name": "foo", // The version of the package this row is describing. // This must be a valid version number according to the Semantic // Versioning 2.0.0 spec at https://semver.org/. "vers": "0.1.0", // Array of direct dependencies of the package. "deps": [ { // Name of the dependency. // If the dependency is renamed from the original package name, // this is the new name. The original package name is stored in // the `package` field. "name": "rand", // The SemVer requirement for this dependency. // This must be a valid version requirement defined at // https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html. "req": "^0.6", // Array of features (as strings) enabled for this dependency. // May be omitted since Cargo 1.84. "features": ["i128_support"], // Boolean of whether or not this is an optional dependency. // Since Cargo 1.84, defaults to `false` if not specified. "optional": false, // Boolean of whether or not default features are enabled. // Since Cargo 1.84, defaults to `true` if not specified. "default_features": true, // The target platform for the dependency. // If not specified or `null`, it is not a target dependency. // Otherwise, a string such as "cfg(windows)". "target": null, // The dependency kind. // "dev", "build", or "normal". // If not specified or `null`, it defaults to "normal". "kind": "normal", // The URL of the index of the registry where this dependency is // from as a string. If not specified or `null`, it is assumed the // dependency is in the current registry. "registry": null, // If the dependency is renamed, this is a string of the actual // package name. If not specified or `null`, this dependency is not // renamed. "package": null, } ], // A SHA256 checksum of the `.crate` file. "cksum": "d867001db0e2b6e0496f9fac96930e2d42233ecd3ca0413e0753d4c7695d289c", // Set of features defined for the package. // Each feature maps to an array of features or dependencies it enables. // May be omitted since Cargo 1.84. "features": { "extras": ["rand/simd_support"] }, // Boolean of whether or not this version has been yanked. "yanked": false, // The `links` string value from the package's manifest, or null if not // specified. This field is optional and defaults to null. "links": null, // An unsigned 32-bit integer value indicating the schema version of this // entry. // // If this is not specified, it should be interpreted as the default of 1. // // Cargo (starting with version 1.51) will ignore versions it does not // recognize. 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. Versions older than 1.51 ignore this field, and // thus may misinterpret the meaning of the index entry. // // The current values are: // // * 1: The schema as documented here, not including newer additions. // This is honored in Rust version 1.51 and newer. // * 2: The addition of the `features2` field. // This is honored in Rust version 1.60 and newer. "v": 2, // This optional 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. // // Cargo will merge any values listed here with the "features" field. // // If this field is included, the "v" field should be set to at least 2. // // Registries are not required to use this field for extended feature // syntax, they are allowed to include those in the "features" field. // Using this is only necessary if the registry wants to support cargo // versions older than 1.19, which in practice is only crates.io since // those older versions do not support other registries. "features2": { "serde": ["dep:serde", "chrono?/serde"] } // The minimal supported Rust version (optional) // This must be a valid version requirement without an operator (e.g. no `=`) "rust_version": "1.60" } ``` The JSON objects should not be modified after they are added except for the `yanked` field whose value may change at any time. > **Note**: The index JSON format has subtle differences from the JSON format of the [Publish API] and [`cargo metadata`]. > If you are using one of those as a source to generate index entries, you are encouraged to carefully inspect the documentation differences between them. > > For the [Publish API], the differences are: > > * `deps` > * `name` --- When the dependency is [renamed] in `Cargo.toml`, the publish API puts the original package name in the `name` field and the aliased name in the `explicit_name_in_toml` field. > The index places the aliased name in the `name` field, and the original package name in the `package` field. > * `req` --- The Publish API field is called `version_req`. > * `cksum` --- The publish API does not specify the checksum, it must be computed by the registry before adding to the index. > * `features` --- Some features may be placed in the `features2` field. > Note: This is only a legacy requirement for [crates.io]; other registries should not need to bother with modifying the features map. > The `v` field indicates the presence of the `features2` field. > * The publish API includes several other fields, such as `description` and `readme`, which don't appear in the index. > These are intended to make it easier for a registry to obtain the metadata about the crate to display on a website without needing to extract and parse the `.crate` file. > This additional information is typically added to a database on the registry server. > * Although `rust_version` is included here, [crates.io] will ignore this field > and instead read it from the `Cargo.toml` contained in the `.crate` file. > > For [`cargo metadata`], the differences are: > > * `vers` --- The `cargo metadata` field is called `version`. > * `deps` > * `name` --- When the dependency is [renamed] in `Cargo.toml`, `cargo metadata` puts the original package name in the `name` field and the aliased name in the `rename` field. > The index places the aliased name in the `name` field, and the original package name in the `package` field. > * `default_features` --- The `cargo metadata` field is called `uses_default_features`. > * `registry` --- `cargo metadata` uses a value of `null` to indicate that the dependency comes from [crates.io]. > The index uses a value of `null` to indicate that the dependency comes from the same registry as the index. > When creating an index entry, a registry other than [crates.io] should translate a value of `null` to be `https://github.com/rust-lang/crates.io-index` and translate a URL that matches the current index to be `null`. > * `cargo metadata` includes some extra fields, such as `source` and `path`. > * The index includes additional fields such as `yanked`, `cksum`, and `v`. [renamed]: specifying-dependencies.md#renaming-dependencies-in-cargotoml [Publish API]: registry-web-api.md#publish [`cargo metadata`]: ../commands/cargo-metadata.md ## Index Protocols Cargo supports two remote registry protocols: `git` and `sparse`. The `git` protocol stores index files in a git repository and the `sparse` protocol fetches individual files over HTTP. ### Git Protocol The git protocol has no protocol prefix in the index url. For example the git index URL for [crates.io] is `https://github.com/rust-lang/crates.io-index`. Cargo caches the git repository on disk so that it can efficiently incrementally fetch updates. ### Sparse Protocol The sparse protocol uses the `sparse+` protocol prefix in the registry URL. For example, the sparse index URL for [crates.io] is `sparse+https://index.crates.io/`. The sparse protocol downloads each index file using an individual HTTP request. Since this results in a large number of small HTTP requests, performance is significantly improved with a server that supports pipelining and HTTP/2. #### Sparse authentication Cargo will attempt to fetch the `config.json` file before fetching any other files. If the server responds with an HTTP 401, then Cargo will assume that the registry requires authentication and re-attempt the request for `config.json` with the authentication token included. On authentication failure (or a missing authentication token) the server may include a `www-authenticate` header with a `Cargo login_url=""` challenge to indicate where the user can go to get a token. Registries that require authentication must set `auth-required: true` in `config.json`. #### Caching Cargo caches the crate metadata files, and captures the `ETag` or `Last-Modified` HTTP header from the server for each entry. When refreshing crate metadata, Cargo sends the `If-None-Match` or `If-Modified-Since` header to allow the server to respond with HTTP 304 "Not Modified" if the local cache is valid, saving time and bandwidth. If both `ETag` and `Last-Modified` headers are present, Cargo uses the `ETag` only. #### Cache Invalidation If a registry is using some kind of CDN or proxy which caches access to the index files, then it is recommended that registries implement some form of cache invalidation when the files are updated. If these caches are not updated, then users may not be able to access new crates until the cache is cleared. #### Nonexistent Crates For crates that do not exist, the registry should respond with a 404 "Not Found", 410 "Gone" or 451 "Unavailable For Legal Reasons" code. #### Sparse Limitations Since the URL of the registry is stored in the lockfile, it's not recommended to offer a registry with both protocols. Discussion about a transition plan is ongoing in issue [#10964]. The [crates.io] registry is an exception, since Cargo internally substitutes the equivalent git URL when the sparse protocol is used. If a registry does offer both protocols, it's currently recommended to choose one protocol as the canonical protocol and use [source replacement] for the other protocol. [`cargo publish`]: ../commands/cargo-publish.md [alphanumeric]: ../../std/primitive.char.html#method.is_alphanumeric [crates.io]: https://crates.io/ [source replacement]: ../reference/source-replacement.md [#10964]: https://github.com/rust-lang/cargo/issues/10964 cargo-0.86.0/src/doc/src/reference/registry-web-api.md000064400000000000000000000267641046102023000206260ustar 00000000000000# Web API A registry may host a web API at the location defined in `config.json` to support any of the actions listed below. Cargo includes the `Authorization` header for requests that require authentication. The header value is the API token. The server should respond with a 403 response code if the token is not valid. Users are expected to visit the registry's website to obtain a token, and Cargo can store the token using the [`cargo login`] command, or by passing the token on the command-line. Responses use a 2xx response code for success. Errors should use an appropriate response code, such as 404. Failure responses should have a JSON object with the following structure: ```javascript { // Array of errors to display to the user. "errors": [ { // The error message as a string. "detail": "error message text" } ] } ``` If the response has this structure Cargo will display the detailed message to the user, even if the response code is 200. If the response code indicates an error and the content does not have this structure, Cargo will display to the user a message intended to help debugging the server error. A server returning an `errors` object allows a registry to provide a more detailed or user-centric error message. For backwards compatibility, servers should ignore any unexpected query parameters or JSON fields. If a JSON field is missing, it should be assumed to be null. The endpoints are versioned with the `v1` component of the path, and Cargo is responsible for handling backwards compatibility fallbacks should any be required in the future. Cargo sets the following headers for all requests: - `Content-Type`: `application/json` (for requests with a body payload) - `Accept`: `application/json` - `User-Agent`: The Cargo version such as `cargo/1.32.0 (8610973aa 2019-01-02)`. This may be modified by the user in a configuration value. Added in 1.29. ## Publish - Endpoint: `/api/v1/crates/new` - Method: PUT - Authorization: Included The publish endpoint is used to publish a new version of a crate. The server should validate the crate, make it available for download, and add it to the index. It is not required for the index to be updated before the successful response is sent. After a successful response, Cargo will poll the index for a short period of time to identify that the new crate has been added. If the crate does not appear in the index after a short period of time, then Cargo will display a warning letting the user know that the new crate is not yet available. The body of the data sent by Cargo is: - 32-bit unsigned little-endian integer of the length of JSON data. - Metadata of the package as a JSON object. - 32-bit unsigned little-endian integer of the length of the `.crate` file. - The `.crate` file. The following is a commented example of the JSON object. Some notes of some restrictions imposed by [crates.io] are included only to illustrate some suggestions on types of validation that may be done, and should not be considered as an exhaustive list of restrictions [crates.io] imposes. ```javascript { // The name of the package. "name": "foo", // The version of the package being published. "vers": "0.1.0", // Array of direct dependencies of the package. "deps": [ { // Name of the dependency. // If the dependency is renamed from the original package name, // this is the original name. The new package name is stored in // the `explicit_name_in_toml` field. "name": "rand", // The semver requirement for this dependency. "version_req": "^0.6", // Array of features (as strings) enabled for this dependency. "features": ["i128_support"], // Boolean of whether or not this is an optional dependency. "optional": false, // Boolean of whether or not default features are enabled. "default_features": true, // The target platform for the dependency. // null if not a target dependency. // Otherwise, a string such as "cfg(windows)". "target": null, // The dependency kind. // "dev", "build", or "normal". "kind": "normal", // The URL of the index of the registry where this dependency is // from as a string. If not specified or null, it is assumed the // dependency is in the current registry. "registry": null, // If the dependency is renamed, this is a string of the new // package name. If not specified or null, this dependency is not // renamed. "explicit_name_in_toml": null, } ], // Set of features defined for the package. // Each feature maps to an array of features or dependencies it enables. // Cargo does not impose limitations on feature names, but crates.io // requires alphanumeric ASCII, `_` or `-` characters. "features": { "extras": ["rand/simd_support"] }, // List of strings of the authors. // May be empty. "authors": ["Alice "], // Description field from the manifest. // May be null. crates.io requires at least some content. "description": null, // String of the URL to the website for this package's documentation. // May be null. "documentation": null, // String of the URL to the website for this package's home page. // May be null. "homepage": null, // String of the content of the README file. // May be null. "readme": null, // String of a relative path to a README file in the crate. // May be null. "readme_file": null, // Array of strings of keywords for the package. "keywords": [], // Array of strings of categories for the package. "categories": [], // String of the license for the package. // May be null. crates.io requires either `license` or `license_file` to be set. "license": null, // String of a relative path to a license file in the crate. // May be null. "license_file": null, // String of the URL to the website for the source repository of this package. // May be null. "repository": null, // Optional object of "status" badges. Each value is an object of // arbitrary string to string mappings. // crates.io has special interpretation of the format of the badges. "badges": { "travis-ci": { "branch": "master", "repository": "rust-lang/cargo" } }, // The `links` string value from the package's manifest, or null if not // specified. This field is optional and defaults to null. "links": null, // The minimal supported Rust version (optional) // This must be a valid version requirement without an operator (e.g. no `=`) "rust_version": null } ``` A successful response includes the JSON object: ```javascript { // Optional object of warnings to display to the user. "warnings": { // Array of strings of categories that are invalid and ignored. "invalid_categories": [], // Array of strings of badge names that are invalid and ignored. "invalid_badges": [], // Array of strings of arbitrary warnings to display to the user. "other": [] } } ``` ## Yank - Endpoint: `/api/v1/crates/{crate_name}/{version}/yank` - Method: DELETE - Authorization: Included The yank endpoint will set the `yank` field of the given version of a crate to `true` in the index. A successful response includes the JSON object: ```javascript { // Indicates the yank succeeded, always true. "ok": true, } ``` ## Unyank - Endpoint: `/api/v1/crates/{crate_name}/{version}/unyank` - Method: PUT - Authorization: Included The unyank endpoint will set the `yank` field of the given version of a crate to `false` in the index. A successful response includes the JSON object: ```javascript { // Indicates the unyank succeeded, always true. "ok": true, } ``` ## Owners Cargo does not have an inherent notion of users and owners, but it does provide the `owner` command to assist managing who has authorization to control a crate. It is up to the registry to decide exactly how users and owners are handled. See the [publishing documentation] for a description of how [crates.io] handles owners via GitHub users and teams. ### Owners: List - Endpoint: `/api/v1/crates/{crate_name}/owners` - Method: GET - Authorization: Included The owners endpoint returns a list of owners of the crate. A successful response includes the JSON object: ```javascript { // Array of owners of the crate. "users": [ { // Unique unsigned 32-bit integer of the owner. "id": 70, // The unique username of the owner. "login": "github:rust-lang:core", // Name of the owner. // This is optional and may be null. "name": "Core", } ] } ``` ### Owners: Add - Endpoint: `/api/v1/crates/{crate_name}/owners` - Method: PUT - Authorization: Included A PUT request will send a request to the registry to add a new owner to a crate. It is up to the registry how to handle the request. For example, [crates.io] sends an invite to the user that they must accept before being added. The request should include the following JSON object: ```javascript { // Array of `login` strings of owners to add. "users": ["login_name"] } ``` A successful response includes the JSON object: ```javascript { // Indicates the add succeeded, always true. "ok": true, // A string to be displayed to the user. "msg": "user ehuss has been invited to be an owner of crate cargo" } ``` ### Owners: Remove - Endpoint: `/api/v1/crates/{crate_name}/owners` - Method: DELETE - Authorization: Included A DELETE request will remove an owner from a crate. The request should include the following JSON object: ```javascript { // Array of `login` strings of owners to remove. "users": ["login_name"] } ``` A successful response includes the JSON object: ```javascript { // Indicates the remove succeeded, always true. "ok": true // A string to be displayed to the user. Currently ignored by cargo. "msg": "owners successfully removed", } ``` ## Search - Endpoint: `/api/v1/crates` - Method: GET - Query Parameters: - `q`: The search query string. - `per_page`: Number of results, default 10, max 100. The search request will perform a search for crates, using criteria defined on the server. A successful response includes the JSON object: ```javascript { // Array of results. "crates": [ { // Name of the crate. "name": "rand", // The highest version available. "max_version": "0.6.1", // Textual description of the crate. "description": "Random number generators and other randomness functionality.\n", } ], "meta": { // Total number of results available on the server. "total": 119 } } ``` ## Login - Endpoint: `/me` The "login" endpoint is not an actual API request. It exists solely for the [`cargo login`] command to display a URL to instruct a user to visit in a web browser to log in and retrieve an API token. [`cargo login`]: ../commands/cargo-login.md [`cargo package`]: ../commands/cargo-package.md [`cargo publish`]: ../commands/cargo-publish.md [alphanumeric]: ../../std/primitive.char.html#method.is_alphanumeric [config]: config.md [crates.io]: https://crates.io/ [publishing documentation]: publishing.md#cargo-owner cargo-0.86.0/src/doc/src/reference/resolver.md000064400000000000000000000733121046102023000172640ustar 00000000000000# Dependency Resolution One of Cargo's primary tasks is to determine the versions of dependencies to use based on the version requirements specified in each package. This process is called "dependency resolution" and is performed by the "resolver". The result of the resolution is stored in the `Cargo.lock` file which "locks" the dependencies to specific versions, and keeps them fixed over time. The [`cargo tree`] command can be used to visualize the result of the resolver. [dependency specifications]: specifying-dependencies.md [dependency specification]: specifying-dependencies.md [`cargo tree`]: ../commands/cargo-tree.md ## Constraints and Heuristics In many cases there is no single "best" dependency resolution. The resolver operates under various constraints and heuristics to find a generally applicable resolution. To understand how these interact, it is helpful to have a coarse understanding of how dependency resolution works. This pseudo-code approximates what Cargo's resolver does: ```rust pub fn resolve(workspace: &[Package], policy: Policy) -> Option { let dep_queue = Queue::new(workspace); let resolved = ResolveGraph::new(); resolve_next(pkq_queue, resolved, policy) } fn resolve_next(dep_queue: Queue, resolved: ResolveGraph, policy: Policy) -> Option { let Some(dep_spec) = policy.pick_next_dep(dep_queue) else { // Done return Some(resolved); }; if let Some(resolved) = policy.try_unify_version(dep_spec, resolved.clone()) { return Some(resolved); } let dep_versions = dep_spec.lookup_versions()?; let mut dep_versions = policy.filter_versions(dep_spec, dep_versions); while let Some(dep_version) = policy.pick_next_version(&mut dep_versions) { if policy.needs_version_unification(dep_version, &resolved) { continue; } let mut dep_queue = dep_queue.clone(); dep_queue.enqueue(dep_version.dependencies); let mut resolved = resolved.clone(); resolved.register(dep_version); if let Some(resolved) = resolve_next(dep_queue, resolved) { return Some(resolved); } } // No valid solution found, backtrack and `pick_next_version` None } ``` Key steps: - Walking dependencies (`pick_next_dep`): The order dependencies are walked can affect how related version requirements for the same dependency get resolved, see unifying versions, and how much the resolver backtracks, affecting resolver performance, - Unifying versions (`try_unify_version`, `needs_version_unification`): Cargo reuses versions where possible to reduce build times and allow types from common dependencies to be passed between APIs. If multiple versions would have been unified if it wasn't for conflicts in their [dependency specifications], Cargo will backtrack, erroring if no solution is found, rather than selecting multiple versions. A [dependency specification] or Cargo may decide that a version is undesirable, preferring to backtrack or error rather than use it. - Preferring versions (`pick_next_version`): Cargo may decide that it should prefer a specific version, falling back to the next version when backtracking. ### Version numbers Generally, Cargo prefers the highest version currently available. For example, if you had a package in the resolve graph with: ```toml [dependencies] bitflags = "*" ``` If at the time the `Cargo.lock` file is generated, the greatest version of `bitflags` is `1.2.1`, then the package will use `1.2.1`. For an example of a possible exception, see [Rust version](#rust-version). ### Version requirements Package specify what versions they support, rejecting all others, through [version requirements]. For example, if you had a package in the resolve graph with: ```toml [dependencies] bitflags = "1.0" # meaning `>=1.0.0,<2.0.0` ``` If at the time the `Cargo.lock` file is generated, the greatest version of `bitflags` is `1.2.1`, then the package will use `1.2.1` because it is the greatest within the compatibility range. If `2.0.0` is published, it will still use `1.2.1` because `2.0.0` is considered incompatible. [version requirements]: specifying-dependencies.md#version-requirement-syntax ### SemVer compatibility Cargo assumes packages follow [SemVer] and will unify dependency versions if they are [SemVer] compatible according to the [Caret version requirements]. If two compatible versions cannot be unified because of conflicting version requirements, Cargo will error. See the [SemVer Compatibility] chapter for guidance on what is considered a "compatible" change. Examples: The following two packages will have their dependencies on `bitflags` unified because any version picked will be compatible with each other. ```toml # Package A [dependencies] bitflags = "1.0" # meaning `>=1.0.0,<2.0.0` # Package B [dependencies] bitflags = "1.1" # meaning `>=1.1.0,<2.0.0` ``` The following packages will error because the version requirements conflict, selecting two distinct compatible versions. ```toml # Package A [dependencies] log = "=0.4.11" # Package B [dependencies] log = "=0.4.8" ``` The following two packages will not have their dependencies on `rand` unified because only incompatible versions are available for each. Instead, two different versions (e.g. 0.6.5 and 0.7.3) will be resolved and built. This can lead to potential problems, see the [Version-incompatibility hazards] section for more details. ```toml # Package A [dependencies] rand = "0.7" # meaning `>=0.7.0,<0.8.0` # Package B [dependencies] rand = "0.6" # meaning `>=0.6.0,<0.7.0` ``` Generally, the following two packages will not have their dependencies unified because incompatible versions are available that satisfy the version requirements: Instead, two different versions (e.g. 0.6.5 and 0.7.3) will be resolved and built. The application of other constraints or heuristics may cause these to be unified, picking one version (e.g. 0.6.5). ```toml # Package A [dependencies] rand = ">=0.6,<0.8.0" # Package B [dependencies] rand = "0.6" # meaning `>=0.6.0,<0.7.0` ``` [SemVer]: https://semver.org/ [SemVer Compatibility]: semver.md [Caret version requirements]: specifying-dependencies.md#default-requirements [Version-incompatibility hazards]: #version-incompatibility-hazards #### Version-incompatibility hazards When multiple versions of a crate appear in the resolve graph, this can cause problems when types from those crates are exposed by the crates using them. This is because the types and items are considered different by the Rust compiler, even if they have the same name. Libraries should take care when publishing a SemVer-incompatible version (for example, publishing `2.0.0` after `1.0.0` has been in use), particularly for libraries that are widely used. The "[semver trick]" is a workaround for this problem of publishing a breaking change while retaining compatibility with older versions. The linked page goes into detail about what the problem is and how to address it. In short, when a library wants to publish a SemVer-breaking release, publish the new release, and also publish a point release of the previous version that reexports the types from the newer version. These incompatibilities usually manifest as a compile-time error, but sometimes they will only appear as a runtime misbehavior. For example, let's say there is a common library named `foo` that ends up appearing with both version `1.0.0` and `2.0.0` in the resolve graph. If [`downcast_ref`] is used on a object created by a library using version `1.0.0`, and the code calling `downcast_ref` is downcasting to a type from version `2.0.0`, the downcast will fail at runtime. It is important to make sure that if you have multiple versions of a library that you are properly using them, especially if it is ever possible for the types from different versions to be used together. The [`cargo tree -d`][`cargo tree`] command can be used to identify duplicate versions and where they come from. Similarly, it is important to consider the impact on the ecosystem if you publish a SemVer-incompatible version of a popular library. [semver trick]: https://github.com/dtolnay/semver-trick [`downcast_ref`]: ../../std/any/trait.Any.html#method.downcast_ref ### Rust version To support developing software with a minimum supported [Rust version], the resolver can take into account a dependency version's compatibility with your Rust version. This is controlled by the config field [`resolver.incompatible-rust-versions`]. With the `fallback` setting, the resolver will prefer packages with a Rust version that is equal to or greater than your own Rust version. For example, you are using Rust 1.85 to develop the following package: ```toml [package] name = "my-cli" rust-version = "1.62" [dependencies] clap = "4.0" # resolves to 4.0.32 ``` The resolver would pick version 4.0.32 because it has a Rust version of 1.60.0. - 4.0.0 is not picked because it is a [lower version number](#version-numbers) despite it also having a Rust version of 1.60.0. - 4.5.20 is not picked because it is incompatible with `my-cli`'s Rust version of 1.62 despite having a much [higher version](#version-numbers) and it has a Rust version of 1.74.0 which is compatible with your 1.85 toolchain. If a version requirement does not include a Rust version compatible dependency version, the resolver won't error but will instead pick a version, even if its potentially suboptimal. For example, you change the dependency on `clap`: ```toml [package] name = "my-cli" rust-version = "1.62" [dependencies] clap = "4.2" # resolves to 4.5.20 ``` No version of `clap` matches that [version requirement](#version-requirements) that is compatible with Rust version 1.62. The resolver will then pick an incompatible version, like 4.5.20 despite it having a Rust version of 1.74. When the resolver selects a dependency version of a package, it does not know all the workspace members that will eventually have a transitive dependency on that version and so it cannot take into account only the Rust versions relevant for that dependency. The resolver has heuristics to find a "good enough" solution when workspace members have different Rust versions. This applies even for packages in a workspace without a Rust version. When a workspace has members with different Rust versions, the resolver may pick a lower dependency version than necessary. For example, you have the following workspace members: ```toml [package] name = "a" rust-version = "1.62" [package] name = "b" [dependencies] clap = "4.2" # resolves to 4.5.20 ``` Though package `b` does not have a Rust version and could use a higher version like 4.5.20, 4.0.32 will be selected because of package `a`'s Rust version of 1.62. Or the resolver may pick too high of a version. For example, you have the following workspace members: ```toml [package] name = "a" rust-version = "1.62" [dependencies] clap = "4.2" # resolves to 4.5.20 [package] name = "b" [dependencies] clap = "4.5" # resolves to 4.5.20 ``` Though each package has a version requirement for `clap` that would meet its own Rust version, because of [version unification](#version-numbers), the resolver will need to pick one version that works in both cases and that would be a version like 4.5.20. [Rust version]: rust-version.md [`resolver.incompatible-rust-versions`]: config.md#resolverincompatible-rust-versions ### Features For the purpose of generating `Cargo.lock`, the resolver builds the dependency graph as-if all [features] of all [workspace] members are enabled. This ensures that any optional dependencies are available and properly resolved with the rest of the graph when features are added or removed with the [`--features` command-line flag](features.md#command-line-feature-options). The resolver runs a second time to determine the actual features used when *compiling* a crate, based on the features selected on the command-line. Dependencies are resolved with the union of all features enabled on them. For example, if one package depends on the [`im`] package with the [`serde` dependency] enabled and another package depends on it with the [`rayon` dependency] enabled, then `im` will be built with both features enabled, and the `serde` and `rayon` crates will be included in the resolve graph. If no packages depend on `im` with those features, then those optional dependencies will be ignored, and they will not affect resolution. When building multiple packages in a workspace (such as with `--workspace` or multiple `-p` flags), the features of the dependencies of all of those packages are unified. If you have a circumstance where you want to avoid that unification for different workspace members, you will need to build them via separate `cargo` invocations. The resolver will skip over versions of packages that are missing required features. For example, if a package depends on version `^1` of [`regex`] with the [`perf` feature], then the oldest version it can select is `1.3.0`, because versions prior to that did not contain the `perf` feature. Similarly, if a feature is removed from a new release, then packages that require that feature will be stuck on the older releases that contain that feature. It is discouraged to remove features in a SemVer-compatible release. Beware that optional dependencies also define an implicit feature, so removing an optional dependency or making it non-optional can cause problems, see [removing an optional dependency]. [`im`]: https://crates.io/crates/im [`perf` feature]: https://github.com/rust-lang/regex/blob/1.3.0/Cargo.toml#L56 [`rayon` dependency]: https://github.com/bodil/im-rs/blob/v15.0.0/Cargo.toml#L47 [`regex`]: https://crates.io/crates/regex [`serde` dependency]: https://github.com/bodil/im-rs/blob/v15.0.0/Cargo.toml#L46 [features]: features.md [removing an optional dependency]: semver.md#cargo-remove-opt-dep [workspace]: workspaces.md #### Feature resolver version 2 When `resolver = "2"` is specified in `Cargo.toml` (see [resolver versions](#resolver-versions) below), a different feature resolver is used which uses a different algorithm for unifying features. The version `"1"` resolver will unify features for a package no matter where it is specified. The version `"2"` resolver will avoid unifying features in the following situations: * Features for target-specific dependencies are not enabled if the target is not currently being built. For example: ```toml [dependencies.common] version = "1.0" features = ["f1"] [target.'cfg(windows)'.dependencies.common] version = "1.0" features = ["f2"] ``` When building this example for a non-Windows platform, the `f2` feature will *not* be enabled. * Features enabled on [build-dependencies] or proc-macros will not be unified when those same dependencies are used as a normal dependency. For example: ```toml [dependencies] log = "0.4" [build-dependencies] log = {version = "0.4", features=['std']} ``` When building the build script, the `log` crate will be built with the `std` feature. When building the library of your package, it will not enable the feature. * Features enabled on [dev-dependencies] will not be unified when those same dependencies are used as a normal dependency, unless those dev-dependencies are currently being built. For example: ```toml [dependencies] serde = {version = "1.0", default-features = false} [dev-dependencies] serde = {version = "1.0", features = ["std"]} ``` In this example, the library will normally link against `serde` without the `std` feature. However, when built as a test or example, it will include the `std` feature. For example, `cargo test` or `cargo build --all-targets` will unify these features. Note that dev-dependencies in dependencies are always ignored, this is only relevant for the top-level package or workspace members. [build-dependencies]: specifying-dependencies.md#build-dependencies [dev-dependencies]: specifying-dependencies.md#development-dependencies [resolver-field]: features.md#resolver-versions ### `links` The [`links` field] is used to ensure only one copy of a native library is linked into a binary. The resolver will attempt to find a graph where there is only one instance of each `links` name. If it is unable to find a graph that satisfies that constraint, it will return an error. For example, it is an error if one package depends on [`libgit2-sys`] version `0.11` and another depends on `0.12`, because Cargo is unable to unify those, but they both link to the `git2` native library. Due to this requirement, it is encouraged to be very careful when making SemVer-incompatible releases with the `links` field if your library is in common use. [`links` field]: manifest.md#the-links-field [`libgit2-sys`]: https://crates.io/crates/libgit2-sys ### Yanked versions [Yanked releases][yank] are those that are marked that they should not be used. When the resolver is building the graph, it will ignore all yanked releases unless they already exist in the `Cargo.lock` file or are explicitly requested by the [`--precise`] flag of `cargo update` (nightly only). [yank]: publishing.md#cargo-yank [`--precise`]: ../commands/cargo-update.md#option-cargo-update---precise ## Dependency updates Dependency resolution is automatically performed by all Cargo commands that need to know about the dependency graph. For example, [`cargo build`] will run the resolver to discover all the dependencies to build. After the first time it runs, the result is stored in the `Cargo.lock` file. Subsequent commands will run the resolver, keeping dependencies locked to the versions in `Cargo.lock` *if it can*. If the dependency list in `Cargo.toml` has been modified, for example changing the version of a dependency from `1.0` to `2.0`, then the resolver will select a new version for that dependency that matches the new requirements. If that new dependency introduces new requirements, those new requirements may also trigger additional updates. The `Cargo.lock` file will be updated with the new result. The `--locked` or `--frozen` flags can be used to change this behavior to prevent automatic updates when requirements change, and return an error instead. [`cargo update`] can be used to update the entries in `Cargo.lock` when new versions are published. Without any options, it will attempt to update all packages in the lock file. The `-p` flag can be used to target the update for a specific package, and other flags such as `--recursive` or `--precise` can be used to control how versions are selected. [`cargo build`]: ../commands/cargo-build.md [`cargo update`]: ../commands/cargo-update.md ## Overrides Cargo has several mechanisms to override dependencies within the graph. The [Overriding Dependencies] chapter goes into detail on how to use overrides. The overrides appear as an overlay to a registry, replacing the patched version with the new entry. Otherwise, resolution is performed like normal. [Overriding Dependencies]: overriding-dependencies.md ## Dependency kinds There are three kinds of dependencies in a package: normal, [build], and [dev][dev-dependencies]. For the most part these are all treated the same from the perspective of the resolver. One difference is that dev-dependencies for non-workspace members are always ignored, and do not influence resolution. [Platform-specific dependencies] with the `[target]` table are resolved as-if all platforms are enabled. In other words, the resolver ignores the platform or `cfg` expression. [build]: specifying-dependencies.md#build-dependencies [dev-dependencies]: specifying-dependencies.md#development-dependencies [Platform-specific dependencies]: specifying-dependencies.md#platform-specific-dependencies ### dev-dependency cycles Usually the resolver does not allow cycles in the graph, but it does allow them for [dev-dependencies]. For example, project "foo" has a dev-dependency on "bar", which has a normal dependency on "foo" (usually as a "path" dependency). This is allowed because there isn't really a cycle from the perspective of the build artifacts. In this example, the "foo" library is built (which does not need "bar" because "bar" is only used for tests), and then "bar" can be built depending on "foo", then the "foo" tests can be built linking to "bar". Beware that this can lead to confusing errors. In the case of building library unit tests, there are actually two copies of the library linked into the final test binary: the one that was linked with "bar", and the one built that contains the unit tests. Similar to the issues highlighted in the [Version-incompatibility hazards] section, the types between the two are not compatible. Be careful when exposing types of "foo" from "bar" in this situation, since the "foo" unit tests won't treat them the same as the local types. If possible, try to split your package into multiple packages and restructure it so that it remains strictly acyclic. ## Resolver versions Different resolver behavior can be specified through the resolver version in `Cargo.toml` like this: ```toml [package] name = "my-package" version = "1.0.0" resolver = "2" ``` - `"1"` (default) - `"2"` ([`edition = "2021"`](manifest.md#the-edition-field) default): Introduces changes in [feature unification](#features). See the [features chapter][features-2] for more details. - `"3"` ([`edition = "2024"`](manifest.md#the-edition-field) default, requires Rust 1.84+): Change the default for [`resolver.incompatible-rust-versions`] from `allow` to `fallback` The resolver is a global option that affects the entire workspace. The `resolver` version in dependencies is ignored, only the value in the top-level package will be used. If using a [virtual workspace], the version should be specified in the `[workspace]` table, for example: ```toml [workspace] members = ["member1", "member2"] resolver = "2" ``` > **MSRV:** Requires 1.51+ [virtual workspace]: workspaces.md#virtual-workspace [features-2]: features.md#feature-resolver-version-2 ## Recommendations The following are some recommendations for setting the version within your package, and for specifying dependency requirements. These are general guidelines that should apply to common situations, but of course some situations may require specifying unusual requirements. * Follow the [SemVer guidelines] when deciding how to update your version number, and whether or not you will need to make a SemVer-incompatible version change. * Use caret requirements for dependencies, such as `"1.2.3"`, for most situations. This ensures that the resolver can be maximally flexible in choosing a version while maintaining build compatibility. * Specify all three components with the version you are currently using. This helps set the minimum version that will be used, and ensures that other users won't end up with an older version of the dependency that might be missing something that your package requires. * Avoid `*` requirements, as they are not allowed on [crates.io], and they can pull in SemVer-breaking changes during a normal `cargo update`. * Avoid overly broad version requirements. For example, `>=2.0.0` can pull in any SemVer-incompatible version, like version `5.0.0`, which can result in broken builds in the future. * Avoid overly narrow version requirements if possible. For example, if you specify a tilde requirement like `bar="~1.3"`, and another package specifies a requirement of `bar="1.4"`, this will fail to resolve, even though minor releases should be compatible. * Try to keep the dependency versions up-to-date with the actual minimum versions that your library requires. For example, if you have a requirement of `bar="1.0.12"`, and then in a future release you start using new features added in the `1.1.0` release of "bar", update your dependency requirement to `bar="1.1.0"`. If you fail to do this, it may not be immediately obvious because Cargo can opportunistically choose the newest version when you run a blanket `cargo update`. However, if another user depends on your library, and runs `cargo update your-library`, it will *not* automatically update "bar" if it is locked in their `Cargo.lock`. It will only update "bar" in that situation if the dependency declaration is also updated. Failure to do so can cause confusing build errors for the user using `cargo update your-library`. * If two packages are tightly coupled, then an `=` dependency requirement may help ensure that they stay in sync. For example, a library with a companion proc-macro library will sometimes make assumptions between the two libraries that won't work well if the two are out of sync (and it is never expected to use the two libraries independently). The parent library can use an `=` requirement on the proc-macro, and re-export the macros for easy access. * `0.0.x` versions can be used for packages that are permanently unstable. In general, the stricter you make the dependency requirements, the more likely it will be for the resolver to fail. Conversely, if you use requirements that are too loose, it may be possible for new versions to be published that will break the build. [SemVer guidelines]: semver.md [crates.io]: https://crates.io/ ## Troubleshooting The following illustrates some problems you may experience, and some possible solutions. ### Why was a dependency included? Say you see dependency `rand` in the `cargo check` output but don't think it's needed and want to understand why it's being pulled in. You can run ```console $ cargo tree --workspace --target all --all-features --invert rand rand v0.8.5 └── ... rand v0.8.5 └── ... ``` ### Why was that feature on this dependency enabled? You might identify that it was an activated feature that caused `rand` to show up. **To figure out which package activated the feature, you can add the `--edges features`** ```console $ cargo tree --workspace --target all --all-features --edges features --invert rand rand v0.8.5 └── ... rand v0.8.5 └── ... ``` ### Unexpected dependency duplication You see multiple instances of `rand` when you run ```console $ cargo tree --workspace --target all --all-features --duplicates rand v0.7.3 └── ... rand v0.8.5 └── ... ``` The resolver algorithm has converged on a solution that includes two copies of a dependency when one would suffice. For example: ```toml # Package A [dependencies] rand = "0.7" # Package B [dependencies] rand = ">=0.6" # note: open requirements such as this are discouraged ``` In this example, Cargo may build two copies of the `rand` crate, even though a single copy at version `0.7.3` would meet all requirements. This is because the resolver's algorithm favors building the latest available version of `rand` for Package B, which is `0.8.5` at the time of this writing, and that is incompatible with Package A's specification. The resolver's algorithm does not currently attempt to "deduplicate" in this situation. The use of open-ended version requirements like `>=0.6` is discouraged in Cargo. But, if you run into this situation, the [`cargo update`] command with the `--precise` flag can be used to manually remove such duplications. [`cargo update`]: ../commands/cargo-update.md ### Why wasn't a newer version selected? Say you noticed that the latest version of a dependency wasn't selected when you ran: ```console $ cargo update ``` You can enable some extra logging to see why this happened: ```console $ env CARGO_LOG=cargo::core::resolver=trace cargo update ``` **Note:** Cargo log targets and levels may change over time. ### SemVer-breaking patch release breaks the build Sometimes a project may inadvertently publish a point release with a SemVer-breaking change. When users update with `cargo update`, they will pick up this new release, and then their build may break. In this situation, it is recommended that the project should [yank] the release, and either remove the SemVer-breaking change, or publish it as a new SemVer-major version increase. If the change happened in a third-party project, if possible try to (politely!) work with the project to resolve the issue. While waiting for the release to be yanked, some workarounds depend on the circumstances: * If your project is the end product (such as a binary executable), just avoid updating the offending package in `Cargo.lock`. This can be done with the `--precise` flag in [`cargo update`]. * If you publish a binary on [crates.io], then you can temporarily add an `=` requirement to force the dependency to a specific good version. * Binary projects can alternatively recommend users to use the `--locked` flag with [`cargo install`] to use the original `Cargo.lock` that contains the known good version. * Libraries may also consider publishing a temporary new release with stricter requirements that avoid the troublesome dependency. You may want to consider using range requirements (instead of `=`) to avoid overly-strict requirements that may conflict with other packages using the same dependency. Once the problem has been resolved, you can publish another point release that relaxes the dependency back to a caret requirement. * If it looks like the third-party project is unable or unwilling to yank the release, then one option is to update your code to be compatible with the changes, and update the dependency requirement to set the minimum version to the new release. You will also need to consider if this is a SemVer-breaking change of your own library, for example if it exposes types from the dependency. [`cargo install`]: ../commands/cargo-install.md cargo-0.86.0/src/doc/src/reference/running-a-registry.md000064400000000000000000000016051046102023000211630ustar 00000000000000# Running a Registry A minimal registry can be implemented by having a git repository that contains an index, and a server that contains the compressed `.crate` files created by [`cargo package`]. Users won't be able to use Cargo to publish to it, but this may be sufficient for closed environments. The index format is described in [Registry Index]. A full-featured registry that supports publishing will additionally need to have a web API service that conforms to the API used by Cargo. The web API is described in [Registry Web API]. Commercial and community projects are available for building and running a registry. See for a list of what is available. [Registry Web API]: registry-web-api.md [Registry Index]: registry-index.md [`cargo publish`]: ../commands/cargo-publish.md [`cargo package`]: ../commands/cargo-package.md cargo-0.86.0/src/doc/src/reference/rust-version.md000064400000000000000000000210551046102023000201000ustar 00000000000000# Rust Version The `rust-version` field is an optional key that tells cargo what version of the Rust toolchain you support for your package. ```toml [package] # ... rust-version = "1.56" ``` The Rust version must be a bare version number with at least one component; it cannot include semver operators or pre-release identifiers. Compiler pre-release identifiers such as -nightly will be ignored while checking the Rust version. > **MSRV:** Respected as of 1.56 ## Uses **Diagnostics:** When your package is compiled on an unsupported toolchain, Cargo will provide clearer diagnostics about the insufficient toolchain version rather than reporting invalid syntax or missing functionality in the standard library. This affects all [Cargo targets](cargo-targets.md) in the package, including binaries, examples, test suites, benchmarks, etc. **Development aid:** `cargo add` will auto-select the dependency's version requirement to be the latest version compatible with your `rust-version`. If that isn't the latest version, `cargo add` will inform users so they can make the choice on whether to keep it or update your `rust-version`. The [resolver](resolver.md#rust-version) may take Rust version into account when picking dependencies. Other tools may also take advantage of it, like `cargo clippy`'s [`incompatible_msrv` lint](https://rust-lang.github.io/rust-clippy/stable/index.html#/incompatible_msrv). > **Note:** The `rust-version` may be ignored using the `--ignore-rust-version` option. ## Support Expectations These are general expectations; some packages may document when they do not follow these. **Complete:** All functionality, including binaries and API, are available on the supported Rust versions under every [feature](features.md). **Verified:** A package's functionality is verified on its supported Rust versions, including automated testing. See also our [Rust version CI guide](../guide/continuous-integration.md#verifying-rust-version). **Patchable:** When licenses allow it, users can [override their local dependency](overriding-dependencies.md) with a fork of your package. In this situation, Cargo may load the entire workspace for the patched dependency which should work on the supported Rust versions, even if other packages in the workspace have different supported Rust versions. **Dependency Support:** In support of the above, it is expected that each dependency's version-requirement supports at least one version compatible with your `rust-version`. However, it is **not** expected that the dependency specification excludes versions incompatible with your `rust-version`. In fact, supporting both allows you to balance the needs of users that support older Rust versions with those that don't. ## Setting and Updating Rust Version What Rust versions to support is a trade off between - Costs for the maintainer in not using newer features of the Rust toolchain or their dependencies - Costs to users who would benefit from a package using newer features of a toolchain, e.g. reducing build times by migrating to a feature in the standard library from a polyfill - Availability of a package to users supporting older Rust versions > **Note:** [Changing `rust-version`](semver.md#env-new-rust) is assumed to be a minor incompatibility > **Recommendation:** Choose a policy for what Rust versions to support and when that is changed so users can compare it with their own policy and, > if it isn't compatible, > decide whether the loss of general improvements or the risk of a blocking bug that won't be fixed is acceptable or not. > > The simplest policy to support is to always use the latest Rust version. > > Depending on your risk profile, the next simplest approach is to continue to support old major or minor versions of your package that support older Rust versions. ### Selecting supported Rust versions Users of your package are most likely to track their supported Rust versions to: - Their Rust toolchain vendor's support policy, e.g. The Rust Project or a Linux distribution - Note: the Rust Project only offers bug fixes and security updates for the latest version. - A fixed schedule for users to re-verify their packages with the new toolchain, e.g. the first release of the year, every 5 releases. In addition, users are unlikely to be using the new Rust version immediately but need time to notice and re-verify or might not be aligned on the exact same schedule.. Example version policies: - "N-2", meaning "latest version with a 2 release grace window for updating" - Every even release with a 2 release grace window for updating - Every version from this calendar year with a one year grace window for updating > **Note:** To find the minimum `rust-version` compatible with your project as-is, you can use third-party tools like [`cargo-msrv`](https://crates.io/crates/cargo-msrv). ### Update timeline When your policy specifies you no longer need to support a Rust version, you can update `rust-version` immediately or when needed. By allowing `rust-version` to drift from your policy, you offer users more of a grace window for upgrading. However, this is too unpredictable to be relied on for aligning with the Rust version users track. The further `rust-version` drifts from your specified policy, the more likely users are to infer a policy you did not intend, leading to frustration at the unmet expectations. When drift is allowed, there is the question of what is "justifiable enough" to drop supported Versions. Each person can come to a reasonably different justification; working through that discussion can be frustrating for the involved parties. This will disempower those who would want to avoid that type of conflict, which is particularly the case for new or casual contributors who either feel that they are not in a position to raise the question or that the conflict may hurt the chance of their change being merged. ### Multiple Policies in a Workspace Cargo allows supporting multiple policies within one workspace. Verifying specific packages under specific Rust versions can get complicated. Tools like [`cargo-hack`](https://crates.io/crates/cargo-hack) can help. For any dependency shared across policies, the lowest common versions must be used as Cargo [unifies SemVer-compatible versions](resolver.md#semver-compatibility), potentially limiting access to features of the shared dependency for the workspace member with the higher `rust-version`. To allow users to patch a dependency on one of your workspace members, every package in the workspace would need to be loadable in the oldest Rust version supported by the workspace. When using [`incompatible-rust-versions = "fallback"`](config.md#resolverincompatible-rust-versions), the Rust version of one package can affect dependency versions selected for another package with a different Rust version. See the [resolver](resolver.md#rust-version) chapter for more details. ### One or More Policies One way to mitigate the downsides of supporting older Rust versions is to apply your policy to older major or minor versions of your package that you continue to support. You likely still need a policy for what Rust versions the development branch support compared to the release branches for those major or minor versions. Only updating the development branch when "needed"' can help reduce the number of supported release branches. There is the question of what can be backported into these release branches. By backporting new functionality between minor versions, the next available version would be missing it which could be considered a breaking change, violating SemVer. Backporting changes also comes with the risk of introducing bugs. Supporting older versions comes at a cost. This cost is dependent on the risk and impact of bugs within the package and what is acceptable for backporting. Creating the release branches on-demand and putting the backport burden on the community are ways to balance this cost. There is not yet a way for dependency management tools to report that a non-latest version is still supported, shifting the responsibility to users to notice this in documentation. For example, a Rust version support policy could look like: - The development branch tracks to the latest stable release from the Rust Project, updated when needed - The minor version will be raised when changing `rust-version` - The project supports every version for this calendar year, with another year grace window - The last minor version that supports a supported Rust version will receive community provided bug fixes - Fixes must be backported to all supported minor releases between the development branch and the needed supported Rust version cargo-0.86.0/src/doc/src/reference/semver.md000064400000000000000000002244331046102023000167260ustar 00000000000000# SemVer Compatibility This chapter provides details on what is conventionally considered a compatible or breaking SemVer change for new releases of a package. See the [SemVer compatibility] section for details on what SemVer is, and how Cargo uses it to ensure compatibility of libraries. These are only *guidelines*, and not necessarily hard-and-fast rules that all projects will obey. The [Change categories] section details how this guide classifies the level and severity of a change. Most of this guide focuses on changes that will cause `cargo` and `rustc` to fail to build something that previously worked. Almost every change carries some risk that it will negatively affect the runtime behavior, and for those cases it is usually a judgment call by the project maintainers whether or not it is a SemVer-incompatible change. [Change categories]: #change-categories [SemVer compatibility]: resolver.md#semver-compatibility ## Change categories All of the policies listed below are categorized by the level of change: * **Major change**: a change that requires a major SemVer bump. * **Minor change**: a change that requires only a minor SemVer bump. * **Possibly-breaking change**: a change that some projects may consider major and others consider minor. The "Possibly-breaking" category covers changes that have the *potential* to break during an update, but may not necessarily cause a breakage. The impact of these changes should be considered carefully. The exact nature will depend on the change and the principles of the project maintainers. Some projects may choose to only bump the patch number on a minor change. It is encouraged to follow the SemVer spec, and only apply bug fixes in patch releases. However, a bug fix may require an API change that is marked as a "minor change", and shouldn't affect compatibility. This guide does not take a stance on how each individual "minor change" should be treated, as the difference between minor and patch changes are conventions that depend on the nature of the change. Some changes are marked as "minor", even though they carry the potential risk of breaking a build. This is for situations where the potential is extremely low, and the potentially breaking code is unlikely to be written in idiomatic Rust, or is specifically discouraged from use. This guide uses the terms "major" and "minor" assuming this relates to a "1.0.0" release or later. Initial development releases starting with "0.y.z" can treat changes in "y" as a major release, and "z" as a minor release. "0.0.z" releases are always major changes. This is because Cargo uses the convention that only changes in the left-most non-zero component are considered incompatible. * API compatibility * Items * [Major: renaming/moving/removing any public items](#item-remove) * [Minor: adding new public items](#item-new) * Types * [Major: Changing the alignment, layout, or size of a well-defined type](#type-layout) * Structs * [Major: adding a private struct field when all current fields are public](#struct-add-private-field-when-public) * [Major: adding a public field when no private field exists](#struct-add-public-field-when-no-private) * [Minor: adding or removing private fields when at least one already exists](#struct-private-fields-with-private) * [Minor: going from a tuple struct with all private fields (with at least one field) to a normal struct, or vice versa](#struct-tuple-normal-with-private) * Enums * [Major: adding new enum variants (without `non_exhaustive`)](#enum-variant-new) * [Major: adding new fields to an enum variant](#enum-fields-new) * Traits * [Major: adding a non-defaulted trait item](#trait-new-item-no-default) * [Major: any change to trait item signatures](#trait-item-signature) * [Possibly-breaking: adding a defaulted trait item](#trait-new-default-item) * [Major: adding a trait item that makes the trait non-object safe](#trait-object-safety) * [Major: adding a type parameter without a default](#trait-new-parameter-no-default) * [Minor: adding a defaulted trait type parameter](#trait-new-parameter-default) * Implementations * [Possibly-breaking change: adding any inherent items](#impl-item-new) * Generics * [Major: tightening generic bounds](#generic-bounds-tighten) * [Minor: loosening generic bounds](#generic-bounds-loosen) * [Minor: adding defaulted type parameters](#generic-new-default) * [Minor: generalizing a type to use generics (with identical types)](#generic-generalize-identical) * [Major: generalizing a type to use generics (with possibly different types)](#generic-generalize-different) * [Minor: changing a generic type to a more generic type](#generic-more-generic) * [Major: capturing more generic parameters in RPIT](#generic-rpit-capture) * Functions * [Major: adding/removing function parameters](#fn-change-arity) * [Possibly-breaking: introducing a new function type parameter](#fn-generic-new) * [Minor: generalizing a function to use generics (supporting original type)](#fn-generalize-compatible) * [Major: generalizing a function to use generics with type mismatch](#fn-generalize-mismatch) * [Minor: making an `unsafe` function safe](#fn-unsafe-safe) * Attributes * [Major: switching from `no_std` support to requiring `std`](#attr-no-std-to-std) * [Major: adding `non_exhaustive` to an existing enum, variant, or struct with no private fields](#attr-adding-non-exhaustive) * Tooling and environment compatibility * [Possibly-breaking: changing the minimum version of Rust required](#env-new-rust) * [Possibly-breaking: changing the platform and environment requirements](#env-change-requirements) * [Minor: introducing new lints](#new-lints) * Cargo * [Minor: adding a new Cargo feature](#cargo-feature-add) * [Major: removing a Cargo feature](#cargo-feature-remove) * [Major: removing a feature from a feature list if that changes functionality or public items](#cargo-feature-remove-another) * [Possibly-breaking: removing an optional dependency](#cargo-remove-opt-dep) * [Minor: changing dependency features](#cargo-change-dep-feature) * [Minor: adding dependencies](#cargo-dep-add) * [Application compatibility](#application-compatibility) ## API compatibility All of the examples below contain three parts: the original code, the code after it has been modified, and an example usage of the code that could appear in another project. In a minor change, the example usage should successfully build with both the before and after versions. ### Major: renaming/moving/removing any public items {#item-remove} The absence of a publicly exposed [item][items] will cause any uses of that item to fail to compile. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub fn foo() {} /////////////////////////////////////////////////////////// // After // ... item has been removed /////////////////////////////////////////////////////////// // Example usage that will break. fn main() { updated_crate::foo(); // Error: cannot find function `foo` } ``` This includes adding any sort of [`cfg` attribute] which can change which items or behavior is available based on [conditional compilation]. Mitigating strategies: * Mark items to be removed as [deprecated], and then remove them at a later date in a SemVer-breaking release. * Mark renamed items as [deprecated], and use a [`pub use`] item to re-export to the old name. ### Minor: adding new public items {#item-new} Adding new, public [items] is a minor change. ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before // ... absence of item /////////////////////////////////////////////////////////// // After pub fn foo() {} /////////////////////////////////////////////////////////// // Example use of the library that will safely work. // `foo` is not used since it didn't previously exist. ``` Note that in some rare cases this can be a **breaking change** due to glob imports. For example, if you add a new trait, and a project has used a glob import that brings that trait into scope, and the new trait introduces an associated item that conflicts with any types it is implemented on, this can cause a compile-time error due to the ambiguity. Example: ```rust,ignore // Breaking change example /////////////////////////////////////////////////////////// // Before // ... absence of trait /////////////////////////////////////////////////////////// // After pub trait NewTrait { fn foo(&self) {} } impl NewTrait for i32 {} /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::*; pub trait LocalTrait { fn foo(&self) {} } impl LocalTrait for i32 {} fn main() { 123i32.foo(); // Error: multiple applicable items in scope } ``` This is not considered a major change because conventionally glob imports are a known forwards-compatibility hazard. Glob imports of items from external crates should be avoided. ### Major: Changing the alignment, layout, or size of a well-defined type {#type-layout} It is a breaking change to change the alignment, layout, or size of a type that was previously well-defined. In general, types that use the [the default representation] do not have a well-defined alignment, layout, or size. The compiler is free to alter the alignment, layout, or size, so code should not make any assumptions about it. > **Note**: It may be possible for external crates to break if they make assumptions about the alignment, layout, or size of a type even if it is not well-defined. > This is not considered a SemVer breaking change since those assumptions should not be made. Some examples of changes that are not a breaking change are (assuming no other rules in this guide are violated): * Adding, removing, reordering, or changing fields of a default representation struct, union, or enum in such a way that the change follows the other rules in this guide (for example, using `non_exhaustive` to allow those changes, or changes to private fields that are already private). See [struct-add-private-field-when-public](#struct-add-private-field-when-public), [struct-add-public-field-when-no-private](#struct-add-public-field-when-no-private), [struct-private-fields-with-private](#struct-private-fields-with-private), [enum-fields-new](#enum-fields-new). * Adding variants to a default representation enum, if the enum uses `non_exhaustive`. This may change the alignment or size of the enumeration, but those are not well-defined. See [enum-variant-new](#enum-variant-new). * Adding, removing, reordering, or changing private fields of a `repr(C)` struct, union, or enum, following the other rules in this guide (for example, using `non_exhaustive`, or adding private fields when other private fields already exist). See [repr-c-private-change](#repr-c-private-change). * Adding variants to a `repr(C)` enum, if the enum uses `non_exhaustive`. See [repr-c-enum-variant-new](#repr-c-enum-variant-new). * Adding `repr(C)` to a default representation struct, union, or enum. See [repr-c-add](#repr-c-add). * Adding `repr()` [primitive representation] to an enum. See [repr-int-enum-add](#repr-int-enum-add). * Adding `repr(transparent)` to a default representation struct or enum. See [repr-transparent-add](#repr-transparent-add). Types that use the [`repr` attribute] can be said to have an alignment and layout that is defined in some way that code may make some assumptions about that may break as a result of changing that type. In some cases, types with a `repr` attribute may not have an alignment, layout, or size that is well-defined. In these cases, it may be safe to make changes to the types, though care should be exercised. For example, types with private fields that do not otherwise document their alignment, layout, or size guarantees cannot be relied upon by external crates since the public API does not fully define the alignment, layout, or size of the type. A common example where a type with *private* fields is well-defined is a type with a single private field with a generic type, using `repr(transparent)`, and the prose of the documentation discusses that it is transparent to the generic type. For example, see [`UnsafeCell`]. Some examples of breaking changes are: * Adding `repr(packed)` to a struct or union. See [repr-packed-add](#repr-packed-add). * Adding `repr(align)` to a struct, union, or enum. See [repr-align-add](#repr-align-add). * Removing `repr(packed)` from a struct or union. See [repr-packed-remove](#repr-packed-remove). * Changing the value N of `repr(packed(N))` if that changes the alignment or layout. See [repr-packed-n-change](#repr-packed-n-change). * Changing the value N of `repr(align(N))` if that changes the alignment. See [repr-align-n-change](#repr-align-n-change). * Removing `repr(align)` from a struct, union, or enum. See [repr-align-remove](#repr-align-remove). * Changing the order of public fields of a `repr(C)` type. See [repr-c-shuffle](#repr-c-shuffle). * Removing `repr(C)` from a struct, union, or enum. See [repr-c-remove](#repr-c-remove). * Removing `repr()` from an enum. See [repr-int-enum-remove](#repr-int-enum-remove). * Changing the primitive representation of a `repr()` enum. See [repr-int-enum-change](#repr-int-enum-change). * Removing `repr(transparent)` from a struct or enum. See [repr-transparent-remove](#repr-transparent-remove). [the default representation]: ../../reference/type-layout.html#the-default-representation [primitive representation]: ../../reference/type-layout.html#primitive-representations [`repr` attribute]: ../../reference/type-layout.html#representations [`std::mem::transmute`]: ../../std/mem/fn.transmute.html [`UnsafeCell`]: ../../std/cell/struct.UnsafeCell.html#memory-layout #### Minor: `repr(C)` add, remove, or change a private field {#repr-c-private-change} It is usually safe to add, remove, or change a private field of a `repr(C)` struct, union, or enum, assuming it follows the other guidelines in this guide (see [struct-add-private-field-when-public](#struct-add-private-field-when-public), [struct-add-public-field-when-no-private](#struct-add-public-field-when-no-private), [struct-private-fields-with-private](#struct-private-fields-with-private), [enum-fields-new](#enum-fields-new)). For example, adding private fields can only be done if there are already other private fields, or it is `non_exhaustive`. Public fields may be added if there are private fields, or it is `non_exhaustive`, and the addition does not alter the layout of the other fields. However, this may change the size and alignment of the type. Care should be taken if the size or alignment changes. Code should not make assumptions about the size or alignment of types with private fields or `non_exhaustive` unless it has a documented size or alignment. ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before #[derive(Default)] #[repr(C)] pub struct Example { pub f1: i32, f2: i32, // a private field } /////////////////////////////////////////////////////////// // After #[derive(Default)] #[repr(C)] pub struct Example { pub f1: i32, f2: i32, f3: i32, // a new field } /////////////////////////////////////////////////////////// // Example use of the library that will safely work. fn main() { // NOTE: Users should not make assumptions about the size or alignment // since they are not documented. let f = updated_crate::Example::default(); } ``` #### Minor: `repr(C)` add enum variant {#repr-c-enum-variant-new} It is usually safe to add variants to a `repr(C)` enum, if the enum uses `non_exhaustive`. See [enum-variant-new](#enum-variant-new) for more discussion. Note that this may be a breaking change since it changes the size and alignment of the type. See [repr-c-private-change](#repr-c-private-change) for similar concerns. ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before #[repr(C)] #[non_exhaustive] pub enum Example { Variant1 { f1: i16 }, Variant2 { f1: i32 }, } /////////////////////////////////////////////////////////// // After #[repr(C)] #[non_exhaustive] pub enum Example { Variant1 { f1: i16 }, Variant2 { f1: i32 }, Variant3 { f1: i64 }, // added } /////////////////////////////////////////////////////////// // Example use of the library that will safely work. fn main() { // NOTE: Users should not make assumptions about the size or alignment // since they are not specified. For example, this raised the size from 8 // to 16 bytes. let f = updated_crate::Example::Variant2 { f1: 123 }; } ``` #### Minor: Adding `repr(C)` to a default representation {#repr-c-add} It is safe to add `repr(C)` to a struct, union, or enum with [the default representation]. This is safe because users should not make assumptions about the alignment, layout, or size of types with the default representation. ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before pub struct Example { pub f1: i32, pub f2: i16, } /////////////////////////////////////////////////////////// // After #[repr(C)] // added pub struct Example { pub f1: i32, pub f2: i16, } /////////////////////////////////////////////////////////// // Example use of the library that will safely work. fn main() { let f = updated_crate::Example { f1: 123, f2: 456 }; } ``` #### Minor: Adding `repr()` to an enum {#repr-int-enum-add} It is safe to add `repr()` [primitive representation] to an enum with [the default representation]. This is safe because users should not make assumptions about the alignment, layout, or size of an enum with the default representation. ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before pub enum E { Variant1, Variant2(i32), Variant3 { f1: f64 }, } /////////////////////////////////////////////////////////// // After #[repr(i32)] // added pub enum E { Variant1, Variant2(i32), Variant3 { f1: f64 }, } /////////////////////////////////////////////////////////// // Example use of the library that will safely work. fn main() { let x = updated_crate::E::Variant3 { f1: 1.23 }; } ``` #### Minor: Adding `repr(transparent)` to a default representation struct or enum {#repr-transparent-add} It is safe to add `repr(transparent)` to a struct or enum with [the default representation]. This is safe because users should not make assumptions about the alignment, layout, or size of a struct or enum with the default representation. ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before #[derive(Default)] pub struct Example(T); /////////////////////////////////////////////////////////// // After #[derive(Default)] #[repr(transparent)] // added pub struct Example(T); /////////////////////////////////////////////////////////// // Example use of the library that will safely work. fn main() { let x = updated_crate::Example::::default(); } ``` #### Major: Adding `repr(packed)` to a struct or union {#repr-packed-add} It is a breaking change to add `repr(packed)` to a struct or union. Making a type `repr(packed)` makes changes that can break code, such as being invalid to take a reference to a field, or causing truncation of disjoint closure captures. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub struct Example { pub f1: u8, pub f2: u16, } /////////////////////////////////////////////////////////// // After #[repr(packed)] // added pub struct Example { pub f1: u8, pub f2: u16, } /////////////////////////////////////////////////////////// // Example usage that will break. fn main() { let f = updated_crate::Example { f1: 1, f2: 2 }; let x = &f.f2; // Error: reference to packed field is unaligned } ``` ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub struct Example(pub i32, pub i32); /////////////////////////////////////////////////////////// // After #[repr(packed)] pub struct Example(pub i32, pub i32); /////////////////////////////////////////////////////////// // Example usage that will break. fn main() { let mut f = updated_crate::Example(123, 456); let c = || { // Without repr(packed), the closure precisely captures `&f.0`. // With repr(packed), the closure captures `&f` to avoid undefined behavior. let a = f.0; }; f.1 = 789; // Error: cannot assign to `f.1` because it is borrowed c(); } ``` #### Major: Adding `repr(align)` to a struct, union, or enum {#repr-align-add} It is a breaking change to add `repr(align)` to a struct, union, or enum. Making a type `repr(align)` would break any use of that type in a `repr(packed)` type because that combination is not allowed. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub struct Aligned { pub a: i32, } /////////////////////////////////////////////////////////// // After #[repr(align(8))] // added pub struct Aligned { pub a: i32, } /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::Aligned; #[repr(packed)] pub struct Packed { // Error: packed type cannot transitively contain a `#[repr(align)]` type f1: Aligned, } fn main() { let p = Packed { f1: Aligned { a: 123 }, }; } ``` #### Major: Removing `repr(packed)` from a struct or union {#repr-packed-remove} It is a breaking change to remove `repr(packed)` from a struct or union. This may change the alignment or layout that extern crates are relying on. If any fields are public, then removing `repr(packed)` may change the way disjoint closure captures work. In some cases, this can cause code to break, similar to those outlined in the [edition guide][edition-closures]. [edition-closures]: ../../edition-guide/rust-2021/disjoint-capture-in-closures.html ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before #[repr(C, packed)] pub struct Packed { pub a: u8, pub b: u16, } /////////////////////////////////////////////////////////// // After #[repr(C)] // removed packed pub struct Packed { pub a: u8, pub b: u16, } /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::Packed; fn main() { let p = Packed { a: 1, b: 2 }; // Some assumption about the size of the type. // Without `packed`, this fails since the size is 4. const _: () = assert!(std::mem::size_of::() == 3); // Error: evaluation of constant value failed } ``` ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before #[repr(C, packed)] pub struct Packed { pub a: *mut i32, pub b: i32, } unsafe impl Send for Packed {} /////////////////////////////////////////////////////////// // After #[repr(C)] // removed packed pub struct Packed { pub a: *mut i32, pub b: i32, } unsafe impl Send for Packed {} /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::Packed; fn main() { let mut x = 123; let p = Packed { a: &mut x as *mut i32, b: 456, }; // When the structure was packed, the closure captures `p` which is Send. // When `packed` is removed, this ends up capturing `p.a` which is not Send. std::thread::spawn(move || unsafe { *(p.a) += 1; // Error: cannot be sent between threads safely }); } ``` #### Major: Changing the value N of `repr(packed(N))` if that changes the alignment or layout {#repr-packed-n-change} It is a breaking change to change the value of N of `repr(packed(N))` if that changes the alignment or layout. This may change the alignment or layout that external crates are relying on. If the value `N` is lowered below the alignment of a public field, then that would break any code that attempts to take a reference of that field. Note that some changes to `N` may not change the alignment or layout, for example increasing it when the current value is already equal to the natural alignment of the type. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before #[repr(packed(4))] pub struct Packed { pub a: u8, pub b: u32, } /////////////////////////////////////////////////////////// // After #[repr(packed(2))] // changed to 2 pub struct Packed { pub a: u8, pub b: u32, } /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::Packed; fn main() { let p = Packed { a: 1, b: 2 }; let x = &p.b; // Error: reference to packed field is unaligned } ``` #### Major: Changing the value N of `repr(align(N))` if that changes the alignment {#repr-align-n-change} It is a breaking change to change the value `N` of `repr(align(N))` if that changes the alignment. This may change the alignment that external crates are relying on. This change should be safe to make if the type is not well-defined as discussed in [type layout](#type-layout) (such as having any private fields and having an undocumented alignment or layout). Note that some changes to `N` may not change the alignment or layout, for example decreasing it when the current value is already equal to or less than the natural alignment of the type. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before #[repr(align(8))] pub struct Packed { pub a: u8, pub b: u32, } /////////////////////////////////////////////////////////// // After #[repr(align(4))] // changed to 4 pub struct Packed { pub a: u8, pub b: u32, } /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::Packed; fn main() { let p = Packed { a: 1, b: 2 }; // Some assumption about the size of the type. // The alignment has changed from 8 to 4. const _: () = assert!(std::mem::align_of::() == 8); // Error: evaluation of constant value failed } ``` #### Major: Removing `repr(align)` from a struct, union, or enum {#repr-align-remove} It is a breaking change to remove `repr(align)` from a struct, union, or enum, if their layout was well-defined. This may change the alignment or layout that external crates are relying on. This change should be safe to make if the type is not well-defined as discussed in [type layout](#type-layout) (such as having any private fields and having an undocumented alignment). ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before #[repr(C, align(8))] pub struct Packed { pub a: u8, pub b: u32, } /////////////////////////////////////////////////////////// // After #[repr(C)] // removed align pub struct Packed { pub a: u8, pub b: u32, } /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::Packed; fn main() { let p = Packed { a: 1, b: 2 }; // Some assumption about the size of the type. // The alignment has changed from 8 to 4. const _: () = assert!(std::mem::align_of::() == 8); // Error: evaluation of constant value failed } ``` #### Major: Changing the order of public fields of a `repr(C)` type {#repr-c-shuffle} It is a breaking change to change the order of public fields of a `repr(C)` type. External crates may be relying on the specific ordering of the fields. ```rust,ignore,run-fail // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before #[repr(C)] pub struct SpecificLayout { pub a: u8, pub b: u32, } /////////////////////////////////////////////////////////// // After #[repr(C)] pub struct SpecificLayout { pub b: u32, // changed order pub a: u8, } /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::SpecificLayout; extern "C" { // This C function is assuming a specific layout defined in a C header. fn c_fn_get_b(x: &SpecificLayout) -> u32; } fn main() { let p = SpecificLayout { a: 1, b: 2 }; unsafe { assert_eq!(c_fn_get_b(&p), 2) } // Error: value not equal to 2 } # mod cdep { # // This simulates what would normally be something included from a build script. # // This definition would be in a C header. # #[repr(C)] # pub struct SpecificLayout { # pub a: u8, # pub b: u32, # } # # #[no_mangle] # pub fn c_fn_get_b(x: &SpecificLayout) -> u32 { # x.b # } # } ``` #### Major: Removing `repr(C)` from a struct, union, or enum {#repr-c-remove} It is a breaking change to remove `repr(C)` from a struct, union, or enum. External crates may be relying on the specific layout of the type. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before #[repr(C)] pub struct SpecificLayout { pub a: u8, pub b: u32, } /////////////////////////////////////////////////////////// // After // removed repr(C) pub struct SpecificLayout { pub a: u8, pub b: u32, } /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::SpecificLayout; extern "C" { // This C function is assuming a specific layout defined in a C header. fn c_fn_get_b(x: &SpecificLayout) -> u32; // Error: is not FFI-safe } fn main() { let p = SpecificLayout { a: 1, b: 2 }; unsafe { assert_eq!(c_fn_get_b(&p), 2) } } # mod cdep { # // This simulates what would normally be something included from a build script. # // This definition would be in a C header. # #[repr(C)] # pub struct SpecificLayout { # pub a: u8, # pub b: u32, # } # # #[no_mangle] # pub fn c_fn_get_b(x: &SpecificLayout) -> u32 { # x.b # } # } ``` #### Major: Removing `repr()` from an enum {#repr-int-enum-remove} It is a breaking change to remove `repr()` from an enum. External crates may be assuming that the discriminant is a specific size. For example, [`std::mem::transmute`] of an enum may fail. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before #[repr(u16)] pub enum Example { Variant1, Variant2, Variant3, } /////////////////////////////////////////////////////////// // After // removed repr(u16) pub enum Example { Variant1, Variant2, Variant3, } /////////////////////////////////////////////////////////// // Example usage that will break. fn main() { let e = updated_crate::Example::Variant2; let i: u16 = unsafe { std::mem::transmute(e) }; // Error: cannot transmute between types of different sizes } ``` #### Major: Changing the primitive representation of a `repr()` enum {#repr-int-enum-change} It is a breaking change to change the primitive representation of a `repr()` enum. External crates may be assuming that the discriminant is a specific size. For example, [`std::mem::transmute`] of an enum may fail. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before #[repr(u16)] pub enum Example { Variant1, Variant2, Variant3, } /////////////////////////////////////////////////////////// // After #[repr(u8)] // changed repr size pub enum Example { Variant1, Variant2, Variant3, } /////////////////////////////////////////////////////////// // Example usage that will break. fn main() { let e = updated_crate::Example::Variant2; let i: u16 = unsafe { std::mem::transmute(e) }; // Error: cannot transmute between types of different sizes } ``` #### Major: Removing `repr(transparent)` from a struct or enum {#repr-transparent-remove} It is a breaking change to remove `repr(transparent)` from a struct or enum. External crates may be relying on the type having the alignment, layout, or size of the transparent field. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before #[repr(transparent)] pub struct Transparent(T); /////////////////////////////////////////////////////////// // After // removed repr pub struct Transparent(T); /////////////////////////////////////////////////////////// // Example usage that will break. #![deny(improper_ctypes)] use updated_crate::Transparent; extern "C" { fn c_fn() -> Transparent; // Error: is not FFI-safe } fn main() {} ``` ### Major: adding a private struct field when all current fields are public {#struct-add-private-field-when-public} When a private field is added to a struct that previously had all public fields, this will break any code that attempts to construct it with a [struct literal]. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub struct Foo { pub f1: i32, } /////////////////////////////////////////////////////////// // After pub struct Foo { pub f1: i32, f2: i32, } /////////////////////////////////////////////////////////// // Example usage that will break. fn main() { let x = updated_crate::Foo { f1: 123 }; // Error: cannot construct `Foo` } ``` Mitigation strategies: * Do not add new fields to all-public field structs. * Mark structs as [`#[non_exhaustive]`][non_exhaustive] when first introducing a struct to prevent users from using struct literal syntax, and instead provide a constructor method and/or [Default] implementation. ### Major: adding a public field when no private field exists {#struct-add-public-field-when-no-private} When a public field is added to a struct that has all public fields, this will break any code that attempts to construct it with a [struct literal]. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub struct Foo { pub f1: i32, } /////////////////////////////////////////////////////////// // After pub struct Foo { pub f1: i32, pub f2: i32, } /////////////////////////////////////////////////////////// // Example usage that will break. fn main() { let x = updated_crate::Foo { f1: 123 }; // Error: missing field `f2` } ``` Mitigation strategies: * Do not add new fields to all-public field structs. * Mark structs as [`#[non_exhaustive]`][non_exhaustive] when first introducing a struct to prevent users from using struct literal syntax, and instead provide a constructor method and/or [Default] implementation. ### Minor: adding or removing private fields when at least one already exists {#struct-private-fields-with-private} It is safe to add or remove private fields from a struct when the struct already has at least one private field. ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before #[derive(Default)] pub struct Foo { f1: i32, } /////////////////////////////////////////////////////////// // After #[derive(Default)] pub struct Foo { f2: f64, } /////////////////////////////////////////////////////////// // Example use of the library that will safely work. fn main() { // Cannot access private fields. let x = updated_crate::Foo::default(); } ``` This is safe because existing code cannot use a [struct literal] to construct it, nor exhaustively match its contents. Note that for tuple structs, this is a **major change** if the tuple contains public fields, and the addition or removal of a private field changes the index of any public field. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before #[derive(Default)] pub struct Foo(pub i32, i32); /////////////////////////////////////////////////////////// // After #[derive(Default)] pub struct Foo(f64, pub i32, i32); /////////////////////////////////////////////////////////// // Example usage that will break. fn main() { let x = updated_crate::Foo::default(); let y = x.0; // Error: is private } ``` ### Minor: going from a tuple struct with all private fields (with at least one field) to a normal struct, or vice versa {#struct-tuple-normal-with-private} Changing a tuple struct to a normal struct (or vice-versa) is safe if all fields are private. ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before #[derive(Default)] pub struct Foo(i32); /////////////////////////////////////////////////////////// // After #[derive(Default)] pub struct Foo { f1: i32, } /////////////////////////////////////////////////////////// // Example use of the library that will safely work. fn main() { // Cannot access private fields. let x = updated_crate::Foo::default(); } ``` This is safe because existing code cannot use a [struct literal] to construct it, nor match its contents. ### Major: adding new enum variants (without `non_exhaustive`) {#enum-variant-new} It is a breaking change to add a new enum variant if the enum does not use the [`#[non_exhaustive]`][non_exhaustive] attribute. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub enum E { Variant1, } /////////////////////////////////////////////////////////// // After pub enum E { Variant1, Variant2, } /////////////////////////////////////////////////////////// // Example usage that will break. fn main() { use updated_crate::E; let x = E::Variant1; match x { // Error: `E::Variant2` not covered E::Variant1 => {} } } ``` Mitigation strategies: * When introducing the enum, mark it as [`#[non_exhaustive]`][non_exhaustive] to force users to use [wildcard patterns] to catch new variants. ### Major: adding new fields to an enum variant {#enum-fields-new} It is a breaking change to add new fields to an enum variant because all fields are public, and constructors and matching will fail to compile. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub enum E { Variant1 { f1: i32 }, } /////////////////////////////////////////////////////////// // After pub enum E { Variant1 { f1: i32, f2: i32 }, } /////////////////////////////////////////////////////////// // Example usage that will break. fn main() { use updated_crate::E; let x = E::Variant1 { f1: 1 }; // Error: missing f2 match x { E::Variant1 { f1 } => {} // Error: missing f2 } } ``` Mitigation strategies: * When introducing the enum, mark the variant as [`non_exhaustive`][non_exhaustive] so that it cannot be constructed or matched without wildcards. ```rust,ignore,skip pub enum E { #[non_exhaustive] Variant1{f1: i32} } ``` * When introducing the enum, use an explicit struct as a value, where you can have control over the field visibility. ```rust,ignore,skip pub struct Foo { f1: i32, f2: i32, } pub enum E { Variant1(Foo) } ``` ### Major: adding a non-defaulted trait item {#trait-new-item-no-default} It is a breaking change to add a non-defaulted item to a trait. This will break any implementors of the trait. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub trait Trait {} /////////////////////////////////////////////////////////// // After pub trait Trait { fn foo(&self); } /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::Trait; struct Foo; impl Trait for Foo {} // Error: not all trait items implemented ``` Mitigation strategies: * Always provide a default implementation or value for new associated trait items. * When introducing the trait, use the [sealed trait] technique to prevent users outside of the crate from implementing the trait. ### Major: any change to trait item signatures {#trait-item-signature} It is a breaking change to make any change to a trait item signature. This can break external implementors of the trait. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub trait Trait { fn f(&self, x: i32) {} } /////////////////////////////////////////////////////////// // After pub trait Trait { // For sealed traits or normal functions, this would be a minor change // because generalizing with generics strictly expands the possible uses. // But in this case, trait implementations must use the same signature. fn f(&self, x: V) {} } /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::Trait; struct Foo; impl Trait for Foo { fn f(&self, x: i32) {} // Error: trait declaration has 1 type parameter } ``` Mitigation strategies: * Introduce new items with default implementations to cover the new functionality instead of modifying existing items. * When introducing the trait, use the [sealed trait] technique to prevent users outside of the crate from implementing the trait. ### Possibly-breaking: adding a defaulted trait item {#trait-new-default-item} It is usually safe to add a defaulted trait item. However, this can sometimes cause a compile error. For example, this can introduce an ambiguity if a method of the same name exists in another trait. ```rust,ignore // Breaking change example /////////////////////////////////////////////////////////// // Before pub trait Trait {} /////////////////////////////////////////////////////////// // After pub trait Trait { fn foo(&self) {} } /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::Trait; struct Foo; trait LocalTrait { fn foo(&self) {} } impl Trait for Foo {} impl LocalTrait for Foo {} fn main() { let x = Foo; x.foo(); // Error: multiple applicable items in scope } ``` Note that this ambiguity does *not* exist for name collisions on [inherent implementations], as they take priority over trait items. See [trait-object-safety](#trait-object-safety) for a special case to consider when adding trait items. Mitigation strategies: * Some projects may deem this acceptable breakage, particularly if the new item name is unlikely to collide with any existing code. Choose names carefully to help avoid these collisions. Additionally, it may be acceptable to require downstream users to add [disambiguation syntax] to select the correct function when updating the dependency. ### Major: adding a trait item that makes the trait non-object safe {#trait-object-safety} It is a breaking change to add a trait item that changes the trait to not be [object safe]. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub trait Trait {} /////////////////////////////////////////////////////////// // After pub trait Trait { // An associated const makes the trait not object-safe. const CONST: i32 = 123; } /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::Trait; struct Foo; impl Trait for Foo {} fn main() { let obj: Box = Box::new(Foo); // Error: cannot be made into an object } ``` It is safe to do the converse (making a non-object safe trait into a safe one). ### Major: adding a type parameter without a default {#trait-new-parameter-no-default} It is a breaking change to add a type parameter without a default to a trait. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub trait Trait {} /////////////////////////////////////////////////////////// // After pub trait Trait {} /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::Trait; struct Foo; impl Trait for Foo {} // Error: missing generics ``` Mitigating strategies: * See [adding a defaulted trait type parameter](#trait-new-parameter-default). ### Minor: adding a defaulted trait type parameter {#trait-new-parameter-default} It is safe to add a type parameter to a trait as long as it has a default. External implementors will use the default without needing to specify the parameter. ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before pub trait Trait {} /////////////////////////////////////////////////////////// // After pub trait Trait {} /////////////////////////////////////////////////////////// // Example use of the library that will safely work. use updated_crate::Trait; struct Foo; impl Trait for Foo {} ``` ### Possibly-breaking change: adding any inherent items {#impl-item-new} Usually adding inherent items to an implementation should be safe because inherent items take priority over trait items. However, in some cases the collision can cause problems if the name is the same as an implemented trait item with a different signature. ```rust,ignore // Breaking change example /////////////////////////////////////////////////////////// // Before pub struct Foo; /////////////////////////////////////////////////////////// // After pub struct Foo; impl Foo { pub fn foo(&self) {} } /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::Foo; trait Trait { fn foo(&self, x: i32) {} } impl Trait for Foo {} fn main() { let x = Foo; x.foo(1); // Error: this method takes 0 arguments but 1 argument was supplied } ``` Note that if the signatures match, there would not be a compile-time error, but possibly a silent change in runtime behavior (because it is now executing a different function). Mitigation strategies: * Some projects may deem this acceptable breakage, particularly if the new item name is unlikely to collide with any existing code. Choose names carefully to help avoid these collisions. Additionally, it may be acceptable to require downstream users to add [disambiguation syntax] to select the correct function when updating the dependency. ### Major: tightening generic bounds {#generic-bounds-tighten} It is a breaking change to tighten generic bounds on a type since this can break users expecting the looser bounds. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub struct Foo { pub f1: A, } /////////////////////////////////////////////////////////// // After pub struct Foo { pub f1: A, } /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::Foo; fn main() { let s = Foo { f1: 1.23 }; // Error: the trait bound `{float}: Eq` is not satisfied } ``` ### Minor: loosening generic bounds {#generic-bounds-loosen} It is safe to loosen the generic bounds on a type, as it only expands what is allowed. ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before pub struct Foo { pub f1: A, } /////////////////////////////////////////////////////////// // After pub struct Foo { pub f1: A, } /////////////////////////////////////////////////////////// // Example use of the library that will safely work. use updated_crate::Foo; fn main() { let s = Foo { f1: 123 }; } ``` ### Minor: adding defaulted type parameters {#generic-new-default} It is safe to add a type parameter to a type as long as it has a default. All existing references will use the default without needing to specify the parameter. ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before #[derive(Default)] pub struct Foo {} /////////////////////////////////////////////////////////// // After #[derive(Default)] pub struct Foo { f1: A, } /////////////////////////////////////////////////////////// // Example use of the library that will safely work. use updated_crate::Foo; fn main() { let s: Foo = Default::default(); } ``` ### Minor: generalizing a type to use generics (with identical types) {#generic-generalize-identical} A struct or enum field can change from a concrete type to a generic type parameter, provided that the change results in an identical type for all existing use cases. For example, the following change is permitted: ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before pub struct Foo(pub u8); /////////////////////////////////////////////////////////// // After pub struct Foo(pub T); /////////////////////////////////////////////////////////// // Example use of the library that will safely work. use updated_crate::Foo; fn main() { let s: Foo = Foo(123); } ``` because existing uses of `Foo` are shorthand for `Foo` which yields the identical field type. ### Major: generalizing a type to use generics (with possibly different types) {#generic-generalize-different} Changing a struct or enum field from a concrete type to a generic type parameter can break if the type can change. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub struct Foo(pub T, pub u8); /////////////////////////////////////////////////////////// // After pub struct Foo(pub T, pub T); /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::Foo; fn main() { let s: Foo = Foo(3.14, 123); // Error: mismatched types } ``` ### Minor: changing a generic type to a more generic type {#generic-more-generic} It is safe to change a generic type to a more generic one. For example, the following adds a generic parameter that defaults to the original type, which is safe because all existing users will be using the same type for both fields, the defaulted parameter does not need to be specified. ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before pub struct Foo(pub T, pub T); /////////////////////////////////////////////////////////// // After pub struct Foo(pub T, pub U); /////////////////////////////////////////////////////////// // Example use of the library that will safely work. use updated_crate::Foo; fn main() { let s: Foo = Foo(1.0, 2.0); } ``` ### Major: capturing more generic parameters in RPIT {#generic-rpit-capture} It is a breaking change to capture additional generic parameters in an [RPIT] (return-position impl trait). ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub fn f<'a, 'b>(x: &'a str, y: &'b str) -> impl Iterator + use<'a> { x.chars() } /////////////////////////////////////////////////////////// // After pub fn f<'a, 'b>(x: &'a str, y: &'b str) -> impl Iterator + use<'a, 'b> { x.chars().chain(y.chars()) } /////////////////////////////////////////////////////////// // Example usage that will break. fn main() { let a = String::new(); let b = String::new(); let iter = updated_crate::f(&a, &b); drop(b); // Error: cannot move out of `b` because it is borrowed } ``` Adding generic parameters to an RPIT places additional constraints on how the resulting type may be used. Note that there are implicit captures when the `use<>` syntax is not specified. In Rust 2021 and earlier editions, the lifetime parameters are only captured if they appear syntactically within a bound in the RPIT type signature. Starting in Rust 2024, all lifetime parameters are unconditionally captured. This means that starting in Rust 2024, the default is maximally compatible, requiring you to be explicit when you want to capture less, which is a SemVer commitment. See the [edition guide][rpit-capture-guide] and the [reference][rpit-reference] for more information on RPIT capturing. It is a minor change to capture fewer generic parameters in an RPIT. > Note: All in-scope type and const generic parameters must be either implicitly captured (no `+ use<…>` specified) or explicitly captured (must be listed in `+ use<…>`), and thus currently it is not allowed to change what is captured of those kinds of generics. [RPIT]: ../../reference/types/impl-trait.md#abstract-return-types [rpit-capture-guide]: ../../edition-guide/rust-2024/rpit-lifetime-capture.html [rpit-reference]: ../../reference/types/impl-trait.md#capturing ### Major: adding/removing function parameters {#fn-change-arity} Changing the arity of a function is a breaking change. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub fn foo() {} /////////////////////////////////////////////////////////// // After pub fn foo(x: i32) {} /////////////////////////////////////////////////////////// // Example usage that will break. fn main() { updated_crate::foo(); // Error: this function takes 1 argument } ``` Mitigating strategies: * Introduce a new function with the new signature and possibly [deprecate][deprecated] the old one. * Introduce functions that take a struct argument, where the struct is built with the builder pattern. This allows new fields to be added to the struct in the future. ### Possibly-breaking: introducing a new function type parameter {#fn-generic-new} Usually, adding a non-defaulted type parameter is safe, but in some cases it can be a breaking change: ```rust,ignore // Breaking change example /////////////////////////////////////////////////////////// // Before pub fn foo() {} /////////////////////////////////////////////////////////// // After pub fn foo() {} /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::foo; fn main() { foo::(); // Error: function takes 2 generic arguments but 1 generic argument was supplied } ``` However, such explicit calls are rare enough (and can usually be written in other ways) that this breakage is usually acceptable. One should take into account how likely it is that the function in question is being called with explicit type arguments. ### Minor: generalizing a function to use generics (supporting original type) {#fn-generalize-compatible} The type of a parameter to a function, or its return value, can be *generalized* to use generics, including by introducing a new type parameter, as long as it can be instantiated to the original type. For example, the following changes are allowed: ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before pub fn foo(x: u8) -> u8 { x } pub fn bar>(t: T) {} /////////////////////////////////////////////////////////// // After use std::ops::Add; pub fn foo(x: T) -> T { x } pub fn bar>(t: T) {} /////////////////////////////////////////////////////////// // Example use of the library that will safely work. use updated_crate::{bar, foo}; fn main() { foo(1); bar(vec![1, 2, 3].into_iter()); } ``` because all existing uses are instantiations of the new signature. Perhaps somewhat surprisingly, generalization applies to trait objects as well, given that every trait implements itself: ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before pub trait Trait {} pub fn foo(t: &dyn Trait) {} /////////////////////////////////////////////////////////// // After pub trait Trait {} pub fn foo(t: &T) {} /////////////////////////////////////////////////////////// // Example use of the library that will safely work. use updated_crate::{foo, Trait}; struct Foo; impl Trait for Foo {} fn main() { let obj = Foo; foo(&obj); } ``` (The use of `?Sized` is essential; otherwise you couldn't recover the original signature.) Introducing generics in this way can potentially create type inference failures. These are usually rare, and may be acceptable breakage for some projects, as this can be fixed with additional type annotations. ```rust,ignore // Breaking change example /////////////////////////////////////////////////////////// // Before pub fn foo() -> i32 { 0 } /////////////////////////////////////////////////////////// // After pub fn foo() -> T { Default::default() } /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::foo; fn main() { let x = foo(); // Error: type annotations needed } ``` ### Major: generalizing a function to use generics with type mismatch {#fn-generalize-mismatch} It is a breaking change to change a function parameter or return type if the generic type constrains or changes the types previously allowed. For example, the following adds a generic constraint that may not be satisfied by existing code: ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub fn foo(x: Vec) {} /////////////////////////////////////////////////////////// // After pub fn foo>(x: T) {} /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::foo; fn main() { foo(vec![1, 2, 3]); // Error: `Copy` is not implemented for `Vec` } ``` ### Minor: making an `unsafe` function safe {#fn-unsafe-safe} A previously `unsafe` function can be made safe without breaking code. Note however that it may cause the [`unused_unsafe`][unused_unsafe] lint to trigger as in the example below, which will cause local crates that have specified `#![deny(warnings)]` to stop compiling. Per [introducing new lints](#new-lints), it is allowed for updates to introduce new warnings. Going the other way (making a safe function `unsafe`) is a breaking change. ```rust,ignore // MINOR CHANGE /////////////////////////////////////////////////////////// // Before pub unsafe fn foo() {} /////////////////////////////////////////////////////////// // After pub fn foo() {} /////////////////////////////////////////////////////////// // Example use of the library that will trigger a lint. use updated_crate::foo; unsafe fn bar(f: unsafe fn()) { f() } fn main() { unsafe { foo() }; // The `unused_unsafe` lint will trigger here unsafe { bar(foo) }; } ``` Making a previously `unsafe` associated function or method on structs / enums safe is also a minor change, while the same is not true for associated function on traits (see [any change to trait item signatures](#trait-item-signature)). ### Major: switching from `no_std` support to requiring `std` {#attr-no-std-to-std} If your library specifically supports a [`no_std`] environment, it is a breaking change to make a new release that requires `std`. ```rust,ignore,skip // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before #![no_std] pub fn foo() {} /////////////////////////////////////////////////////////// // After pub fn foo() { std::time::SystemTime::now(); } /////////////////////////////////////////////////////////// // Example usage that will break. // This will fail to link for no_std targets because they don't have a `std` crate. #![no_std] use updated_crate::foo; fn example() { foo(); } ``` Mitigation strategies: * A common idiom to avoid this is to include a `std` [Cargo feature] that optionally enables `std` support, and when the feature is off, the library can be used in a `no_std` environment. ### Major: adding `non_exhaustive` to an existing enum, variant, or struct with no private fields {#attr-adding-non-exhaustive} Making items [`#[non_exhaustive]`][non_exhaustive] changes how they may be used outside the crate where they are defined: - Non-exhaustive structs and enum variants cannot be constructed using [struct literal] syntax, including [functional update syntax]. - Pattern matching on non-exhaustive structs requires `..` and matching on enums does not count towards exhaustiveness. - Casting enum variants to their discriminant with `as` is not allowed. Structs with private fields cannot be constructed using [struct literal] syntax regardless of whether [`#[non_exhaustive]`][non_exhaustive] is used. Adding [`#[non_exhaustive]`][non_exhaustive] to such a struct is not a breaking change. ```rust,ignore // MAJOR CHANGE /////////////////////////////////////////////////////////// // Before pub struct Foo { pub bar: usize, } pub enum Bar { X, Y(usize), Z { a: usize }, } pub enum Quux { Var, } /////////////////////////////////////////////////////////// // After #[non_exhaustive] pub struct Foo { pub bar: usize, } pub enum Bar { #[non_exhaustive] X, #[non_exhaustive] Y(usize), #[non_exhaustive] Z { a: usize }, } #[non_exhaustive] pub enum Quux { Var, } /////////////////////////////////////////////////////////// // Example usage that will break. use updated_crate::{Bar, Foo, Quux}; fn main() { let foo = Foo { bar: 0 }; // Error: cannot create non-exhaustive struct using struct expression let bar_x = Bar::X; // Error: unit variant `X` is private let bar_y = Bar::Y(0); // Error: tuple variant `Y` is private let bar_z = Bar::Z { a: 0 }; // Error: cannot create non-exhaustive variant using struct expression let q = Quux::Var; match q { Quux::Var => 0, // Error: non-exhaustive patterns: `_` not covered }; } ``` Mitigation strategies: * Mark structs, enums, and enum variants as [`#[non_exhaustive]`][non_exhaustive] when first introducing them, rather than adding [`#[non_exhaustive]`][non_exhaustive] later on. ## Tooling and environment compatibility ### Possibly-breaking: changing the minimum version of Rust required {#env-new-rust} Introducing the use of new features in a new release of Rust can break projects that are using older versions of Rust. This also includes using new features in a new release of Cargo, and requiring the use of a nightly-only feature in a crate that previously worked on stable. It is generally recommended to treat this as a minor change, rather than as a major change, for [various reasons][msrv-is-minor]. It is usually relatively easy to update to a newer version of Rust. Rust also has a rapid 6-week release cycle, and some projects will provide compatibility within a window of releases (such as the current stable release plus N previous releases). Just keep in mind that some large projects may not be able to update their Rust toolchain rapidly. Mitigation strategies: * Use [Cargo features] to make the new features opt-in. * Provide a large window of support for older releases. * Copy the source of new standard library items if possible so that you can continue to use an older version but take advantage of the new feature. * Provide a separate branch of older minor releases that can receive backports of important bugfixes. * Keep an eye out for the [`[cfg(version(..))]`][cfg-version] and [`#[cfg(accessible(..))]`][cfg-accessible] features which provide an opt-in mechanism for new features. These are currently unstable and only available in the nightly channel. ### Possibly-breaking: changing the platform and environment requirements {#env-change-requirements} There is a very wide range of assumptions a library makes about the environment that it runs in, such as the host platform, operating system version, available services, filesystem support, etc. It can be a breaking change if you make a new release that restricts what was previously supported, for example requiring a newer version of an operating system. These changes can be difficult to track, since you may not always know if a change breaks in an environment that is not automatically tested. Some projects may deem this acceptable breakage, particularly if the breakage is unlikely for most users, or the project doesn't have the resources to support all environments. Another notable situation is when a vendor discontinues support for some hardware or OS, the project may deem it reasonable to also discontinue support. Mitigation strategies: * Document the platforms and environments you specifically support. * Test your code on a wide range of environments in CI. ### Minor: introducing new lints {#new-lints} Some changes to a library may cause new lints to be triggered in users of that library. This should generally be considered a compatible change. ```rust,ignore,dont-deny // MINOR CHANGE /////////////////////////////////////////////////////////// // Before pub fn foo() {} /////////////////////////////////////////////////////////// // After #[deprecated] pub fn foo() {} /////////////////////////////////////////////////////////// // Example use of the library that will safely work. fn main() { updated_crate::foo(); // Warning: use of deprecated function } ``` Beware that it may be possible for this to technically cause a project to fail if they have explicitly denied the warning, and the updated crate is a direct dependency. Denying warnings should be done with care and the understanding that new lints may be introduced over time. However, library authors should be cautious about introducing new warnings and may want to consider the potential impact on their users. The following lints are examples of those that may be introduced when updating a dependency: * [`deprecated`][deprecated-lint] --- Introduced when a dependency adds the [`#[deprecated]` attribute][deprecated] to an item you are using. * [`unused_must_use`] --- Introduced when a dependency adds the [`#[must_use]` attribute][must-use-attr] to an item where you are not consuming the result. * [`unused_unsafe`] --- Introduced when a dependency *removes* the `unsafe` qualifier from a function, and that is the only unsafe function called in an unsafe block. Additionally, updating `rustc` to a new version may introduce new lints. Transitive dependencies which introduce new lints should not usually cause a failure because Cargo uses [`--cap-lints`](../../rustc/lints/levels.html#capping-lints) to suppress all lints in dependencies. Mitigating strategies: * If you build with warnings denied, understand you may need to deal with resolving new warnings whenever you update your dependencies. If using RUSTFLAGS to pass `-Dwarnings`, also add the `-A` flag to allow lints that are likely to cause issues, such as `-Adeprecated`. * Introduce deprecations behind a [feature][Cargo features]. For example `#[cfg_attr(feature = "deprecated", deprecated="use bar instead")]`. Then, when you plan to remove an item in a future SemVer breaking change, you can communicate with your users that they should enable the `deprecated` feature *before* updating to remove the use of the deprecated items. This allows users to choose when to respond to deprecations without needing to immediately respond to them. A downside is that it can be difficult to communicate to users that they need to take these manual steps to prepare for a major update. [`unused_must_use`]: ../../rustc/lints/listing/warn-by-default.html#unused-must-use [deprecated-lint]: ../../rustc/lints/listing/warn-by-default.html#deprecated [must-use-attr]: ../../reference/attributes/diagnostics.html#the-must_use-attribute [`unused_unsafe`]: ../../rustc/lints/listing/warn-by-default.html#unused-unsafe ### Cargo #### Minor: adding a new Cargo feature {#cargo-feature-add} It is usually safe to add new [Cargo features]. If the feature introduces new changes that cause a breaking change, this can cause difficulties for projects that have stricter backwards-compatibility needs. In that scenario, avoid adding the feature to the "default" list, and possibly document the consequences of enabling the feature. ```toml # MINOR CHANGE ########################################################### # Before [features] # ..empty ########################################################### # After [features] std = [] ``` #### Major: removing a Cargo feature {#cargo-feature-remove} It is usually a breaking change to remove [Cargo features]. This will cause an error for any project that enabled the feature. ```toml # MAJOR CHANGE ########################################################### # Before [features] logging = [] ########################################################### # After [dependencies] # ..logging removed ``` Mitigation strategies: * Clearly document your features. If there is an internal or experimental feature, mark it as such, so that users know the status of the feature. * Leave the old feature in `Cargo.toml`, but otherwise remove its functionality. Document that the feature is deprecated, and remove it in a future major SemVer release. #### Major: removing a feature from a feature list if that changes functionality or public items {#cargo-feature-remove-another} If removing a feature from another feature, this can break existing users if they are expecting that functionality to be available through that feature. ```toml # Breaking change example ########################################################### # Before [features] default = ["std"] std = [] ########################################################### # After [features] default = [] # This may cause packages to fail if they are expecting std to be enabled. std = [] ``` #### Possibly-breaking: removing an optional dependency {#cargo-remove-opt-dep} Removing an [optional dependency][opt-dep] can break a project using your library because another project may be enabling that dependency via [Cargo features]. When there is an optional dependency, cargo implicitly defines a feature of the same name to provide a mechanism to enable the dependency and to check when it is enabled. This problem can be avoided by using the `dep:` syntax in the `[features]` table, which disables this implicit feature. Using `dep:` makes it possible to hide the existence of optional dependencies under more semantically-relevant names which can be more safely modified. ```toml # Breaking change example ########################################################### # Before [dependencies] curl = { version = "0.4.31", optional = true } ########################################################### # After [dependencies] # ..curl removed ``` ```toml # MINOR CHANGE # # This example shows how to avoid breaking changes with optional dependencies. ########################################################### # Before [dependencies] curl = { version = "0.4.31", optional = true } [features] networking = ["dep:curl"] ########################################################### # After [dependencies] # Here, one optional dependency was replaced with another. hyper = { version = "0.14.27", optional = true } [features] networking = ["dep:hyper"] ``` Mitigation strategies: * Use the `dep:` syntax in the `[features]` table to avoid exposing optional dependencies in the first place. See [optional dependencies][opt-dep] for more information. * Clearly document your features. If the optional dependency is not included in the documented list of features, then you may decide to consider it safe to change undocumented entries. * Leave the optional dependency, and just don't use it within your library. * Replace the optional dependency with a [Cargo feature] that does nothing, and document that it is deprecated. * Use high-level features which enable optional dependencies, and document those as the preferred way to enable the extended functionality. For example, if your library has optional support for something like "networking", create a generic feature name "networking" that enables the optional dependencies necessary to implement "networking". Then document the "networking" feature. [opt-dep]: features.md#optional-dependencies #### Minor: changing dependency features {#cargo-change-dep-feature} It is usually safe to change the features on a dependency, as long as the feature does not introduce a breaking change. ```toml # MINOR CHANGE ########################################################### # Before [dependencies] rand = { version = "0.7.3", features = ["small_rng"] } ########################################################### # After [dependencies] rand = "0.7.3" ``` #### Minor: adding dependencies {#cargo-dep-add} It is usually safe to add new dependencies, as long as the new dependency does not introduce new requirements that result in a breaking change. For example, adding a new dependency that requires nightly in a project that previously worked on stable is a major change. ```toml # MINOR CHANGE ########################################################### # Before [dependencies] # ..empty ########################################################### # After [dependencies] log = "0.4.11" ``` ## Application compatibility Cargo projects may also include executable binaries which have their own interfaces (such as a CLI interface, OS-level interaction, etc.). Since these are part of the Cargo package, they often use and share the same version as the package. You will need to decide if and how you want to employ a SemVer contract with your users in the changes you make to your application. The potential breaking and compatible changes to an application are too numerous to list, so you are encouraged to use the spirit of the [SemVer] spec to guide your decisions on how to apply versioning to your application, or at least document what your commitments are. [`cfg` attribute]: ../../reference/conditional-compilation.md#the-cfg-attribute [`no_std`]: ../../reference/names/preludes.html#the-no_std-attribute [`pub use`]: ../../reference/items/use-declarations.html [Cargo feature]: features.md [Cargo features]: features.md [cfg-accessible]: https://github.com/rust-lang/rust/issues/64797 [cfg-version]: https://github.com/rust-lang/rust/issues/64796 [conditional compilation]: ../../reference/conditional-compilation.md [Default]: ../../std/default/trait.Default.html [deprecated]: ../../reference/attributes/diagnostics.html#the-deprecated-attribute [disambiguation syntax]: ../../reference/expressions/call-expr.html#disambiguating-function-calls [functional update syntax]: ../../reference/expressions/struct-expr.html#functional-update-syntax [inherent implementations]: ../../reference/items/implementations.html#inherent-implementations [items]: ../../reference/items.html [non_exhaustive]: ../../reference/attributes/type_system.html#the-non_exhaustive-attribute [object safe]: ../../reference/items/traits.html#object-safety [rust-feature]: https://doc.rust-lang.org/nightly/unstable-book/ [sealed trait]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed [SemVer]: https://semver.org/ [struct literal]: ../../reference/expressions/struct-expr.html [wildcard patterns]: ../../reference/patterns.html#wildcard-pattern [unused_unsafe]: ../../rustc/lints/listing/warn-by-default.html#unused-unsafe [msrv-is-minor]: https://github.com/rust-lang/api-guidelines/discussions/231 cargo-0.86.0/src/doc/src/reference/source-replacement.md000064400000000000000000000123661046102023000212220ustar 00000000000000# Source Replacement This document is about replacing the crate index. You can read about overriding dependencies in the [overriding dependencies] section of this documentation. A *source* is a provider that contains crates that may be included as dependencies for a package. Cargo supports the ability to **replace one source with another** to express strategies such as: * Vendoring --- custom sources can be defined which represent crates on the local filesystem. These sources are subsets of the source that they're replacing and can be checked into packages if necessary. * Mirroring --- sources can be replaced with an equivalent version which acts as a cache for crates.io itself. Cargo has a core assumption about source replacement that the source code is exactly the same from both sources. Note that this also means that a replacement source is not allowed to have crates which are not present in the original source. As a consequence, source replacement is not appropriate for situations such as patching a dependency or a private registry. Cargo supports patching dependencies through the usage of [the `[patch]` key][overriding dependencies], and private registry support is described in [the Registries chapter][registries]. When using source replacement, running commands like `cargo publish` that need to contact the registry require passing the `--registry` option. This helps avoid any ambiguity about which registry to contact, and will use the authentication token for the specified registry. [overriding dependencies]: overriding-dependencies.md [registries]: registries.md ## Configuration Configuration of replacement sources is done through [`.cargo/config.toml`][config] and the full set of available keys are: ```toml # The `source` table is where all keys related to source-replacement # are stored. [source] # Under the `source` table are a number of other tables whose keys are a # name for the relevant source. For example this section defines a new # source, called `my-vendor-source`, which comes from a directory # located at `vendor` relative to the directory containing this `.cargo/config.toml` # file [source.my-vendor-source] directory = "vendor" # The crates.io default source for crates is available under the name # "crates-io", and here we use the `replace-with` key to indicate that it's # replaced with our source above. # # The `replace-with` key can also reference an alternative registry name # defined in the `[registries]` table. [source.crates-io] replace-with = "my-vendor-source" # Each source has its own table where the key is the name of the source [source.the-source-name] # Indicate that `the-source-name` will be replaced with `another-source`, # defined elsewhere replace-with = "another-source" # Several kinds of sources can be specified (described in more detail below): registry = "https://example.com/path/to/index" local-registry = "path/to/registry" directory = "path/to/vendor" # Git sources can optionally specify a branch/tag/rev as well git = "https://example.com/path/to/repo" # branch = "master" # tag = "v1.0.1" # rev = "313f44e8" ``` [config]: config.md ## Registry Sources A "registry source" is one that is the same as crates.io itself. That is, it has an index served in a git repository which matches the format of the [crates.io index](https://github.com/rust-lang/crates.io-index). That repository then has configuration indicating where to download crates from. Currently there is not an already-available project for setting up a mirror of crates.io. Stay tuned though! ## Local Registry Sources A "local registry source" is intended to be a subset of another registry source, but available on the local filesystem (aka vendoring). Local registries are downloaded ahead of time, typically sync'd with a `Cargo.lock`, and are made up of a set of `*.crate` files and an index like the normal registry is. The primary way to manage and create local registry sources is through the [`cargo-local-registry`][cargo-local-registry] subcommand, [available on crates.io][cargo-local-registry] and can be installed with `cargo install cargo-local-registry`. [cargo-local-registry]: https://crates.io/crates/cargo-local-registry Local registries are contained within one directory and contain a number of `*.crate` files downloaded from crates.io as well as an `index` directory with the same format as the crates.io-index project (populated with just entries for the crates that are present). ## Directory Sources A "directory source" is similar to a local registry source where it contains a number of crates available on the local filesystem, suitable for vendoring dependencies. Directory sources are primarily managed by the `cargo vendor` subcommand. Directory sources are distinct from local registries though in that they contain the unpacked version of `*.crate` files, making it more suitable in some situations to check everything into source control. A directory source is just a directory containing a number of other directories which contain the source code for crates (the unpacked version of `*.crate` files). Currently no restriction is placed on the name of each directory. Each crate in a directory source also has an associated metadata file indicating the checksum of each file in the crate to protect against accidental modifications. cargo-0.86.0/src/doc/src/reference/specifying-dependencies.md000064400000000000000000000605571046102023000222160ustar 00000000000000# Specifying Dependencies Your crates can depend on other libraries from [crates.io] or other registries, `git` repositories, or subdirectories on your local file system. You can also temporarily override the location of a dependency --- for example, to be able to test out a bug fix in the dependency that you are working on locally. You can have different dependencies for different platforms, and dependencies that are only used during development. Let's take a look at how to do each of these. ## Specifying dependencies from crates.io Cargo is configured to look for dependencies on [crates.io] by default. Only the name and a version string are required in this case. In [the cargo guide](../guide/index.md), we specified a dependency on the `time` crate: ```toml [dependencies] time = "0.1.12" ``` The version string `"0.1.12"` is called a [version requirement](#version-requirement-syntax). It specifies a range of versions that can be selected from when [resolving dependencies](resolver.md). In this case, `"0.1.12"` represents the version range `>=0.1.12, <0.2.0`. An update is allowed if it is within that range. In this case, if we ran `cargo update time`, cargo should update us to version `0.1.13` if it is the latest `0.1.z` release, but would not update us to `0.2.0`. ## Version requirement syntax ### Default requirements **Default requirements** specify a minimum version with the ability to update to [SemVer] compatible versions. Versions are considered compatible if their left-most non-zero major/minor/patch component is the same. This is different from [SemVer] which considers all pre-1.0.0 packages to be incompatible. `1.2.3` is an example of a default requirement. ```notrust 1.2.3 := >=1.2.3, <2.0.0 1.2 := >=1.2.0, <2.0.0 1 := >=1.0.0, <2.0.0 0.2.3 := >=0.2.3, <0.3.0 0.2 := >=0.2.0, <0.3.0 0.0.3 := >=0.0.3, <0.0.4 0.0 := >=0.0.0, <0.1.0 0 := >=0.0.0, <1.0.0 ``` ### Caret requirements **Caret requirements** are the default version requirement strategy. This version strategy allows [SemVer] compatible updates. They are specified as version requirements with a leading caret (`^`). `^1.2.3` is an example of a caret requirement. Leaving off the caret is a simplified equivalent syntax to using caret requirements. While caret requirements are the default, it is recommended to use the simplified syntax when possible. `log = "^1.2.3"` is exactly equivalent to `log = "1.2.3"`. ### Tilde requirements **Tilde requirements** specify a minimal version with some ability to update. If you specify a major, minor, and patch version or only a major and minor version, only patch-level changes are allowed. If you only specify a major version, then minor- and patch-level changes are allowed. `~1.2.3` is an example of a tilde requirement. ```notrust ~1.2.3 := >=1.2.3, <1.3.0 ~1.2 := >=1.2.0, <1.3.0 ~1 := >=1.0.0, <2.0.0 ``` ### Wildcard requirements **Wildcard requirements** allow for any version where the wildcard is positioned. `*`, `1.*` and `1.2.*` are examples of wildcard requirements. ```notrust * := >=0.0.0 1.* := >=1.0.0, <2.0.0 1.2.* := >=1.2.0, <1.3.0 ``` > **Note**: [crates.io] does not allow bare `*` versions. ### Comparison requirements **Comparison requirements** allow manually specifying a version range or an exact version to depend on. Here are some examples of comparison requirements: ```notrust >= 1.2.0 > 1 < 2 = 1.2.3 ``` ### Multiple version requirements As shown in the examples above, multiple version requirements can be separated with a comma, e.g., `>= 1.2, < 1.5`. ### Pre-releases Version requirements exclude [pre-release versions](manifest.md#the-version-field), such as `1.0.0-alpha`, unless specifically asked for. For example, if `1.0.0-alpha` of package `foo` is published, then a requirement of `foo = "1.0"` will *not* match, and will return an error. The pre-release must be specified, such as `foo = "1.0.0-alpha"`. Similarly [`cargo install`] will avoid pre-releases unless explicitly asked to install one. Cargo allows "newer" pre-releases to be used automatically. For example, if `1.0.0-beta` is published, then a requirement `foo = "1.0.0-alpha"` will allow updating to the `beta` version. Note that this only works on the same release version, `foo = "1.0.0-alpha"` will not allow updating to `foo = "1.0.1-alpha"` or `foo = "1.0.1-beta"`. Cargo will also upgrade automatically to semver-compatible released versions from prereleases. The requirement `foo = "1.0.0-alpha"` will allow updating to `foo = "1.0.0"` as well as `foo = "1.2.0"`. Beware that pre-release versions can be unstable, and as such care should be taken when using them. Some projects may choose to publish breaking changes between pre-release versions. It is recommended to not use pre-release dependencies in a library if your library is not also a pre-release. Care should also be taken when updating your `Cargo.lock`, and be prepared if a pre-release update causes issues. [`cargo install`]: ../commands/cargo-install.md ### Version metadata [Version metadata](manifest.md#the-version-field), such as `1.0.0+21AF26D3`, is ignored and should not be used in version requirements. > **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 > 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 [#9029]). > 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 [#9029]: https://github.com/rust-lang/cargo/issues/9029 [#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] set the `registry` key to the name of the registry to use: ```toml [dependencies] some-crate = { version = "1.0", registry = "my-registry" } ``` where `my-registry` is the registry name configured in `.cargo/config.toml` file. See the [registries documentation] for more information. > **Note**: [crates.io] does not allow packages to be published with > dependencies on code published outside of [crates.io]. [registries documentation]: registries.md ## Specifying dependencies from `git` repositories To depend on a library located in a `git` repository, the minimum information you need to specify is the location of the repository with the `git` key: ```toml [dependencies] regex = { git = "https://github.com/rust-lang/regex.git" } ``` Cargo fetches the `git` repository at that location and traverses the file tree to find `Cargo.toml` file for the requested crate anywhere inside the `git` repository. For example, `regex-lite` and `regex-syntax` are members of `rust-lang/regex` repo and can be referred to by the repo's root URL (`https://github.com/rust-lang/regex.git`) regardless of where in the file tree they reside. ```toml regex-lite = { git = "https://github.com/rust-lang/regex.git" } regex-syntax = { git = "https://github.com/rust-lang/regex.git" } ``` The above rule does not apply to [`path` dependencies](#specifying-path-dependencies). ### Choice of commit Cargo assumes that we intend to use the latest commit on the default branch to build our package if we only specify the repo URL, as in the examples above. You can combine the `git` key with the `rev`, `tag`, or `branch` keys to be more specific about which commit to use. Here's an example of using the latest commit on a branch named `next`: ```toml [dependencies] regex = { git = "https://github.com/rust-lang/regex.git", branch = "next" } ``` Anything that is not a branch or a tag falls under `rev` key. This can be a commit hash like `rev = "4c59b707"`, or a named reference exposed by the remote repository such as `rev = "refs/pull/493/head"`. What references are available for the `rev` key varies by where the repo is hosted. GitHub exposes a reference to the most recent commit of every pull request as in the example above. Other git hosts may provide something equivalent under a different naming scheme. **More `git` dependency examples:** ```toml # .git suffix can be omitted if the host accepts such URLs - both examples work the same regex = { git = "https://github.com/rust-lang/regex" } regex = { git = "https://github.com/rust-lang/regex.git" } # a commit with a particular tag regex = { git = "https://github.com/rust-lang/regex.git", tag = "1.10.3" } # a commit by its SHA1 hash regex = { git = "https://github.com/rust-lang/regex.git", rev = "0c0990399270277832fbb5b91a1fa118e6f63dba" } # HEAD commit of PR 493 regex = { git = "https://github.com/rust-lang/regex.git", rev = "refs/pull/493/head" } # INVALID EXAMPLES # specifying the commit after # ignores the commit ID and generates a warning regex = { git = "https://github.com/rust-lang/regex.git#4c59b70" } # git and path cannot be used at the same time regex = { git = "https://github.com/rust-lang/regex.git#4c59b70", path = "../regex" } ``` Cargo locks the commits of `git` dependencies in `Cargo.lock` file at the time of their addition and checks for updates only when you run `cargo update` command. ### The role of the `version` key The `version` key always implies that the package is available in a registry, regardless of the presence of `git` or `path` keys. The `version` key does _not_ affect which commit is used when Cargo retrieves the `git` dependency, but Cargo checks the version information in the dependency's `Cargo.toml` file against the `version` key and raises an error if the check fails. In this example, Cargo retrieves the HEAD commit of the branch called `next` from Git and checks if the crate's version is compatible with `version = "1.10.3"`: ```toml [dependencies] regex = { version = "1.10.3", git = "https://github.com/rust-lang/regex.git", branch = "next" } ``` `version`, `git`, and `path` keys are considered separate locations for resolving the dependency. See [Multiple locations](#multiple-locations) section below for detailed explanations. > **Note**: [crates.io] does not allow packages to be published with > dependencies on code published outside of [crates.io] itself > ([dev-dependencies] are ignored). See the [Multiple > locations](#multiple-locations) section for a fallback alternative for `git` > and `path` dependencies. ### Accessing private Git repositories See [Git Authentication](../appendix/git-authentication.md) for help with Git authentication for private repos. ## Specifying path dependencies Over time, our `hello_world` package from [the guide](../guide/index.md) has grown significantly in size! It’s gotten to the point that we probably want to split out a separate crate for others to use. To do this Cargo supports **path dependencies** which are typically sub-crates that live within one repository. Let’s start by making a new crate inside of our `hello_world` package: ```console # inside of hello_world/ $ cargo new hello_utils ``` This will create a new folder `hello_utils` inside of which a `Cargo.toml` and `src` folder are ready to be configured. To tell Cargo about this, open up `hello_world/Cargo.toml` and add `hello_utils` to your dependencies: ```toml [dependencies] hello_utils = { path = "hello_utils" } ``` This tells Cargo that we depend on a crate called `hello_utils` which is found in the `hello_utils` folder, relative to the `Cargo.toml` file it’s written in. The next `cargo build` will automatically build `hello_utils` and all of its dependencies. ### No local path traversal The local paths must point to the exact folder with the dependency's `Cargo.toml`. Unlike with `git` dependencies, Cargo does not traverse local paths. For example, if `regex-lite` and `regex-syntax` are members of a locally cloned `rust-lang/regex` repo, they have to be referred to by the full path: ```toml # git key accepts the repo root URL and Cargo traverses the tree to find the crate [dependencies] regex-lite = { git = "https://github.com/rust-lang/regex.git" } regex-syntax = { git = "https://github.com/rust-lang/regex.git" } # path key requires the member name to be included in the local path [dependencies] regex-lite = { path = "../regex/regex-lite" } regex-syntax = { path = "../regex/regex-syntax" } ``` ### Local paths in published crates Crates that use dependencies specified with only a path are not permitted on [crates.io]. If we wanted to publish our `hello_world` crate, we would need to publish a version of `hello_utils` to [crates.io] as a separate crate and specify its version in the dependencies line of `hello_world`: ```toml [dependencies] hello_utils = { path = "hello_utils", version = "0.1.0" } ``` The use of `path` and `version` keys together is explained in the [Multiple locations](#multiple-locations) section. > **Note**: [crates.io] does not allow packages to be published with > dependencies on code outside of [crates.io], except for [dev-dependencies]. > See the [Multiple locations](#multiple-locations) section > for a fallback alternative for `git` and `path` dependencies. ## Multiple locations It is possible to specify both a registry version and a `git` or `path` location. The `git` or `path` dependency will be used locally (in which case the `version` is checked against the local copy), and when published to a registry like [crates.io], it will use the registry version. Other combinations are not allowed. Examples: ```toml [dependencies] # Uses `my-bitflags` when used locally, and uses # version 1.0 from crates.io when published. bitflags = { path = "my-bitflags", version = "1.0" } # Uses the given git repo when used locally, and uses # version 1.0 from crates.io when published. smallvec = { git = "https://github.com/servo/rust-smallvec.git", version = "1.0" } # N.B. that if a version doesn't match, Cargo will fail to compile! ``` One example where this can be useful is when you have split up a library into multiple packages within the same workspace. You can then use `path` dependencies to point to the local packages within the workspace to use the local version during development, and then use the [crates.io] version once it is published. This is similar to specifying an [override](overriding-dependencies.md), but only applies to this one dependency declaration. ## Platform specific dependencies Platform-specific dependencies take the same format, but are listed under a `target` section. Normally Rust-like [`#[cfg]` syntax](../../reference/conditional-compilation.html) will be used to define these sections: ```toml [target.'cfg(windows)'.dependencies] winhttp = "0.4.0" [target.'cfg(unix)'.dependencies] openssl = "1.0.1" [target.'cfg(target_arch = "x86")'.dependencies] native-i686 = { path = "native/i686" } [target.'cfg(target_arch = "x86_64")'.dependencies] native-x86_64 = { path = "native/x86_64" } ``` Like with Rust, the syntax here supports the `not`, `any`, and `all` operators to combine various cfg name/value pairs. If you want to know which cfg targets are available on your platform, run `rustc --print=cfg` from the command line. If you want to know which `cfg` targets are available for another platform, such as 64-bit Windows, run `rustc --print=cfg --target=x86_64-pc-windows-msvc`. Unlike in your Rust source code, you cannot use `[target.'cfg(feature = "fancy-feature")'.dependencies]` to add dependencies based on optional features. Use [the `[features]` section](features.md) instead: ```toml [dependencies] foo = { version = "1.0", optional = true } bar = { version = "1.0", optional = true } [features] fancy-feature = ["foo", "bar"] ``` The same applies to `cfg(debug_assertions)`, `cfg(test)` and `cfg(proc_macro)`. These values will not work as expected and will always have the default value returned by `rustc --print=cfg`. There is currently no way to add dependencies based on these configuration values. In addition to `#[cfg]` syntax, Cargo also supports listing out the full target the dependencies would apply to: ```toml [target.x86_64-pc-windows-gnu.dependencies] winhttp = "0.4.0" [target.i686-unknown-linux-gnu.dependencies] openssl = "1.0.1" ``` ### Custom target specifications If you’re using a custom target specification (such as `--target foo/bar.json`), use the base filename without the `.json` extension: ```toml [target.bar.dependencies] winhttp = "0.4.0" [target.my-special-i686-platform.dependencies] openssl = "1.0.1" native = { path = "native/i686" } ``` > **Note**: Custom target specifications are not usable on the stable channel. ## Development dependencies You can add a `[dev-dependencies]` section to your `Cargo.toml` whose format is equivalent to `[dependencies]`: ```toml [dev-dependencies] tempdir = "0.3" ``` Dev-dependencies are not used when compiling a package for building, but are used for compiling tests, examples, and benchmarks. These dependencies are *not* propagated to other packages which depend on this package. You can also have target-specific development dependencies by using `dev-dependencies` in the target section header instead of `dependencies`. For example: ```toml [target.'cfg(unix)'.dev-dependencies] mio = "0.0.1" ``` > **Note**: When a package is published, only dev-dependencies that specify a > `version` will be included in the published crate. For most use cases, > dev-dependencies are not needed when published, though some users (like OS > packagers) may want to run tests within a crate, so providing a `version` if > possible can still be beneficial. ## Build dependencies You can depend on other Cargo-based crates for use in your build scripts. Dependencies are declared through the `build-dependencies` section of the manifest: ```toml [build-dependencies] cc = "1.0.3" ``` You can also have target-specific build dependencies by using `build-dependencies` in the target section header instead of `dependencies`. For example: ```toml [target.'cfg(unix)'.build-dependencies] cc = "1.0.3" ``` In this case, the dependency will only be built when the host platform matches the specified target. The build script **does not** have access to the dependencies listed in the `dependencies` or `dev-dependencies` section. Build dependencies will likewise not be available to the package itself unless listed under the `dependencies` section as well. A package itself and its build script are built separately, so their dependencies need not coincide. Cargo is kept simpler and cleaner by using independent dependencies for independent purposes. ## Choosing features If a package you depend on offers conditional features, you can specify which to use: ```toml [dependencies.awesome] version = "1.3.5" default-features = false # do not include the default features, and optionally # cherry-pick individual features features = ["secure-password", "civet"] ``` More information about features can be found in the [features chapter](features.md#dependency-features). ## Renaming dependencies in `Cargo.toml` When writing a `[dependencies]` section in `Cargo.toml` the key you write for a dependency typically matches up to the name of the crate you import from in the code. For some projects, though, you may wish to reference the crate with a different name in the code regardless of how it's published on crates.io. For example you may wish to: * Avoid the need to `use foo as bar` in Rust source. * Depend on multiple versions of a crate. * Depend on crates with the same name from different registries. To support this Cargo supports a `package` key in the `[dependencies]` section of which package should be depended on: ```toml [package] name = "mypackage" version = "0.0.1" [dependencies] foo = "0.1" bar = { git = "https://github.com/example/project.git", package = "foo" } baz = { version = "0.1", registry = "custom", package = "foo" } ``` In this example, three crates are now available in your Rust code: ```rust,ignore extern crate foo; // crates.io extern crate bar; // git repository extern crate baz; // registry `custom` ``` All three of these crates have the package name of `foo` in their own `Cargo.toml`, so we're explicitly using the `package` key to inform Cargo that we want the `foo` package even though we're calling it something else locally. The `package` key, if not specified, defaults to the name of the dependency being requested. Note that if you have an optional dependency like: ```toml [dependencies] bar = { version = "0.1", package = 'foo', optional = true } ``` you're depending on the crate `foo` from crates.io, but your crate has a `bar` feature instead of a `foo` feature. That is, names of features take after the name of the dependency, not the package name, when renamed. Enabling transitive dependencies works similarly, for example we could add the following to the above manifest: ```toml [features] log-debug = ['bar/log-debug'] # using 'foo/log-debug' would be an error! ``` ## Inheriting a dependency from a workspace Dependencies can be inherited from a workspace by specifying the dependency in the workspace's [`[workspace.dependencies]`][workspace.dependencies] table. After that, add it to the `[dependencies]` table with `workspace = true`. Along with the `workspace` key, dependencies can also include these keys: - [`optional`][optional]: Note that the`[workspace.dependencies]` table is not allowed to specify `optional`. - [`features`][features]: These are additive with the features declared in the `[workspace.dependencies]` Other than `optional` and `features`, inherited dependencies cannot use any other dependency key (such as `version` or `default-features`). Dependencies in the `[dependencies]`, `[dev-dependencies]`, `[build-dependencies]`, and `[target."...".dependencies]` sections support the ability to reference the `[workspace.dependencies]` definition of dependencies. ```toml [package] name = "bar" version = "0.2.0" [dependencies] regex = { workspace = true, features = ["unicode"] } [build-dependencies] cc.workspace = true [dev-dependencies] rand = { workspace = true, optional = true } ``` [SemVer]: https://semver.org [crates.io]: https://crates.io/ [dev-dependencies]: #development-dependencies [workspace.dependencies]: workspaces.md#the-dependencies-table [optional]: features.md#optional-dependencies [features]: features.md cargo-0.86.0/src/doc/src/reference/timings.md000064400000000000000000000056221046102023000170740ustar 00000000000000# Reporting build timings The `--timings` option gives some information about how long each compilation takes, and tracks concurrency information over time. ```sh cargo build --timings ``` This writes an HTML report in `target/cargo-timings/cargo-timing.html`. This also writes a copy of the report to the same directory with a timestamp in the filename, if you want to look at older runs. ## Reading the graphs There are two tables and two graphs in the output. The first table displays the build information of the project, including the number of units built, the maximum number of concurrency, build time, and the version information of the currently used compiler. ![build-info](../images/build-info.png) The "unit" graph shows the duration of each unit over time. A "unit" is a single compiler invocation. There are lines that show which additional units are "unlocked" when a unit finishes. That is, it shows the new units that are now allowed to run because their dependencies are all finished. Hover the mouse over a unit to highlight the lines. This can help visualize the critical path of dependencies. This may change between runs because the units may finish in different orders. The "codegen" times are highlighted in a lavender color. In some cases, build pipelining allows units to start when their dependencies are performing code generation. This information is not always displayed (for example, binary units do not show when code generation starts). The "custom build" units are `build.rs` scripts, which when run are highlighted in orange. ![build-unit-time](../images/build-unit-time.png) The second graph shows Cargo's concurrency over time. The background indicates CPU usage. The three lines are: - "Waiting" (red) --- This is the number of units waiting for a CPU slot to open. - "Inactive" (blue) --- This is the number of units that are waiting for their dependencies to finish. - "Active" (green) --- This is the number of units currently running. ![cargo-concurrency-over-time](../images/cargo-concurrency-over-time.png) Note: This does not show the concurrency in the compiler itself. `rustc` coordinates with Cargo via the "job server" to stay within the concurrency limit. This currently mostly applies to the code generation phase. Tips for addressing compile times: - Look for slow dependencies. - Check if they have features that you may wish to consider disabling. - Consider trying to remove the dependency completely. - Look for a crate being built multiple times with different versions. Try to remove the older versions from the dependency graph. - Split large crates into smaller pieces. - If there are a large number of crates bottlenecked on a single crate, focus your attention on improving that one crate to improve parallelism. The last table lists the total time and "codegen" time spent on each unit, as well as the features that were enabled during each unit's compilation. cargo-0.86.0/src/doc/src/reference/unstable.md000064400000000000000000002437571046102023000172540ustar 00000000000000# Unstable Features Experimental Cargo features are only available on the [nightly channel]. You are encouraged to experiment with these features to see if they meet your needs, and if there are any issues or problems. Check the linked tracking issues listed below for more information on the feature, and click the GitHub subscribe button if you want future updates. After some period of time, if the feature does not have any major concerns, it can be [stabilized], which will make it available on stable once the current nightly release reaches the stable channel (anywhere from 6 to 12 weeks). There are three different ways that unstable features can be enabled based on how the feature works: * New syntax in `Cargo.toml` requires a `cargo-features` key at the top of `Cargo.toml`, before any tables. For example: ```toml # This specifies which new Cargo.toml features are enabled. cargo-features = ["test-dummy-unstable"] [package] name = "my-package" version = "0.1.0" im-a-teapot = true # This is a new option enabled by test-dummy-unstable. ``` * New command-line flags, options, and subcommands require the `-Z unstable-options` CLI option to also be included. For example, the new `--artifact-dir` option is only available on nightly: ```cargo +nightly build --artifact-dir=out -Z unstable-options``` * `-Z` command-line flags are used to enable new functionality that may not have an interface, or the interface has not yet been designed, or for more complex features that affect multiple parts of Cargo. For example, the [mtime-on-use](#mtime-on-use) feature can be enabled with: ```cargo +nightly build -Z mtime-on-use``` Run `cargo -Z help` to see a list of flags available. Anything which can be configured with a `-Z` flag can also be set in the cargo [config file] (`.cargo/config.toml`) in the `unstable` table. For example: ```toml [unstable] mtime-on-use = true build-std = ["core", "alloc"] ``` 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 ## List of unstable features * Unstable-specific features * [-Z allow-features](#allow-features) --- Provides a way to restrict which unstable features are used. * Build scripts and linking * [Metabuild](#metabuild) --- Provides declarative build scripts. * Resolver and features * [no-index-update](#no-index-update) --- Prevents cargo from updating the index cache. * [avoid-dev-deps](#avoid-dev-deps) --- Prevents the resolver from including dev-dependencies during resolution. * [minimal-versions](#minimal-versions) --- Forces the resolver to use the lowest compatible version instead of the highest. * [direct-minimal-versions](#direct-minimal-versions) β€” Forces the resolver to use the lowest compatible version instead of the highest. * [public-dependency](#public-dependency) --- Allows dependencies to be classified as either public or private. * [msrv-policy](#msrv-policy) --- MSRV-aware resolver and version selection * [precise-pre-release](#precise-pre-release) --- Allows pre-release versions to be selected with `update --precise` * [update-breaking](#update-breaking) --- Allows upgrading to breaking versions with `update --breaking` * Output behavior * [artifact-dir](#artifact-dir) --- Adds a directory where artifacts are copied to. * [Different binary name](#different-binary-name) --- Assign a name to the built binary that is separate from the crate name. * [root-dir](#root-dir) --- Controls the root directory relative to which paths are printed * Compile behavior * [mtime-on-use](#mtime-on-use) --- Updates the last-modified timestamp on every dependency every time it is used, to provide a mechanism to delete unused artifacts. * [doctest-xcompile](#doctest-xcompile) --- Supports running doctests with the `--target` flag. * [build-std](#build-std) --- Builds the standard library instead of using pre-built binaries. * [build-std-features](#build-std-features) --- Sets features to use with the standard library. * [binary-dep-depinfo](#binary-dep-depinfo) --- Causes the dep-info file to track binary dependencies. * [checksum-freshness](#checksum-freshness) --- When passed, the decision as to whether a crate needs to be rebuilt is made using file checksums instead of the file mtime. * [panic-abort-tests](#panic-abort-tests) --- Allows running tests with the "abort" panic strategy. * [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. * [gc](#gc) --- Global cache garbage collection. * [open-namespaces](#open-namespaces) --- Allow multiple packages to participate in the same API namespace * rustdoc * [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. * [output-format](#output-format-for-rustdoc) --- Allows documentation to also be emitted in the experimental [JSON format](https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc_json_types/). * `Cargo.toml` extensions * [Profile `rustflags` option](#profile-rustflags-option) --- Passed directly to rustc. * [codegen-backend](#codegen-backend) --- Select the codegen backend used by rustc. * [per-package-target](#per-package-target) --- Sets the `--target` to use for each individual package. * [artifact dependencies](#artifact-dependencies) --- Allow build artifacts to be included into other build artifacts and build them for different targets. * [Profile `trim-paths` option](#profile-trim-paths-option) --- Control the sanitization of file paths in build outputs. * [`[lints.cargo]`](#lintscargo) --- Allows configuring lints for Cargo. * [path bases](#path-bases) --- Named base directories for path dependencies. * Information and metadata * [Build-plan](#build-plan) --- Emits JSON information on which commands will be run. * [unit-graph](#unit-graph) --- Emits JSON for Cargo's internal graph structure. * [`cargo rustc --print`](#rustc---print) --- Calls rustc with `--print` to display information from rustc. * Configuration * [config-include](#config-include) --- Adds the ability for config files to include other files. * [`cargo config`](#cargo-config) --- Adds a new subcommand for viewing config files. * Registries * [publish-timeout](#publish-timeout) --- Controls the timeout between uploading the crate and being available in the index * [asymmetric-token](#asymmetric-token) --- Adds support for authentication tokens using asymmetric cryptography (`cargo:paseto` provider). * Other * [gitoxide](#gitoxide) --- Use `gitoxide` instead of `git2` for a set of operations. * [script](#script) --- Enable support for single-file `.rs` packages. * [lockfile-path](#lockfile-path) --- Allows to specify a path to lockfile other than the default path `/Cargo.lock`. * [package-workspace](#package-workspace) --- Allows for packaging and publishing multiple crates in a workspace. * [native-completions](#native-completions) --- Move cargo shell completions to native completions. * [warnings](#warnings) --- controls warning behavior; options for allowing or denying warnings. ## allow-features This permanently-unstable flag makes it so that only a listed set of unstable features can be used. Specifically, if you pass `-Zallow-features=foo,bar`, you'll continue to be able to pass `-Zfoo` and `-Zbar` to `cargo`, but you will be unable to pass `-Zbaz`. You can pass an empty string (`-Zallow-features=`) to disallow all unstable features. `-Zallow-features` also restricts which unstable features can be passed to the `cargo-features` entry in `Cargo.toml`. If, for example, you want to allow ```toml cargo-features = ["test-dummy-unstable"] ``` where `test-dummy-unstable` is unstable, that features would also be disallowed by `-Zallow-features=`, and allowed with `-Zallow-features=test-dummy-unstable`. The list of features passed to cargo's `-Zallow-features` is also passed to any Rust tools that cargo ends up calling (like `rustc` or `rustdoc`). Thus, if you run `cargo -Zallow-features=`, no unstable Cargo _or_ Rust features can be used. ## no-index-update * Original Issue: [#3479](https://github.com/rust-lang/cargo/issues/3479) * Tracking Issue: [#7404](https://github.com/rust-lang/cargo/issues/7404) The `-Z no-index-update` flag ensures that Cargo does not attempt to update the registry index. This is intended for tools such as Crater that issue many Cargo commands, and you want to avoid the network latency for updating the index each time. ## mtime-on-use * Original Issue: [#6477](https://github.com/rust-lang/cargo/pull/6477) * Cache usage meta tracking issue: [#7150](https://github.com/rust-lang/cargo/issues/7150) The `-Z mtime-on-use` flag is an experiment to have Cargo update the mtime of used files to make it easier for tools like cargo-sweep to detect which files are stale. For many workflows this needs to be set on *all* invocations of cargo. To make this more practical setting the `unstable.mtime_on_use` flag in `.cargo/config.toml` or the corresponding ENV variable will apply the `-Z mtime-on-use` to all invocations of nightly cargo. (the config flag is ignored by stable) ## avoid-dev-deps * Original Issue: [#4988](https://github.com/rust-lang/cargo/issues/4988) * Tracking Issue: [#5133](https://github.com/rust-lang/cargo/issues/5133) When running commands such as `cargo install` or `cargo build`, Cargo currently requires dev-dependencies to be downloaded, even if they are not used. The `-Z avoid-dev-deps` flag allows Cargo to avoid downloading dev-dependencies if they are not needed. The `Cargo.lock` file will not be generated if dev-dependencies are skipped. ## minimal-versions * Original Issue: [#4100](https://github.com/rust-lang/cargo/issues/4100) * Tracking Issue: [#5657](https://github.com/rust-lang/cargo/issues/5657) > Note: It is not recommended to use this feature. Because it enforces minimal > versions for all transitive dependencies, its usefulness is limited since > not all external dependencies declare proper lower version bounds. It is > intended that it will be changed in the future to only enforce minimal > versions for direct dependencies. When a `Cargo.lock` file is generated, the `-Z minimal-versions` flag will resolve the dependencies to the minimum SemVer version that will satisfy the requirements (instead of the greatest version). The intended use-case of this flag is to check, during continuous integration, that the versions specified in Cargo.toml are a correct reflection of the minimum versions that you are actually using. That is, if Cargo.toml says `foo = "1.0.0"` that you don't accidentally depend on features added only in `foo 1.5.0`. ## direct-minimal-versions * Original Issue: [#4100](https://github.com/rust-lang/cargo/issues/4100) * Tracking Issue: [#5657](https://github.com/rust-lang/cargo/issues/5657) When a `Cargo.lock` file is generated, the `-Z direct-minimal-versions` flag will resolve the dependencies to the minimum SemVer version that will satisfy the requirements (instead of the greatest version) for direct dependencies only. The intended use-case of this flag is to check, during continuous integration, that the versions specified in Cargo.toml are a correct reflection of the minimum versions that you are actually using. That is, if Cargo.toml says `foo = "1.0.0"` that you don't accidentally depend on features added only in `foo 1.5.0`. Indirect dependencies are resolved as normal so as not to be blocked on their minimal version validation. ## artifact-dir * Original Issue: [#4875](https://github.com/rust-lang/cargo/issues/4875) * Tracking Issue: [#6790](https://github.com/rust-lang/cargo/issues/6790) This feature allows you to specify the directory where artifacts will be copied to after they are built. Typically artifacts are only written to the `target/release` or `target/debug` directories. However, determining the exact filename can be tricky since you need to parse JSON output. The `--artifact-dir` flag makes it easier to predictably access the artifacts. Note that the artifacts are copied, so the originals are still in the `target` directory. Example: ```sh cargo +nightly build --artifact-dir=out -Z unstable-options ``` This can also be specified in `.cargo/config.toml` files. ```toml [build] artifact-dir = "out" ``` ## root-dir * Original Issue: [#9887](https://github.com/rust-lang/cargo/issues/9887) * Tracking Issue: None (not currently slated for stabilization) The `-Zroot-dir` flag sets the root directory relative to which paths are printed. This affects both diagnostics and paths emitted by the `file!()` macro. ## doctest-xcompile * Tracking Issue: [#7040](https://github.com/rust-lang/cargo/issues/7040) * Tracking Rustc Issue: [#64245](https://github.com/rust-lang/rust/issues/64245) This flag changes `cargo test`'s behavior when handling doctests when a target is passed. Currently, if a target is passed that is different from the host cargo will simply skip testing doctests. If this flag is present, cargo will continue as normal, passing the tests to doctest, while also passing it a `--target` option, as well as enabling `-Zunstable-features --enable-per-target-ignores` and passing along information from `.cargo/config.toml`. See the rustc issue for more information. ```sh cargo test --target foo -Zdoctest-xcompile ``` ## Build-plan * Tracking Issue: [#5579](https://github.com/rust-lang/cargo/issues/5579)
> The build-plan feature is deprecated and may be removed in a future version. > See .
The `--build-plan` argument for the `build` command will output JSON with information about which commands would be run without actually executing anything. This can be useful when integrating with another build tool. Example: ```sh cargo +nightly build --build-plan -Z unstable-options ``` ## Metabuild * Tracking Issue: [rust-lang/rust#49803](https://github.com/rust-lang/rust/issues/49803) * RFC: [#2196](https://github.com/rust-lang/rfcs/blob/master/text/2196-metabuild.md) Metabuild is a feature to have declarative build scripts. Instead of writing a `build.rs` script, you specify a list of build dependencies in the `metabuild` key in `Cargo.toml`. A build script is automatically generated that runs each build dependency in order. Metabuild packages can then read metadata from `Cargo.toml` to specify their behavior. Include `cargo-features` at the top of `Cargo.toml`, a `metabuild` key in the `package`, list the dependencies in `build-dependencies`, and add any metadata that the metabuild packages require under `package.metadata`. Example: ```toml cargo-features = ["metabuild"] [package] name = "mypackage" version = "0.0.1" metabuild = ["foo", "bar"] [build-dependencies] foo = "1.0" bar = "1.0" [package.metadata.foo] extra-info = "qwerty" ``` Metabuild packages should have a public function called `metabuild` that performs the same actions as a regular `build.rs` script would perform. ## public-dependency * Tracking Issue: [#44663](https://github.com/rust-lang/rust/issues/44663) The 'public-dependency' feature allows marking dependencies as 'public' or 'private'. When this feature is enabled, additional information is passed to rustc to allow the [exported_private_dependencies](../../rustc/lints/listing/warn-by-default.html#exported-private-dependencies) lint to function properly. To enable this feature, you can either use `-Zpublic-dependency` ```sh cargo +nightly run -Zpublic-dependency ``` or `[unstable]` table, for example, ```toml # .cargo/config.toml [unstable] public-dependency = true ``` `public-dependency` could also be enabled in `cargo-features`, **though this is deprecated and will be removed soon**. ```toml cargo-features = ["public-dependency"] [dependencies] my_dep = { version = "1.2.3", public = true } private_dep = "2.0.0" # Will be 'private' by default ``` Documentation updates: - For workspace's "The `dependencies` table" section, include `public` as an unsupported field for `workspace.dependencies` ## msrv-policy - [RFC: MSRV-aware Resolver](https://rust-lang.github.io/rfcs/3537-msrv-resolver.html) - [#9930](https://github.com/rust-lang/cargo/issues/9930) (MSRV-aware resolver) Catch-all unstable feature for MSRV-aware cargo features under [RFC 2495](https://github.com/rust-lang/rfcs/pull/2495). ### MSRV-aware cargo add This was stabilized in 1.79 in [#13608](https://github.com/rust-lang/cargo/pull/13608). ### MSRV-aware resolver This was stabilized in 1.84 in [#14639](https://github.com/rust-lang/cargo/pull/14639). ### Convert `incompatible_toolchain` error into a lint Unimplemented ### `--update-rust-version` flag for `cargo add`, `cargo update` Unimplemented ### `package.rust-version = "toolchain"` Unimplemented ### Update `cargo new` template to set `package.rust-version = "toolchain"` Unimplemented ## precise-pre-release * Tracking Issue: [#13290](https://github.com/rust-lang/cargo/issues/13290) * RFC: [#3493](https://github.com/rust-lang/rfcs/pull/3493) The `precise-pre-release` feature allows pre-release versions to be selected with `update --precise` even when a pre-release is not specified by a projects `Cargo.toml`. Take for example this `Cargo.toml`. ```toml [dependencies] my-dependency = "0.1.1" ``` It's possible to update `my-dependency` to a pre-release with `update -Zunstable-options my-dependency --precise 0.1.2-pre.0`. This is because `0.1.2-pre.0` is considered compatible with `0.1.1`. It would not be possible to upgrade to `0.2.0-pre.0` from `0.1.1` in the same way. ## update-breaking * Tracking Issue: [#12425](https://github.com/rust-lang/cargo/issues/12425) Allow upgrading dependencies version requirements in `Cargo.toml` across SemVer incompatible versions using with the `--breaking` flag. This only applies to dependencies when - The package is a dependency of a workspace member - The dependency is not renamed - A SemVer-incompatible version is available - The "SemVer operator" is used (`^` which is the default) Users may further restrict which packages get upgraded by specifying them on the command line. Example: ```console $ cargo +nightly -Zunstable-options update --breaking $ cargo +nightly -Zunstable-options update --breaking clap ``` *This is meant to fill a similar role as [cargo-upgrade](https://github.com/killercup/cargo-edit/)* ## build-std * Tracking Repository: The `build-std` feature enables Cargo to compile the standard library itself as part of a crate graph compilation. This feature has also historically been known as "std-aware Cargo". This feature is still in very early stages of development, and is also a possible massive feature addition to Cargo. This is a very large feature to document, even in the minimal form that it exists in today, so if you're curious to stay up to date you'll want to follow the [tracking repository](https://github.com/rust-lang/wg-cargo-std-aware) and its set of issues. The functionality implemented today is behind a flag called `-Z build-std`. This flag indicates that Cargo should compile the standard library from source code using the same profile as the main build itself. Note that for this to work you need to have the source code for the standard library available, and at this time the only supported method of doing so is to add the `rust-src` rust rustup component: ```console $ rustup component add rust-src --toolchain nightly ``` Usage looks like: ```console $ cargo new foo $ cd foo $ cargo +nightly run -Z build-std --target x86_64-unknown-linux-gnu Compiling core v0.0.0 (...) ... Compiling foo v0.1.0 (...) Finished dev [unoptimized + debuginfo] target(s) in 21.00s Running `target/x86_64-unknown-linux-gnu/debug/foo` Hello, world! ``` Here we recompiled the standard library in debug mode with debug assertions (like `src/main.rs` is compiled) and everything was linked together at the end. Using `-Z build-std` will implicitly compile the stable crates `core`, `std`, `alloc`, and `proc_macro`. If you're using `cargo test` it will also compile the `test` crate. If you're working with an environment which does not support some of these crates, then you can pass an argument to `-Zbuild-std` as well: ```console $ cargo +nightly build -Z build-std=core,alloc ``` The value here is a comma-separated list of standard library crates to build. ### Requirements As a summary, a list of requirements today to use `-Z build-std` are: * You must install libstd's source code through `rustup component add rust-src` * You must use both a nightly Cargo and a nightly rustc * The `-Z build-std` flag must be passed to all `cargo` invocations. ### Reporting bugs and helping out The `-Z build-std` feature is in the very early stages of development! This feature for Cargo has an extremely long history and is very large in scope, and this is just the beginning. If you'd like to report bugs please either report them to: * Cargo --- --- for implementation bugs * The tracking repository --- --- for larger design questions. Also if you'd like to see a feature that's not yet implemented and/or if something doesn't quite work the way you'd like it to, feel free to check out the [issue tracker](https://github.com/rust-lang/wg-cargo-std-aware/issues) of the tracking repository, and if it's not there please file a new issue! ## build-std-features * Tracking Repository: This flag is a sibling to the `-Zbuild-std` feature flag. This will configure the features enabled for the standard library itself when building the standard library. The default enabled features, at this time, are `backtrace` and `panic-unwind`. This flag expects a comma-separated list and, if provided, will override the default list of features enabled. ## binary-dep-depinfo * Tracking rustc issue: [#63012](https://github.com/rust-lang/rust/issues/63012) The `-Z binary-dep-depinfo` flag causes Cargo to forward the same flag to `rustc` which will then cause `rustc` to include the paths of all binary dependencies in the "dep info" file (with the `.d` extension). Cargo then uses that information for change-detection (if any binary dependency changes, then the crate will be rebuilt). The primary use case is for building the compiler itself, which has implicit dependencies on the standard library that would otherwise be untracked for change-detection. ## checksum-freshness * Tracking issue: [#14136](https://github.com/rust-lang/cargo/issues/14136) The `-Z checksum-freshness` flag will replace the use of file mtimes in cargo's fingerprints with a file checksum value. This is most useful on systems with a poor mtime implementation, or in CI/CD. The checksum algorithm can change without notice between cargo versions. Fingerprints are used by cargo to determine when a crate needs to be rebuilt. For the time being files ingested by build script will continue to use mtimes, even when `checksum-freshness` is enabled. This is not intended as a long term solution. ## panic-abort-tests * Tracking Issue: [#67650](https://github.com/rust-lang/rust/issues/67650) * Original Pull Request: [#7460](https://github.com/rust-lang/cargo/pull/7460) The `-Z panic-abort-tests` flag will enable nightly support to compile test harness crates with `-Cpanic=abort`. Without this flag Cargo will compile tests, and everything they depend on, with `-Cpanic=unwind` because it's the only way `test`-the-crate knows how to operate. As of [rust-lang/rust#64158], however, the `test` crate supports `-C panic=abort` with a test-per-process, and can help avoid compiling crate graphs multiple times. It's currently unclear how this feature will be stabilized in Cargo, but we'd like to stabilize it somehow! [rust-lang/rust#64158]: https://github.com/rust-lang/rust/pull/64158 ## 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 an array of config file paths. Only path ending with `.toml` is accepted. ```toml # a path ending with `.toml` include = "path/to/mordor.toml" # or an array of paths include = ["frodo.toml", "samwise.toml"] ``` 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) * Tracking Issue: [#9453](https://github.com/rust-lang/cargo/issues/9453) Historically, Cargo's behavior for whether the `linker` and `rustflags` configuration options from environment variables and [`[target]`](config.md#target) are respected for build scripts, plugins, and other artifacts that are _always_ built for the host platform has been somewhat inconsistent. When `--target` is _not_ passed, Cargo respects the same `linker` and `rustflags` for build scripts as for all other compile artifacts. When `--target` _is_ passed, however, Cargo respects `linker` from [`[target.]`](config.md#targettriplelinker), and does not pick up any `rustflags` configuration. This dual behavior is confusing, but also makes it difficult to correctly configure builds where the host triple and the [target triple] happen to be the same, but artifacts intended to run on the build host should still be configured differently. `-Ztarget-applies-to-host` enables the top-level `target-applies-to-host` setting in Cargo configuration files which allows users to opt into different (and more consistent) behavior for these properties. When `target-applies-to-host` is unset, or set to `true`, in the configuration file, the existing Cargo behavior is preserved (though see `-Zhost-config`, which changes that default). When it is set to `false`, no options from `[target.]`, `RUSTFLAGS`, or `[build]` are respected for host artifacts regardless of whether `--target` is passed to Cargo. To customize artifacts intended to be run on the host, use `[host]` ([`host-config`](#host-config)). In the future, `target-applies-to-host` may end up defaulting to `false` to provide more sane and consistent default behavior. ```toml # config.toml target-applies-to-host = false ``` ```console cargo +nightly -Ztarget-applies-to-host build --target x86_64-unknown-linux-gnu ``` ## host-config * Original Pull Request: [#9322](https://github.com/rust-lang/cargo/pull/9322) * Tracking Issue: [#9452](https://github.com/rust-lang/cargo/issues/9452) The `host` key in a config file can be used to pass flags to host build targets such as build scripts that must run on the host system instead of the target system when cross compiling. It supports both generic and host arch specific tables. Matching host arch tables take precedence over generic host tables. It requires the `-Zhost-config` and `-Ztarget-applies-to-host` command-line options to be set, and that `target-applies-to-host = false` is set in the Cargo configuration file. ```toml # config.toml [host] linker = "/path/to/host/linker" [host.x86_64-unknown-linux-gnu] linker = "/path/to/host/arch/linker" rustflags = ["-Clink-arg=--verbose"] [target.x86_64-unknown-linux-gnu] linker = "/path/to/target/linker" ``` The generic `host` table above will be entirely ignored when building on an `x86_64-unknown-linux-gnu` host as the `host.x86_64-unknown-linux-gnu` table takes precedence. Setting `-Zhost-config` changes the default for `target-applies-to-host` to `false` from `true`. ```console cargo +nightly -Ztarget-applies-to-host -Zhost-config build --target x86_64-unknown-linux-gnu ``` ## unit-graph * Tracking Issue: [#8002](https://github.com/rust-lang/cargo/issues/8002) The `--unit-graph` flag can be passed to any build command (`build`, `check`, `run`, `test`, `bench`, `doc`, etc.) to emit a JSON object to stdout which represents Cargo's internal unit graph. Nothing is actually built, and the command returns immediately after printing. Each "unit" corresponds to an execution of the compiler. These objects also include which unit each unit depends on. ``` cargo +nightly build --unit-graph -Z unstable-options ``` This structure provides a more complete view of the dependency relationship as Cargo sees it. In particular, the "features" field supports the new feature resolver where a dependency can be built multiple times with different features. `cargo metadata` fundamentally cannot represent the relationship of features between different dependency kinds, and features now depend on which command is run and which packages and targets are selected. Additionally it can provide details about intra-package dependencies like build scripts or tests. The following is a description of the JSON structure: ```javascript { /* Version of the JSON output structure. If any backwards incompatible changes are made, this value will be increased. */ "version": 1, /* Array of all build units. */ "units": [ { /* An opaque string which indicates the package. Information about the package can be obtained from `cargo metadata`. */ "pkg_id": "my-package 0.1.0 (path+file:///path/to/my-package)", /* The Cargo target. See the `cargo metadata` documentation for more information about these fields. https://doc.rust-lang.org/cargo/commands/cargo-metadata.html */ "target": { "kind": ["lib"], "crate_types": ["lib"], "name": "my_package", "src_path": "/path/to/my-package/src/lib.rs", "edition": "2018", "test": true, "doctest": true }, /* The profile settings for this unit. These values may not match the profile defined in the manifest. Units can use modified profile settings. For example, the "panic" setting can be overridden for tests to force it to "unwind". */ "profile": { /* The profile name these settings are derived from. */ "name": "dev", /* The optimization level as a string. */ "opt_level": "0", /* The LTO setting as a string. */ "lto": "false", /* The codegen units as an integer. `null` if it should use the compiler's default. */ "codegen_units": null, /* The debug information level as an integer. `null` if it should use the compiler's default (0). */ "debuginfo": 2, /* Whether or not debug-assertions are enabled. */ "debug_assertions": true, /* Whether or not overflow-checks are enabled. */ "overflow_checks": true, /* Whether or not rpath is enabled. */ "rpath": false, /* Whether or not incremental is enabled. */ "incremental": true, /* The panic strategy, "unwind" or "abort". */ "panic": "unwind" }, /* Which platform this target is being built for. A value of `null` indicates it is for the host. Otherwise it is a string of the target triple (such as "x86_64-unknown-linux-gnu"). */ "platform": null, /* The "mode" for this unit. Valid values: * "test" --- Build using `rustc` as a test. * "build" --- Build using `rustc`. * "check" --- Build using `rustc` in "check" mode. * "doc" --- Build using `rustdoc`. * "doctest" --- Test using `rustdoc`. * "run-custom-build" --- Represents the execution of a build script. */ "mode": "build", /* Array of features enabled on this unit as strings. */ "features": ["somefeat"], /* Whether or not this is a standard-library unit, part of the unstable build-std feature. If not set, treat as `false`. */ "is_std": false, /* Array of dependencies of this unit. */ "dependencies": [ { /* Index in the "units" array for the dependency. */ "index": 1, /* The name that this dependency will be referred as. */ "extern_crate_name": "unicode_xid", /* Whether or not this dependency is "public", part of the unstable public-dependency feature. If not set, the public-dependency feature is not enabled. */ "public": false, /* Whether or not this dependency is injected into the prelude, currently used by the build-std feature. If not set, treat as `false`. */ "noprelude": false } ] }, // ... ], /* Array of indices in the "units" array that are the "roots" of the dependency graph. */ "roots": [0], } ``` ## Profile `rustflags` option * Original Issue: [rust-lang/cargo#7878](https://github.com/rust-lang/cargo/issues/7878) * Tracking Issue: [rust-lang/cargo#10271](https://github.com/rust-lang/cargo/issues/10271) This feature provides a new option in the `[profile]` section to specify flags that are passed directly to rustc. This can be enabled like so: ```toml cargo-features = ["profile-rustflags"] [package] # ... [profile.release] rustflags = [ "-C", "..." ] ``` To set this in a profile in Cargo configuration, you need to use either `-Z profile-rustflags` or `[unstable]` table to enable it. For example, ```toml # .cargo/config.toml [unstable] profile-rustflags = true [profile.release] rustflags = [ "-C", "..." ] ``` ## rustdoc-map * Tracking Issue: [#8296](https://github.com/rust-lang/cargo/issues/8296) This feature adds configuration settings that are passed to `rustdoc` so that it can generate links to dependencies whose documentation is hosted elsewhere when the dependency is not documented. First, add this to `.cargo/config`: ```toml [doc.extern-map.registries] crates-io = "https://docs.rs/" ``` Then, when building documentation, use the following flags to cause links to dependencies to link to [docs.rs](https://docs.rs/): ``` cargo +nightly doc --no-deps -Zrustdoc-map ``` The `registries` table contains a mapping of registry name to the URL to link to. The URL may have the markers `{pkg_name}` and `{version}` which will get replaced with the corresponding values. If neither are specified, then Cargo defaults to appending `{pkg_name}/{version}/` to the end of the URL. Another config setting is available to redirect standard library links. By default, rustdoc creates links to . To change this behavior, use the `doc.extern-map.std` setting: ```toml [doc.extern-map] std = "local" ``` A value of `"local"` means to link to the documentation found in the `rustc` sysroot. If you are using rustup, this documentation can be installed with `rustup component add rust-docs`. The default value is `"remote"`. The value may also take a URL for a custom location. ## per-package-target * Tracking Issue: [#9406](https://github.com/rust-lang/cargo/pull/9406) * Original Pull Request: [#9030](https://github.com/rust-lang/cargo/pull/9030) * Original Issue: [#7004](https://github.com/rust-lang/cargo/pull/7004) The `per-package-target` feature adds two keys to the manifest: `package.default-target` and `package.forced-target`. The first makes the package be compiled by default (ie. when no `--target` argument is passed) for some target. The second one makes the package always be compiled for the target. Example: ```toml [package] forced-target = "wasm32-unknown-unknown" ``` In this example, the crate is always built for `wasm32-unknown-unknown`, for instance because it is going to be used as a plugin for a main program that runs on the host (or provided on the command line) target. ## artifact-dependencies * Tracking Issue: [#9096](https://github.com/rust-lang/cargo/pull/9096) * Original Pull Request: [#9992](https://github.com/rust-lang/cargo/pull/9992) Artifact dependencies allow Cargo packages to depend on `bin`, `cdylib`, and `staticlib` crates, and use the artifacts built by those crates at compile time. Run `cargo` with `-Z bindeps` to enable this functionality. ### artifact-dependencies: Dependency declarations Artifact-dependencies adds the following keys to a dependency declaration in `Cargo.toml`: - `artifact` --- This specifies the [Cargo Target](cargo-targets.md) to build. Normally without this field, Cargo will only build the `[lib]` target from a dependency. This field allows specifying which target will be built, and made available as a binary at build time: * `"bin"` --- Compiled executable binaries, corresponding to all of the `[[bin]]` sections in the dependency's manifest. * `"bin:"` --- Compiled executable binary, corresponding to a specific binary target specified by the given ``. * `"cdylib"` --- A C-compatible dynamic library, corresponding to a `[lib]` section with `crate-type = ["cdylib"]` in the dependency's manifest. * `"staticlib"` --- A C-compatible static library, corresponding to a `[lib]` section with `crate-type = ["staticlib"]` in the dependency's manifest. The `artifact` value can be a string, or it can be an array of strings to specify multiple targets. Example: ```toml [dependencies] bar = { version = "1.0", artifact = "staticlib" } zoo = { version = "1.0", artifact = ["bin:cat", "bin:dog"]} ``` - `lib` --- This is a Boolean value which indicates whether or not to also build the dependency's library as a normal Rust `lib` dependency. This field can only be specified when `artifact` is specified. The default for this field is `false` when `artifact` is specified. If this is set to `true`, then the dependency's `[lib]` target will also be built for the platform target the declaring package is being built for. This allows the package to use the dependency from Rust code like a normal dependency in addition to an artifact dependency. Example: ```toml [dependencies] bar = { version = "1.0", artifact = "bin", lib = true } ``` - `target` --- The platform target to build the dependency for. This field can only be specified when `artifact` is specified. The default if this is not specified depends on the dependency kind. For build dependencies, it will be built for the host target. For all other dependencies, it will be built for the same targets the declaring package is built for. For a build dependency, this can also take the special value of `"target"` which means to build the dependency for the same targets that the package is being built for. ```toml [build-dependencies] bar = { version = "1.0", artifact = "cdylib", target = "wasm32-unknown-unknown"} same-target = { version = "1.0", artifact = "bin", target = "target" } ``` ### artifact-dependencies: Environment variables After building an artifact dependency, Cargo provides the following environment variables that you can use to access the artifact: - `CARGO__DIR_` --- This is the directory containing all the artifacts from the dependency. `` is the `artifact` specified for the dependency (uppercased as in `CDYLIB`, `STATICLIB`, or `BIN`) and `` is the name of the dependency. As with other Cargo environment variables, dependency names are converted to uppercase, with dashes replaced by underscores. If your manifest renames the dependency, `` corresponds to the name you specify, not the original package name. - `CARGO__FILE__` --- This is the full path to the artifact. `` is the `artifact` specified for the dependency (uppercased as above), `` is the name of the dependency (transformed as above), and `` is the name of the artifact from the dependency. Note that `` is not modified in any way from the `name` specified in the crate supplying the artifact, or the crate name if not specified; for instance, it may be in lowercase, or contain dashes. For convenience, if the artifact name matches the original package name, cargo additionally supplies a copy of this variable with the `_` suffix omitted. For instance, if the `cmake` crate supplies a binary named `cmake`, Cargo supplies both `CARGO_BIN_FILE_CMAKE` and `CARGO_BIN_FILE_CMAKE_cmake`. For each kind of dependency, these variables are supplied to the same part of the build process that has access to that kind of dependency: - For build-dependencies, these variables are supplied to the `build.rs` script, and can be accessed using [`std::env::var_os`](https://doc.rust-lang.org/std/env/fn.var_os.html). (As with any OS file path, these may or may not be valid UTF-8.) - For normal dependencies, these variables are supplied during the compilation of the crate, and can be accessed using the [`env!`] macro. - For dev-dependencies, these variables are supplied during the compilation of examples, tests, and benchmarks, and can be accessed using the [`env!`] macro. [`env!`]: https://doc.rust-lang.org/std/macro.env.html ### artifact-dependencies: Examples #### Example: use a binary executable from a build script In the `Cargo.toml` file, you can specify a dependency on a binary to make available for a build script: ```toml [build-dependencies] some-build-tool = { version = "1.0", artifact = "bin" } ``` Then inside the build script, the binary can be executed at build time: ```rust fn main() { let build_tool = std::env::var_os("CARGO_BIN_FILE_SOME_BUILD_TOOL").unwrap(); let status = std::process::Command::new(build_tool) .arg("do-stuff") .status() .unwrap(); if !status.success() { eprintln!("failed!"); std::process::exit(1); } } ``` #### Example: use _cdylib_ artifact in build script The `Cargo.toml` in the consuming package, building the `bar` library as `cdylib` for a specific build target… ```toml [build-dependencies] bar = { artifact = "cdylib", version = "1.0", target = "wasm32-unknown-unknown" } ``` …along with the build script in `build.rs`. ```rust fn main() { wasm::run_file(std::env::var("CARGO_CDYLIB_FILE_BAR").unwrap()); } ``` #### Example: use _binary_ artifact and its library in a binary The `Cargo.toml` in the consuming package, building the `bar` binary for inclusion as artifact while making it available as library as well… ```toml [dependencies] bar = { artifact = "bin", version = "1.0", lib = true } ``` …along with the executable using `main.rs`. ```rust fn main() { bar::init(); command::run(env!("CARGO_BIN_FILE_BAR")); } ``` ## publish-timeout * Tracking Issue: [11222](https://github.com/rust-lang/cargo/issues/11222) The `publish.timeout` key in a config file can be used to control how long `cargo publish` waits between posting a package to the registry and it being available in the local index. A timeout of `0` prevents any checks from occurring. The current default is `60` seconds. It requires the `-Zpublish-timeout` command-line options to be set. ```toml # config.toml [publish] timeout = 300 # in seconds ``` ## asymmetric-token * Tracking Issue: [10519](https://github.com/rust-lang/cargo/issues/10519) * RFC: [#3231](https://github.com/rust-lang/rfcs/pull/3231) The `-Z asymmetric-token` flag enables the `cargo:paseto` credential provider which allows Cargo to authenticate to registries without sending secrets over the network. In [`config.toml`](config.md) and `credentials.toml` files there is a field called `private-key`, which is a private key formatted in the secret [subset of `PASERK`](https://github.com/paseto-standard/paserk/blob/master/types/secret.md) and is used to sign asymmetric tokens A keypair can be generated with `cargo login --generate-keypair` which will: - generate a public/private keypair in the currently recommended fashion. - save the private key in `credentials.toml`. - print the public key in [PASERK public](https://github.com/paseto-standard/paserk/blob/master/types/public.md) format. It is recommended that the `private-key` be saved in `credentials.toml`. It is also supported in `config.toml`, primarily so that it can be set using the associated environment variable, which is the recommended way to provide it in CI contexts. This setup is what we have for the `token` field for setting a secret token. There is also an optional field called `private-key-subject` which is a string chosen by the registry. This string will be included as part of an asymmetric token and should not be secret. It is intended for the rare use cases like "cryptographic proof that the central CA server authorized this action". Cargo requires it to be non-whitespace printable ASCII. Registries that need non-ASCII data should base64 encode it. Both fields can be set with `cargo login --registry=name --private-key --private-key-subject="subject"` which will prompt you to put in the key value. A registry can have at most one of `private-key` or `token` set. All PASETOs will include `iat`, the current time in ISO 8601 format. Cargo will include the following where appropriate: - `sub` an optional, non-secret string chosen by the registry that is expected to be claimed with every request. The value will be the `private-key-subject` from the `config.toml` file. - `mutation` if present, indicates that this request is a mutating operation (or a read-only operation if not present), must be one of the strings `publish`, `yank`, or `unyank`. - `name` name of the crate related to this request. - `vers` version string of the crate related to this request. - `cksum` the SHA256 hash of the crate contents, as a string of 64 lowercase hexadecimal digits, must be present only when `mutation` is equal to `publish` - `challenge` the challenge string received from a 401/403 from this server this session. Registries that issue challenges must track which challenges have been issued/used and never accept a given challenge more than once within the same validity period (avoiding the need to track every challenge ever issued). The "footer" (which is part of the signature) will be a JSON string in UTF-8 and include: - `url` the RFC 3986 compliant URL where cargo got the config.json file, - If this is a registry with an HTTP index, then this is the base URL that all index queries are relative to. - If this is a registry with a GIT index, it is the URL Cargo used to clone the index. - `kid` the identifier of the private key used to sign the request, using the [PASERK IDs](https://github.com/paseto-standard/paserk/blob/master/operations/ID.md) standard. PASETO includes the message that was signed, so the server does not have to reconstruct the exact string from the request in order to check the signature. The server does need to check that the signature is valid for the string in the PASETO and that the contents of that string matches the request. If a claim should be expected for the request but is missing in the PASETO then the request must be rejected. ## `cargo config` * Original Issue: [#2362](https://github.com/rust-lang/cargo/issues/2362) * Tracking Issue: [#9301](https://github.com/rust-lang/cargo/issues/9301) The `cargo config` subcommand provides a way to display the configuration files that cargo loads. It currently includes the `get` subcommand which can take an optional config value to display. ```console 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. ## rustc `--print` * Tracking Issue: [#9357](https://github.com/rust-lang/cargo/issues/9357) `cargo rustc --print=VAL` forwards the `--print` flag to `rustc` in order to extract information from `rustc`. This runs `rustc` with the corresponding [`--print`](https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information) flag, and then immediately exits without compiling. Exposing this as a cargo flag allows cargo to inject the correct target and RUSTFLAGS based on the current configuration. The primary use case is to run `cargo rustc --print=cfg` to get config values for the appropriate target and influenced by any other RUSTFLAGS. ## Different binary name * Tracking Issue: [#9778](https://github.com/rust-lang/cargo/issues/9778) * PR: [#9627](https://github.com/rust-lang/cargo/pull/9627) The `different-binary-name` feature allows setting the filename of the binary without having to obey the restrictions placed on crate names. For example, the crate name must use only `alphanumeric` characters or `-` or `_`, and cannot be empty. The `filename` parameter should **not** include the binary extension, `cargo` will figure out the appropriate extension and use that for the binary on its own. The `filename` parameter is only available in the `[[bin]]` section of the manifest. ```toml cargo-features = ["different-binary-name"] [package] name = "foo" version = "0.0.1" [[bin]] name = "foo" filename = "007bar" path = "src/main.rs" ``` ## scrape-examples * RFC: [#3123](https://github.com/rust-lang/rfcs/pull/3123) * Tracking Issue: [#9910](https://github.com/rust-lang/cargo/issues/9910) The `-Z rustdoc-scrape-examples` flag tells Rustdoc to search crates in the current workspace for calls to functions. Those call-sites are then included as documentation. You can use the flag like this: ``` cargo doc -Z unstable-options -Z rustdoc-scrape-examples ``` By default, Cargo will scrape examples from the example targets of packages being documented. You can individually enable or disable targets from being scraped with the `doc-scrape-examples` flag, such as: ```toml # Enable scraping examples from a library [lib] doc-scrape-examples = true # Disable scraping examples from an example target [[example]] name = "my-example" doc-scrape-examples = false ``` **Note on tests:** enabling `doc-scrape-examples` on test targets will not currently have any effect. Scraping examples from tests is a work-in-progress. **Note on dev-dependencies:** documenting a library does not normally require the crate's dev-dependencies. However, example targets require dev-deps. For backwards compatibility, `-Z rustdoc-scrape-examples` will *not* introduce a dev-deps requirement for `cargo doc`. Therefore examples will *not* be scraped from example targets under the following conditions: 1. No target being documented requires dev-deps, AND 2. At least one crate with targets being documented has dev-deps, AND 3. The `doc-scrape-examples` parameter is unset or false for all `[[example]]` targets. If you want examples to be scraped from example targets, then you must not satisfy one of the above conditions. For example, you can set `doc-scrape-examples` to true for one example target, and that signals to Cargo that you are ok with dev-deps being build for `cargo doc`. ## output-format for rustdoc * Tracking Issue: [#13283](https://github.com/rust-lang/cargo/issues/13283) This flag determines the output format of `cargo rustdoc`, accepting `html` or `json`, providing tools with a way to lean on [rustdoc's experimental JSON format](https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc_json_types/). You can use the flag like this: ``` cargo rustdoc -Z unstable-options --output-format json ``` ## codegen-backend The `codegen-backend` feature makes it possible to select the codegen backend used by rustc using a profile. Example: ```toml [package] name = "foo" [dependencies] serde = "1.0.117" [profile.dev.package.foo] codegen-backend = "cranelift" ``` To set this in a profile in Cargo configuration, you need to use either `-Z codegen-backend` or `[unstable]` table to enable it. For example, ```toml # .cargo/config.toml [unstable] codegen-backend = true [profile.dev.package.foo] codegen-backend = "cranelift" ``` ## gitoxide * Tracking Issue: [#11813](https://github.com/rust-lang/cargo/issues/11813) With the 'gitoxide' unstable feature, all or the specified git operations will be performed by the `gitoxide` crate instead of `git2`. While `-Zgitoxide` enables all currently implemented features, one can individually select git operations to run with `gitoxide` with the `-Zgitoxide=operation[,operationN]` syntax. Valid operations are the following: * `fetch` - All fetches are done with `gitoxide`, which includes git dependencies as well as the crates index. * `checkout` *(planned)* - checkout the worktree, with support for filters and submodules. ## git * Tracking Issue: [#13285](https://github.com/rust-lang/cargo/issues/13285) With the 'git' unstable feature, both `gitoxide` and `git2` will perform shallow fetches of the crate index and git dependencies. While `-Zgit` enables all currently implemented features, one can individually select when to perform shallow fetches with the `-Zgit=operation[,operationN]` syntax. Valid operations are the following: * `shallow-index` - perform a shallow clone of the index. * `shallow-deps` - perform a shallow clone of git dependencies. **Details on shallow clones** * To enable shallow clones, add `-Zgit=shallow-deps` for fetching git dependencies or `-Zgit=shallow-index` for fetching registry index. * Shallow-cloned and shallow-checked-out git repositories reside at their own `-shallow` suffixed directories, i.e, - `~/.cargo/registry/index/*-shallow` - `~/.cargo/git/db/*-shallow` - `~/.cargo/git/checkouts/*-shallow` * When the unstable feature is on, fetching/cloning a git repository is always a shallow fetch. This roughly equals to `git fetch --depth 1` everywhere. * Even with the presence of `Cargo.lock` or specifying a commit `{ rev = "…" }`, gitoxide and libgit2 are 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, } 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 rust "frontmatter", a markdown code-fence with `cargo` at the start of the infostring at the top of the file. Inferred / defaulted manifest fields: - `package.name = ` - `package.edition = ` 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.autolib`, `package.autobins`, `package.autoexamples`, `package.autotests`, `package.autobenches` The default `CARGO_TARGET_DIR` for single-file packages is at `$CARGO_HOME/target/`: - 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 ` 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 ` and `cargo ` - `cargo ` runs with the config for `` and not the current dir, more like `cargo install --path ` - `cargo ` is at a verbosity level below the normal default. Pass `-v` to get normal output. ### Documentation Updates ## Profile `trim-paths` option * Tracking Issue: [rust-lang/cargo#12137](https://github.com/rust-lang/cargo/issues/12137) * Tracking Rustc Issue: [rust-lang/rust#111540](https://github.com/rust-lang/rust/issues/111540) This adds a new profile setting to control how paths are sanitized in the resulting binary. This can be enabled like so: ```toml cargo-features = ["trim-paths"] [package] # ... [profile.release] trim-paths = ["diagnostics", "object"] ``` To set this in a profile in Cargo configuration, you need to use either `-Z trim-paths` or `[unstable]` table to enable it. For example, ```toml # .cargo/config.toml [unstable] trim-paths = true [profile.release] trim-paths = ["diagnostics", "object"] ``` ### Documentation updates #### trim-paths *as a new ["Profiles settings" entry](./profiles.html#profile-settings)* `trim-paths` is a profile setting which enables and controls the sanitization of file paths in build outputs. It takes the following values: - `"none"` and `false` --- disable path sanitization - `"macro"` --- sanitize paths in the expansion of `std::file!()` macro. This is where paths in embedded panic messages come from - `"diagnostics"` --- sanitize paths in printed compiler diagnostics - `"object"` --- sanitize paths in compiled executables or libraries - `"all"` and `true` --- sanitize paths in all possible locations It also takes an array with the combinations of `"macro"`, `"diagnostics"`, and `"object"`. It is defaulted to `none` for the `dev` profile, and `object` for the `release` profile. You can manually override it by specifying this option in `Cargo.toml`: ```toml [profile.dev] trim-paths = "all" [profile.release] trim-paths = ["object", "diagnostics"] ``` The default `release` profile setting (`object`) sanitizes only the paths in emitted executable or library files. It always affects paths from macros such as panic messages, and in debug information only if they will be embedded together with the binary (the default on platforms with ELF binaries, such as Linux and windows-gnu), but will not touch them if they are in separate files (the default on Windows MSVC and macOS). But the paths to these separate files are sanitized. If `trim-paths` is not `none` or `false`, then the following paths are sanitized if they appear in a selected scope: 1. Path to the source files of the standard and core library (sysroot) will begin with `/rustc/[rustc commit hash]`, e.g. `/home/username/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs` -> `/rustc/fe72845f7bb6a77b9e671e6a4f32fe714962cec4/library/core/src/result.rs` 2. Path to the current package will be stripped, relatively to the current workspace root, e.g. `/home/username/crate/src/lib.rs` -> `src/lib.rs`. 3. Path to dependency packages will be replaced with `[package name]-[version]`. E.g. `/home/username/deps/foo/src/lib.rs` -> `foo-0.1.0/src/lib.rs` When a path to the source files of the standard and core library is *not* in scope for sanitization, the emitted path will depend on if `rust-src` component is present. If it is, then some paths will point to the copy of the source files on your file system; if it isn't, then they will show up as `/rustc/[rustc commit hash]/library/...` (just like when it is selected for sanitization). Paths to all other source files will not be affected. This will not affect any hard-coded paths in the source code, such as in strings. #### Environment variable *as a new entry of ["Environment variables Cargo sets for build scripts"](./environment-variables.md#environment-variables-cargo-sets-for-crates)* * `CARGO_TRIM_PATHS` --- The value of `trim-paths` profile option. `false`, `"none"`, and empty arrays would be converted to `none`. `true` and `"all"` become `all`. Values in a non-empty array would be joined into a comma-separated list. If the build script introduces absolute paths to built artifacts (such as by invoking a compiler), the user may request them to be sanitized in different types of artifacts. Common paths requiring sanitization include `OUT_DIR`, `CARGO_MANIFEST_DIR` and `CARGO_MANIFEST_PATH`, plus any other introduced by the build script, such as include directories. ## gc * Tracking Issue: [#12633](https://github.com/rust-lang/cargo/issues/12633) The `-Zgc` flag enables garbage-collection within cargo's global cache within the cargo home directory. This includes downloaded dependencies such as compressed `.crate` files, extracted `src` directories, registry index caches, and git dependencies. When `-Zgc` is present, cargo will track the last time any index and dependency was used, and then uses those timestamps to manually or automatically delete cache entries that have not been used for a while. ```sh cargo build -Zgc ``` ### Automatic garbage collection Automatic deletion happens on commands that are already doing a significant amount of work, such as all of the build commands (`cargo build`, `cargo test`, `cargo check`, etc.), and `cargo fetch`. The deletion happens just after resolution and packages have been downloaded. Automatic deletion is only done once per day (see `gc.auto.frequency` to configure). Automatic deletion is disabled if cargo is offline such as with `--offline` or `--frozen` to avoid deleting artifacts that may need to be used if you are offline for a long period of time. #### Automatic gc configuration The automatic gc behavior can be specified via a cargo configuration setting. The settings available are: ```toml # Example config.toml file. # This table defines the behavior for automatic garbage collection. [gc.auto] # The maximum frequency that automatic garbage collection happens. # Can be "never" to disable automatic-gc, or "always" to run on every command. frequency = "1 day" # Anything older than this duration will be deleted in the source cache. max-src-age = "1 month" # Anything older than this duration will be deleted in the compressed crate cache. max-crate-age = "3 months" # Any index older than this duration will be deleted from the index cache. max-index-age = "3 months" # Any git checkout older than this duration will be deleted from the checkout cache. max-git-co-age = "1 month" # Any git clone older than this duration will be deleted from the git cache. max-git-db-age = "3 months" ``` ### Manual garbage collection with `cargo clean` Manual deletion can be done with the `cargo clean gc` command. Deletion of cache contents can be performed by passing one of the cache options: - `--max-src-age=DURATION` --- Deletes source cache files that have not been used since the given age. - `--max-crate-age=DURATION` --- Deletes crate cache files that have not been used since the given age. - `--max-index-age=DURATION` --- Deletes registry indexes that have not been used since then given age (including their `.crate` and `src` files). - `--max-git-co-age=DURATION` --- Deletes git dependency checkouts that have not been used since then given age. - `--max-git-db-age=DURATION` --- Deletes git dependency clones that have not been used since then given age. - `--max-download-age=DURATION` --- Deletes any downloaded cache data that has not been used since then given age. - `--max-src-size=SIZE` --- Deletes the oldest source cache files until the cache is under the given size. - `--max-crate-size=SIZE` --- Deletes the oldest crate cache files until the cache is under the given size. - `--max-git-size=SIZE` --- Deletes the oldest git dependency caches until the cache is under the given size. - `--max-download-size=SIZE` --- Deletes the oldest downloaded cache data until the cache is under the given size. A DURATION is specified in the form "N seconds/minutes/days/weeks/months" where N is an integer. A SIZE is specified in the form "N *suffix*" where *suffix* is B, kB, MB, GB, kiB, MiB, or GiB, and N is an integer or floating point number. If no suffix is specified, the number is the number of bytes. ```sh cargo clean gc cargo clean gc --max-download-age=1week cargo clean gc --max-git-size=0 --max-download-size=100MB ``` ## open-namespaces * Tracking Issue: [#13576](https://github.com/rust-lang/cargo/issues/13576) Allow multiple packages to participate in the same API namespace This can be enabled like so: ```toml cargo-features = ["open-namespaces"] [package] # ... ``` ## `[lints.cargo]` * Tracking Issue: [#12235](https://github.com/rust-lang/cargo/issues/12235) A new `lints` tool table for `cargo` that can be used to configure lints emitted by `cargo` itself when `-Zcargo-lints` is used ```toml [lints.cargo] implicit-features = "warn" ``` This will work with [RFC 2906 `workspace-deduplicate`](https://rust-lang.github.io/rfcs/2906-cargo-workspace-deduplicate.html): ```toml [workspace.lints.cargo] implicit-features = "warn" [lints] workspace = true ``` ## Path Bases * Tracking Issue: [#14355](https://github.com/rust-lang/cargo/issues/14355) A `path` dependency may optionally specify a base by setting the `base` key to the name of a path base from the `[path-bases]` table in either the [configuration](config.md) or one of the [built-in path bases](#built-in-path-bases). The value of that path base is prepended to the `path` value (along with a path separator if necessary) to produce the actual location where Cargo will look for the dependency. For example, if the `Cargo.toml` contains: ```toml cargo-features = ["path-bases"] [dependencies] foo = { base = "dev", path = "foo" } ``` Given a `[path-bases]` table in the configuration that contains: ```toml [path-bases] dev = "/home/user/dev/rust/libraries/" ``` This will produce a `path` dependency `foo` located at `/home/user/dev/rust/libraries/foo`. Path bases can be either absolute or relative. Relative path bases are relative to the parent directory of the configuration file that declared that path base. The name of a path base must use only [alphanumeric](https://doc.rust-lang.org/std/primitive.char.html#method.is_alphanumeric) characters or `-` or `_`, must start with an [alphabetic](https://doc.rust-lang.org/std/primitive.char.html#method.is_alphabetic) character, and must not be empty. If the name of path base used in a dependency is neither in the configuration nor one of the built-in path base, then Cargo will raise an error. #### Built-in path bases Cargo provides implicit path bases that can be used without the need to specify them in a `[path-bases]` table. * `workspace` - If a project is [a workspace or workspace member](workspaces.md) then this path base is defined as the parent directory of the root `Cargo.toml` of the workspace. If a built-in path base name is also declared in the configuration, then Cargo will prefer the value in the configuration. The allows Cargo to add new built-in path bases without compatibility issues (as existing uses will shadow the built-in name). ## lockfile-path * Original Issue: [#5707](https://github.com/rust-lang/cargo/issues/5707) * Tracking Issue: [#14421](https://github.com/rust-lang/cargo/issues/14421) This feature allows you to specify the path of lockfile Cargo.lock. By default, lockfile is written into `/Cargo.lock`. However, when sources are stored in read-only directory, most of the cargo commands would fail, trying to write a lockfile. The `--lockfile-path` flag makes it easier to work with readonly sources. Note, that currently path must end with `Cargo.lock`. Meaning, if you want to use this feature in multiple projects, lockfiles should be stored in different directories. Example: ```sh cargo +nightly metadata --lockfile-path=$LOCKFILES_ROOT/my-project/Cargo.lock -Z unstable-options ``` ## package-workspace * Tracking Issue: [#10948](https://github.com/rust-lang/cargo/issues/10948) This allows cargo to package (or publish) multiple crates in a workspace, even if they have inter-dependencies. For example, consider a workspace containing packages `foo` and `dep`, where `foo` depends on `dep`. Then ```sh cargo +nightly -Zpackage-workspace package -p foo -p dep ``` will package both `foo` and `dep`, while ```sh cargo +nightly -Zpackage-workspace publish -p foo -p dep ``` will publish both `foo` and `dep`. If `foo` and `dep` are the only crates in the workspace, you can use the `--workspace` flag instead of specifying the crates individually: ```sh cargo +nightly -Zpackage-workspace package --workspace cargo +nightly -Zpackage-workspace publish --workspace ``` #### Lock-file behavior When packaging a binary at the same time as one of its dependencies, the binary will be packaged with a lock-file pointing at the dependency's registry entry *as though the dependency were already published*, even though it has not yet been. In this case, `cargo` needs to know the registry that the dependency will eventually be published on. `cargo` will attempt to infer this registry by examining the [the `publish` field](manifest.md#the-publish-field), falling back to `crates.io` if no `publish` field is set. To explicitly set the registry, pass a `--registry` or `--index` flag. ```sh cargo +nightly -Zpackage-workspace --registry=my-registry package -p foo -p dep cargo +nightly -Zpackage-workspace --index=https://example.com package -p foo -p dep ``` ## native-completions * Original Issue: [#6645](https://github.com/rust-lang/cargo/issues/6645) * Tracking Issue: [#14520](https://github.com/rust-lang/cargo/issues/14520) This feature moves the handwritten completion scripts to Rust native, making it easier for us to add, extend and test new completions. This feature is enabled with the nightly channel, without requiring additional `-Z` options. Areas of particular interest for feedback - Arguments that need escaping or quoting that aren't handled correctly - Inaccuracies in the information - Bugs in parsing of the command-line - Arguments that don't report their completions - If a known issue is being problematic Feedback can be broken down into - What completion candidates are reported - Known issues: [#14520](https://github.com/rust-lang/cargo/issues/14520), [`A-completions`](https://github.com/rust-lang/cargo/labels/A-completions) - [Report an issue](https://github.com/rust-lang/cargo/issues/new) or [discuss the behavior](https://github.com/rust-lang/cargo/issues/14520) - Shell integration, command-line parsing, and completion filtering - Known issues: [clap#3166](https://github.com/clap-rs/clap/issues/3166), [clap's `A-completions`](https://github.com/clap-rs/clap/labels/A-completion) - [Report an issue](https://github.com/clap-rs/clap/issues/new/choose) or [discuss the behavior](https://github.com/clap-rs/clap/discussions/new/choose) When in doubt, you can discuss this in [#14520](https://github.com/rust-lang/cargo/issues/14520) or on [zulip](https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo) ### How to use native-completions feature: - bash: Add `source <(CARGO_COMPLETE=bash cargo +nightly)` to your .bashrc. - zsh: Add `source <(CARGO_COMPLETE=zsh cargo +nightly)` to your .zshrc. - fish: Add `source (CARGO_COMPLETE=fish cargo +nightly | psub)` to `$XDG_CONFIG_HOME/fish/completions/cargo.fish` - elvish: Add `eval (E:CARGO_COMPLETE=elvish cargo +nightly | slurp)` to `$XDG_CONFIG_HOME/elvish/rc.elv` - powershell: Add `CARGO_COMPLETE=powershell cargo +nightly | Invoke-Expression` to `$PROFILE`. ## warnings * Original Issue: [#8424](https://github.com/rust-lang/cargo/issues/8424) * Tracking Issue: [#14802](https://github.com/rust-lang/cargo/issues/14802) The `-Z warnings` feature enables the `build.warnings` configuration option to control how Cargo handles warnings. If the `-Z warnings` unstable flag is not enabled, then the `build.warnings` config will be ignored. This setting currently only applies to rustc warnings. It may apply to additional warnings (such as Cargo lints or Cargo warnings) in the future. ### `build.warnings` * Type: string * Default: `warn` * Environment: `CARGO_BUILD_WARNINGS` Controls how Cargo handles warnings. Allowed values are: * `warn`: warnings are emitted as warnings (default). * `allow`: warnings are hidden. * `deny`: if warnings are emitted, an error will be raised at the end of the operation and the process will exit with a failure exit code. # Stabilized and removed features ## Compile progress The compile-progress feature has been stabilized in the 1.30 release. Progress bars are now enabled by default. See [`term.progress`](config.md#termprogresswhen) for more information about controlling this feature. ## Edition Specifying the `edition` in `Cargo.toml` has been stabilized in the 1.31 release. See [the edition field](manifest.md#the-edition-field) for more information about specifying this field. ## rename-dependency Specifying renamed dependencies in `Cargo.toml` has been stabilized in the 1.31 release. See [renaming dependencies](specifying-dependencies.md#renaming-dependencies-in-cargotoml) for more information about renaming dependencies. ## Alternate Registries Support for alternate registries has been stabilized in the 1.34 release. See the [Registries chapter](registries.md) for more information about alternate registries. ## Offline Mode The offline feature has been stabilized in the 1.36 release. See the [`--offline` flag](../commands/cargo.md#option-cargo---offline) for more information on using the offline mode. ## publish-lockfile The `publish-lockfile` feature has been removed in the 1.37 release. The `Cargo.lock` file is always included when a package is published if the package contains a binary target. `cargo install` requires the `--locked` flag to use the `Cargo.lock` file. See [`cargo package`](../commands/cargo-package.md) and [`cargo install`](../commands/cargo-install.md) for more information. ## default-run The `default-run` feature has been stabilized in the 1.37 release. See [the `default-run` field](manifest.md#the-default-run-field) for more information about specifying the default target to run. ## cache-messages Compiler message caching has been stabilized in the 1.40 release. Compiler warnings are now cached by default and will be replayed automatically when re-running Cargo. ## install-upgrade The `install-upgrade` feature has been stabilized in the 1.41 release. [`cargo install`] will now automatically upgrade packages if they appear to be out-of-date. See the [`cargo install`] documentation for more information. [`cargo install`]: ../commands/cargo-install.md ## Profile Overrides Profile overrides have been stabilized in the 1.41 release. See [Profile Overrides](profiles.md#overrides) for more information on using overrides. ## Config Profiles Specifying profiles in Cargo config files and environment variables has been stabilized in the 1.43 release. See the [config `[profile]` table](config.md#profile) for more information about specifying [profiles](profiles.md) in config files. ## crate-versions The `-Z crate-versions` flag has been stabilized in the 1.47 release. The crate version is now automatically included in the [`cargo doc`](../commands/cargo-doc.md) documentation sidebar. ## Features The `-Z features` flag has been stabilized in the 1.51 release. See [feature resolver version 2](features.md#feature-resolver-version-2) for more information on using the new feature resolver. ## package-features The `-Z package-features` flag has been stabilized in the 1.51 release. See the [resolver version 2 command-line flags](features.md#resolver-version-2-command-line-flags) for more information on using the features CLI options. ## Resolver The `resolver` feature in `Cargo.toml` has been stabilized in the 1.51 release. See the [resolver versions](resolver.md#resolver-versions) for more information about specifying resolvers. ## extra-link-arg The `extra-link-arg` feature to specify additional linker arguments in build scripts has been stabilized in the 1.56 release. See the [build script documentation](build-scripts.md#outputs-of-the-build-script) for more information on specifying extra linker arguments. ## configurable-env The `configurable-env` feature to specify environment variables in Cargo configuration has been stabilized in the 1.56 release. See the [config documentation](config.html#env) for more information about configuring environment variables. ## rust-version The `rust-version` field in `Cargo.toml` has been stabilized in the 1.56 release. See the [rust-version field](manifest.html#the-rust-version-field) for more information on using the `rust-version` field and the `--ignore-rust-version` option. ## patch-in-config The `-Z patch-in-config` flag, and the corresponding support for `[patch]` section in Cargo configuration files has been stabilized in the 1.56 release. See the [patch field](config.html#patch) for more information. ## edition 2021 The 2021 edition has been stabilized in the 1.56 release. See the [`edition` field](manifest.md#the-edition-field) for more information on setting the edition. See [`cargo fix --edition`](../commands/cargo-fix.md) and [The Edition Guide](../../edition-guide/index.html) for more information on migrating existing projects. ## Custom named profiles Custom named profiles have been stabilized in the 1.57 release. See the [profiles chapter](profiles.md#custom-profiles) for more information. ## Profile `strip` option The profile `strip` option has been stabilized in the 1.59 release. See the [profiles chapter](profiles.md#strip) for more information. ## Future incompat report Support for generating a future-incompat report has been stabilized in the 1.59 release. See the [future incompat report chapter](future-incompat-report.md) for more information. ## Namespaced features Namespaced features has been stabilized in the 1.60 release. See the [Features chapter](features.md#optional-dependencies) for more information. ## Weak dependency features Weak dependency features has been stabilized in the 1.60 release. See the [Features chapter](features.md#dependency-features) for more information. ## timings The `-Ztimings` option has been stabilized as `--timings` in the 1.60 release. (`--timings=html` and the machine-readable `--timings=json` output remain unstable and require `-Zunstable-options`.) ## config-cli The `--config` CLI option has been stabilized in the 1.63 release. See the [config documentation](config.html#command-line-overrides) for more information. ## multitarget The `-Z multitarget` option has been stabilized in the 1.64 release. See [`build.target`](config.md#buildtarget) for more information about setting the default [target platform triples][target triple]. ## crate-type The `--crate-type` flag for `cargo rustc` has been stabilized in the 1.64 release. See the [`cargo rustc` documentation](../commands/cargo-rustc.md) for more information. ## Workspace Inheritance Workspace Inheritance has been stabilized in the 1.64 release. See [workspace.package](workspaces.md#the-package-table), [workspace.dependencies](workspaces.md#the-dependencies-table), and [inheriting-a-dependency-from-a-workspace](specifying-dependencies.md#inheriting-a-dependency-from-a-workspace) for more information. ## terminal-width The `-Z terminal-width` option has been stabilized in the 1.68 release. The terminal width is always passed to the compiler when running from a terminal where Cargo can automatically detect the width. ## sparse-registry Sparse registry support has been stabilized in the 1.68 release. See [Registry Protocols](registries.md#registry-protocols) for more information. ### `cargo logout` The [`cargo logout`] command has been stabilized in the 1.70 release. [target triple]: ../appendix/glossary.md#target '"target" (glossary)' [`cargo logout`]: ../commands/cargo-logout.md ## `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. ## keep-going The `--keep-going` option has been stabilized in the 1.74 release. See the [`--keep-going` flag](../commands/cargo-build.html#option-cargo-build---keep-going) in `cargo build` as an example for more details. ## `[lints]` [`[lints]`](manifest.html#the-lints-section) (enabled via `-Zlints`) has been stabilized in the 1.74 release. ## credential-process The `-Z credential-process` feature has been stabilized in the 1.74 release. See [Registry Authentication](registry-authentication.md) documentation for details. ## registry-auth The `-Z registry-auth` feature has been stabilized in the 1.74 release with the additional requirement that a credential-provider is configured. See [Registry Authentication](registry-authentication.md) documentation for details. ## check-cfg The `-Z check-cfg` feature has been stabilized in the 1.80 release by making it the default behavior. See the [build script documentation](build-scripts.md#rustc-check-cfg) for information about specifying custom cfgs. ## Edition 2024 The 2024 edition has been stabilized in the 1.85 release. See the [`edition` field](manifest.md#the-edition-field) for more information on setting the edition. See [`cargo fix --edition`](../commands/cargo-fix.md) and [The Edition Guide](../../edition-guide/index.html) for more information on migrating existing projects. cargo-0.86.0/src/doc/src/reference/workspaces.md000064400000000000000000000250121046102023000175760ustar 00000000000000# Workspaces A *workspace* is a collection of one or more packages, called *workspace members*, that are managed together. The key points of workspaces are: * Common commands can run across all workspace members, like `cargo check --workspace`. * All packages share a common [`Cargo.lock`] file which resides in the *workspace root*. * All packages share a common [output directory], which defaults to a directory named `target` in the *workspace root*. * Sharing package metadata, like with [`workspace.package`](#the-package-table). * The [`[patch]`][patch], [`[replace]`][replace] and [`[profile.*]`][profiles] sections in `Cargo.toml` are only recognized in the *root* manifest, and ignored in member crates' manifests. The root `Cargo.toml` of a workspace supports the following sections: * [`[workspace]`](#the-workspace-section) --- Defines a workspace. * [`resolver`](resolver.md#resolver-versions) --- Sets the dependency resolver to use. * [`members`](#the-members-and-exclude-fields) --- Packages to include in the workspace. * [`exclude`](#the-members-and-exclude-fields) --- Packages to exclude from the workspace. * [`default-members`](#the-default-members-field) --- Packages to operate on when a specific package wasn't selected. * [`package`](#the-package-table) --- Keys for inheriting in packages. * [`dependencies`](#the-dependencies-table) --- Keys for inheriting in package dependencies. * [`lints`](#the-lints-table) --- Keys for inheriting in package lints. * [`metadata`](#the-metadata-table) --- Extra settings for external tools. * [`[patch]`](overriding-dependencies.md#the-patch-section) --- Override dependencies. * [`[replace]`](overriding-dependencies.md#the-replace-section) --- Override dependencies (deprecated). * [`[profile]`](profiles.md) --- Compiler settings and optimizations. ## The `[workspace]` section To create a workspace, you add the `[workspace]` table to a `Cargo.toml`: ```toml [workspace] # ... ``` At minimum, a workspace has to have a member, either with a root package or as a virtual manifest. ### Root package If the [`[workspace]` section](#the-workspace-section) is added to a `Cargo.toml` that already defines a `[package]`, the package is the *root package* of the workspace. The *workspace root* is the directory where the workspace's `Cargo.toml` is located. ```toml [workspace] [package] name = "hello_world" # the name of the package version = "0.1.0" # the current version, obeying semver authors = ["Alice ", "Bob "] ``` ### Virtual workspace Alternatively, a `Cargo.toml` file can be created with a `[workspace]` section but without a [`[package]` section][package]. This is called a *virtual manifest*. This is typically useful when there isn't a "primary" package, or you want to keep all the packages organized in separate directories. ```toml # [PROJECT_DIR]/Cargo.toml [workspace] members = ["hello_world"] resolver = "2" ``` ```toml # [PROJECT_DIR]/hello_world/Cargo.toml [package] name = "hello_world" # the name of the package version = "0.1.0" # the current version, obeying semver edition = "2024" # the edition, will have no effect on a resolver used in the workspace authors = ["Alice ", "Bob "] ``` By having a workspace without a root package, - [`resolver`](resolver.md#resolver-versions) must be set explicitly in virtual workspaces as they have no [`package.edition`][package-edition] to infer it from [resolver version](resolver.md#resolver-versions). - Commands run in the workspace root will run against all workspace members by default, see [`default-members`](#the-default-members-field). ## The `members` and `exclude` fields The `members` and `exclude` fields define which packages are members of the workspace: ```toml [workspace] members = ["member1", "path/to/member2", "crates/*"] exclude = ["crates/foo", "path/to/other"] ``` All [`path` dependencies] residing in the workspace directory automatically become members. Additional members can be listed with the `members` key, which should be an array of strings containing directories with `Cargo.toml` files. The `members` list also supports [globs] to match multiple paths, using typical filename glob patterns like `*` and `?`. The `exclude` key can be used to prevent paths from being included in a workspace. This can be useful if some path dependencies aren't desired to be in the workspace at all, or using a glob pattern and you want to remove a directory. When inside a subdirectory within the workspace, Cargo will automatically search the parent directories for a `Cargo.toml` file with a `[workspace]` definition to determine which workspace to use. The [`package.workspace`] manifest key can be used in member crates to point at a workspace's root to override this automatic search. The manual setting can be useful if the member is not inside a subdirectory of the workspace root. ### Package selection In a workspace, package-related Cargo commands like [`cargo build`] can use the `-p` / `--package` or `--workspace` command-line flags to determine which packages to operate on. If neither of those flags are specified, Cargo will use the package in the current working directory. However, if the current directory is a workspace root, the [`default-members`](#the-default-members-field) will be used. ## The `default-members` field The `default-members` field specifies paths of [members](#the-members-and-exclude-fields) to operate on when in the workspace root and the package selection flags are not used: ```toml [workspace] members = ["path/to/member1", "path/to/member2", "path/to/member3/*"] default-members = ["path/to/member2", "path/to/member3/foo"] ``` > Note: when a [root package](#root-package) is present, > you can only operate on it using `--package` and `--workspace` flags. When unspecified, the [root package](#root-package) will be used. In the case of a [virtual workspace](#virtual-workspace), all members will be used (as if `--workspace` were specified on the command-line). ## The `package` table The `workspace.package` table is where you define keys that can be inherited by members of a workspace. These keys can be inherited by defining them in the member package with `{key}.workspace = true`. Keys that are supported: | | | |----------------|-----------------| | `authors` | `categories` | | `description` | `documentation` | | `edition` | `exclude` | | `homepage` | `include` | | `keywords` | `license` | | `license-file` | `publish` | | `readme` | `repository` | | `rust-version` | `version` | - `license-file` and `readme` are relative to the workspace root - `include` and `exclude` are relative to your package root Example: ```toml # [PROJECT_DIR]/Cargo.toml [workspace] members = ["bar"] [workspace.package] version = "1.2.3" authors = ["Nice Folks"] description = "A short description of my package" documentation = "https://example.com/bar" ``` ```toml # [PROJECT_DIR]/bar/Cargo.toml [package] name = "bar" version.workspace = true authors.workspace = true description.workspace = true documentation.workspace = true ``` > **MSRV:** Requires 1.64+ ## The `dependencies` table The `workspace.dependencies` table is where you define dependencies to be inherited by members of a workspace. Specifying a workspace dependency is similar to [package dependencies][specifying-dependencies] except: - Dependencies from this table cannot be declared as `optional` - [`features`][features] declared in this table are additive with the `features` from `[dependencies]` You can then [inherit the workspace dependency as a package dependency][inheriting-a-dependency-from-a-workspace] Example: ```toml # [PROJECT_DIR]/Cargo.toml [workspace] members = ["bar"] [workspace.dependencies] cc = "1.0.73" rand = "0.8.5" regex = { version = "1.6.0", default-features = false, features = ["std"] } ``` ```toml # [PROJECT_DIR]/bar/Cargo.toml [package] name = "bar" version = "0.2.0" [dependencies] regex = { workspace = true, features = ["unicode"] } [build-dependencies] cc.workspace = true [dev-dependencies] rand.workspace = true ``` > **MSRV:** Requires 1.64+ ## The `lints` table The `workspace.lints` table is where you define lint configuration to be inherited by members of a workspace. Specifying a workspace lint configuration is similar to [package lints](manifest.md#the-lints-section). Example: ```toml # [PROJECT_DIR]/Cargo.toml [workspace] members = ["crates/*"] [workspace.lints.rust] unsafe_code = "forbid" ``` ```toml # [PROJECT_DIR]/crates/bar/Cargo.toml [package] name = "bar" version = "0.1.0" [lints] workspace = true ``` > **MSRV:** Respected as of 1.74 ## The `metadata` table The `workspace.metadata` table is ignored by Cargo and will not be warned about. This section can be used for tools that would like to store workspace configuration in `Cargo.toml`. For example: ```toml [workspace] members = ["member1", "member2"] [workspace.metadata.webcontents] root = "path/to/webproject" tool = ["npm", "run", "build"] # ... ``` There is a similar set of tables at the package level at [`package.metadata`][package-metadata]. While cargo does not specify a format for the content of either of these tables, it is suggested that external tools may wish to use them in a consistent fashion, such as referring to the data in `workspace.metadata` if data is missing from `package.metadata`, if that makes sense for the tool in question. [package]: manifest.md#the-package-section [`Cargo.lock`]: ../guide/cargo-toml-vs-cargo-lock.md [package-metadata]: manifest.md#the-metadata-table [package-edition]: manifest.md#the-edition-field [output directory]: build-cache.md [patch]: overriding-dependencies.md#the-patch-section [replace]: overriding-dependencies.md#the-replace-section [profiles]: profiles.md [`path` dependencies]: specifying-dependencies.md#specifying-path-dependencies [`package.workspace`]: manifest.md#the-workspace-field [globs]: https://docs.rs/glob/0.3.0/glob/struct.Pattern.html [`cargo build`]: ../commands/cargo-build.md [specifying-dependencies]: specifying-dependencies.md [features]: features.md [inheriting-a-dependency-from-a-workspace]: specifying-dependencies.md#inheriting-a-dependency-from-a-workspace cargo-0.86.0/src/doc/theme/favicon.png000064400000000000000000000353561046102023000156170ustar 0000000000000000 ¨%6  ¨ή% h†6(0` $  '-:l3LbΜKnΔ@^y[/=$= 3b(=OΏ4OhτDf„i“Ή`ˆ¬ςMq‘³@_zT*>O /FXc!1A‘=]zώ?a€Fi‰p›Αx₯ΝS}£8^υAe„Έ@_zZ&6D ):JWcij&9K’Acώ>]yCb~\£k”ΉNxž)Rw/W|8_‚φ?cƒ½@`{],>N !/9L#-x uegis':L·=Ys>a}>yŸMгS}ŸKp‘3Y|*Rw*Rw.V{8^χ@d„Ώ@`|a(;K  #,6D$/u*@TΓ:Xtυ>]zλ+@R΅"†+6Ÿ5K`Χ;_{ω-k‘s¦…½?¬δA’ΦKŽΈO{žDiŠ4Z|+Sw)Rw-Uyη<±μ<―ι@£ΨW—Ύ_…₯Hl6[|#Gg3Xyn™ΐd²ωKp‘ΗAaiη<―κ<―κ:°λZΊλ}ΐδcŸΔO€Fj‰Bd„l–»v‘ΙHr˜3[~ϊ>bƒΚBc€n7Nc   1 @ENQV0H^Ί>Zu>[t:dƒ'o™w­|Ά}Έ ~Έ Ί Ί €»ŒΔ>ζ;―κ;―ι:ιVΈκ{Ιπ_Όμ<₯έG•ΓP¦V{œ`†¨Cj(Qv+Sx4\ϋ>c„ΝAb€q5La" +)5b/G]·7SmΑ!3C Z%t.AR²;Ysο4d…0tœz―{Ά }Έ }· s© mŸ v¬‚ΌƒΎŽΗ>­ζ;ι;ι;ι@°θ[ΊιWΈι9­θ9­θ>¨ήK”ΐOƒ©Ov˜?d†/Vz)Rw,Uz3[ό?d…ΡJlŠu6Qj".<,-CX7Tnρ@bIo“>_}φ5MdΨ;Ztν1gŠoŸ v­!ˆ½» ~Ή ~Έ q₯ o’ o‘ h—~Ά…Α Ι>­ζ:ι:ι:ι:θ9­θ:¬η9­η:­θ<ιE­β?ͺβEΞO‹³PyœAfˆ0Wz$Jk3YzgΆό\ƒ¦ΣQv—F5PiZ>_|ύ>_}=\xB`|IiƒN|™r£v―y΄{΅#‹ΏƒΌ Ό x q€}Άq’h–{±ˆΔ"’Λ=­ε:­θ:θ:­θ:­θ9­η9¬η:­θ:­θ<θF―ε=°λ<°μ=­ζC ΣNŽ·Pzž>a€;_p›Αu‘Θm˜Ύj9Vp]>\wύ?[u:`}3o”V˜»NΖ |΅z΅{Ά }·$ŒΑ…Ώ‚Όnži˜q£p v©~΄‹Ζ$”Ν=¬ε9­θ9­η9­η9¬η8¬η9¬η9¬η9¬η;­ηF°ε=°κ<―κ<―κ<°λ<­ηB’ΦL»S£]ƒ₯h΄l•Ίf;VmW:cσ&k”s§ΆS£ΜFšΕ ~· }Έ ~Ή €Ί&ŽΓˆΒΈp‘j˜ožnžv¨†ΏΘ&–Ο=¬ε9¬η9¬η8¬η8¬η9¬η9¬η9¬η9¬η;­ηF°ε=―κ;ι;―κ:¬ζ:­η;―κ;θ@€ΩJ’ΏT„©πW{œT*Ri!vͺΣy³z΅€Έ2’Β„» Ί Ί »‚Ό(ΔŠΔΆu¨nr’v§}°ŽΘΚ(˜Ρ<¬ε8¬η8«ζ8«ζ8«ζ8«ζ8«ζ8«ζ8«ζ:¬ζF―ε<―ι;ι7€Ϋ1’Γ1‘Α6ŸΤ;­θ;―κ;ιD©ήΚP‚Ÿ!\{|³|· }Έ ~Ή Ί €»‚Ό‚ΌƒΎ…ΐ*‘ΖŒΖ„½ožt₯|°|―ŠΒ‘Μ’Ν*šΣ<¬ε6§α7©γ8«ζ8«ζ8«ζ8«ζ8«ζ8«ζ:¬ζF―ε<θ9«ε0Ώ0ΐ6‘Χ2•Θ5žΤ:ι:ιB°θΚU₯Ν*x ΉΟ Ί €»Όƒ½ƒΎ„Ώ…Ώ†ΑˆΒ+’ΗŽΘŒΖ|―v§{‰Α’Ν “Ξ ”Ο+›Υ<¬ε1ŸΧ5₯ή7«ζ7ͺε6ͺε7«ζ7ͺε7ͺε9«εF―ε;θ8¨α0ΐ.‹Ί1”Η5ŸΥ0ΐ8¦ί:­θB°θΙT©Τ0†²…½ΞΌƒΎ…Ώ†Α‡Β‡ΒˆΓ‰ΓŠΔ-”Ι‘ΚΛΚΕΚ ”Ο!”Ο"–Ρ&—Ρ6G­ΰ;ͺγ7ͺδ5ͺεL±εVΆη=¬ε7ͺε7ͺε9«εG―ε;­η8¨α1•Θ/Ώ/ŽΎ.Œ»,…³3›Π9­θA°θΙR©Σ2ˆ΄ˆΐΞ…ΐ†ΑˆΓ‰Δ‹ΖŒΖ‹ΖŒΖΘ0–Λ"“Ν’Ν“Ξ ”Ο!•Π#–Ρ*˜Π0–Ι,Ύ.ΒHͺάIͺΫH«ή>«γWΆηwΕμWΆη5©δ5¨β8¨βG°ε:­η8«ζ0“Ε+„².‹Ί-‰Έ1•Θ1•Θ8¬ηA°θΙR¨Σ5ŠΆ‹ΓΞˆΓŠΕ‹ΖŒΗŽΙΛΛΛ#‘Μ2˜Ν$•Ο ”Ο!•Π&—Π3šΟ8–Η(ŠΌ„Ή»Ε@―θ=―κA­γFͺέ`³έ}Γζ^Έζ5©δ2‘Ϊ4‘ΩG°ζ9«ζ8«ζ4žΥ.½/‘Γ-ŠΉ0’Ε1–Ι8«ζ@―ηΙR§8» ŽΖΞŒΗΘΚΛ’Ν!•Π$—Ρ$’Κ(•Ο5›Ο'˜Ρ+˜Π2—ΛFœΘdͺΞ:”Β ΌƒΏ„Ύ!Η@η<°λ<°λ<―κ@ζV±ΰ[±έH¬ί?ͺΰ9¨αF―ε8«ε7«ζ7©δ2™Ξ0“Ε1—Λ.ŽΏ3Σ7«ζ@ζΙS¨Σ<“ΐ#’ΚΞΛ’Ν “Ξ"•Π*šΣ'šΥ(œΧ(—Ο-Χ<Ÿ8˜Κ+Ώ„Ί9—Η\ͺ6•Ζ„Ώ†Α†Α#‘Ι@―η<°λ<―κ<―κ<°λ;―λ<―ιA¬γH«ήNίS³δ=¬ε7«ζ6ͺζ6©γ3Τ0”Η2šΠ6©γ7«ζ?ζΙSͺΦ<’½'–ΞΞ ”Ο"–Ρ)šΤQ­ά_³ή/ŸΩ/’ά<¨ίM°βD’Ρώ…ΌΌ‚Ύ;™ΚQ₯Ο%ΕˆΓ‰Δ‰Δ%“Λ@―η;ι;ι:¬ζ9¨ΰ:«ε;―κ;―κ;ιA―ηU³βNίώJ­ΰώ@¬γ8«ε6ͺζ6ͺε6ͺε6©δ6ͺε?­εΙP¦ΠFœΘ,šΞ%”Ν&šΥ4’Ϊi»δjΉβG«ήR²γW΅εU΅ηA§Ϋ…ΐ„Ώ†Α‹ΔŠΔŠΕ‹ΖŒΗŒΗ'•Ξ@―η;ι:¬ζ3–Θ0Ώ1’Γ7£Ϊ;ι;ι>°ιL΄ι?°ιD­δώK¬ήώM­ήώE­βώ:«δ6ͺε5©δ6©γ>¬εΙP¦Ρ^΄ΰ1ŸΦΞ(–Ξ/ ΪG¬ΰŒΚι“Κηn»γW΄δM±εM²η@§άˆΒˆΒ‰ΔŠΕŒΗΘΘŽΙŽΙ)—Π?η:ι6’Ψ-‡΅3—Κ6’Ω2•Η7₯έ:ι>―ιL΄ι=°λ<°λ<―κE―εrΌβώd΅ήύK­ίώ?¬γ7ͺδ=¬εΙO¦ΡeΊε@©ήΞDͺίQ°αX΄δnΏθ}ΕλƒΗλ€Εθp½ε^·δD¨Ϋ‹Ε‹ΖŒΗŽΙΚΚΛΛ‘Μ,š?ζ:ι4Σ1’Δ-ˆ·4›Ο1“Ε1”Η9­η=θL΄ι=°κ<―κ;―κB±κsΕοuΔμJαώJ«άύK¬άM°βΘV©Ηι bΈδžV³δυO±δL±εJ°εM²ζY·ηlΏκ}Ζλ…Θκb΄ήΙŽΙΚ‘Λ’Ν’Ν “Ν “Ν ”Ο.›Τ?­ζ9­θ5 Χ0’Δ-ˆ·/ŽΏ-‡΅.‹Ί7§ί=ηK³θ=―κ;ι;―κ>―ιfΏμvΕνB±ι9­η>«βMΰΓ\’Δ tΒκYΆηCS³ε“P²εΪN²εόL±εK°εL²ζR΄ηa»ιY³α ’Μ‘Μ“Ξ!”Ο"•Π"•Π"•Π#–Π#–Ρ1Υ?­ζ8¬η7§α-ŠΊ,†΄.ŒΌ/ΐ0“Ζ5’Ω<θK³η<―ι;ι;―ι;ι=―ιJ³ι=η9¬η:ι@εΕI–» xΔμ]ΆδYΆζcS΄ζ΄O²ενN²ζM±ζL±ζDͺί#•Ο!”Ο#–Ρ$˜%™Σ&šΤ&™Τ&˜Σ'˜Σ3ŸΧ>­ζ8«ζ8«ζ2™Ξ0’Ε0’Δ/‘Β/Α5£Ϋ<­ηJ²η<θ:­θ:θ:ι:­θ8­θ9¬η9­θ:ιA­εΕI–Ό pΌδ ]·ζ7VΆη…R΄ηΠP³ηωE¬ΰ&˜$˜Σ&™Τ'›Φ)œΦ*žΩ+žΩ*›Υ)–Ο6 Ω>¬ε7«ζ8«ζ7©γ1—Λ0’Δ/‘Γ/’Ε7¨γ;¬ζJ²η;­θ:­θ:­θ:­θ9­θ9¬η9­θ:­η:­θ@­δΕH”» ‚ΙοaΊι[ΈθUG«ήΎ*›Υ(›Φ)Ψ*žΩ-ŸΪ0’Ϋ/’έ. Ω,šΣ:€έ>¬δ6ͺε7ͺε7«ζ6©γ3 Χ2œ6§ΰ7ͺε:«εI±ζ:­η9¬η9¬η9¬η8¬η9¬η9­θ9¬η9­θ?¬δΕH•» ;’Φm-ŸΩ+ŸΪ, Ϋ=¨ήaΈδN―ΰ0₯ΰ7¨βB­γS΄εR΅θA―ζ8«ε6ͺε6ͺε7«ζ7«ζ7ͺε6ͺε:¬εI±ζ:­η9¬η8¬ζ8¬ζ8¬η9¬η9¬η9¬η9¬η?¬δΕG”Ί >₯Ϋm/ŸΨ-ŸΨ.’ήS³δsΑιX΄γG―δT΄εW΅εT΅ηUΆθX·θTΆθG±ζ;¬ε6ͺε5©δ6©δ6©δ9«εI±ζύ9«ζ8«ζ8«ε8«ζ8«ζ8«ζ8«ζ8«ζ8«ζ?¬δΕPœΒ A¨έm0žΦ.žΧ5§αd»η”Ξμ€Βδ]΅γP²δL²ζM²ηN²ηN³ηR΅θW·θXΈιO΄θAζ8ͺδ5¨γ9ͺδI²ηό8©γ4£ά7«ζ7«ζ7«ζ7«ζ7«ζ7«ζ7ͺεB―ηΕxΓι F¬ΰm>ͺβHβS²γg»ζ„Θλ†ΘλΕθrΎε^ΆδQ²δM²ζN³θN³θN³ηP΅ιU·ιYΈιTΆιG°ζ>¬εI²ηό7¨α2 Ψ7ͺε8«ε;¬ε6ͺε7«ζ7ͺε7ͺεB―ηΕ}Ηξ V±ίmX΄γT³γO±δL±εL±εWΆηjΎι}Ζλ„Ηκ{Βηj»εX΅εO³ζN³θO΄ιO΄θO΄θRΆιYΉκ]Ίκ^ΉθύM²ζ@ε8ͺε<¬δiΎιXΆη9«ε6ͺδ6ͺεBζΕ|Ζν 5œΡm1Τ>§έJ―βN²εM±εK°εL±εR΄η`ΊθtΒλ‚Θλ‚ΖκtΏζaΈεS΄ζO΄θQ΅θUΆιW·ιUΆθS΅ηU΅ζX΅ζR³εK±εpΑλoΑλ=¬δ5¨γ3’ΫA­δΕ|Ηξ 3Σm#–Ρ$—,Φ;¦έG­βM±εM±εM²ζL±ζN²ζX·θjΏλ|Ελ†Θλ†Θκl½ηUΆηR΄ηO²ηM²ηM³ηM²ηO³ηYΆζp½ε“Λθ‰ΘιH°ε7©γ0žΥ@¬δΕ|Ηο 7‘Χm'šΤ'›Φ(œΧ)Ψ- Ϊ9¦ήE­γM²ζN²ζM²ηM²ηO³ηVΆθg½κh½ιV΅ζM±εM²ζL²ζL²ζP³ζ]·ζpΏθ€Ει†ΙμƒΙνsΑιZΆεS³εG―δH°ζΖ|Ζμ 9€Ϊm*žΨ*žΩ+ŸΪ8₯έU²βDͺή0€ί9©γL±εWΆηX·θVΆηP²εM±εK±εK°εK±εM±εV΄εg»ζzΓι…ΘλΗμnΐκ]ΊκQ΅ιN³θP΄θTΆθZ·ηψf»η”Οο=§έm-žΨ-ŸΪ.’έW΄δtΑθQ±αB­γQ³δW΄δV΅ζY·θώ\ΈθώWΆζR³ζN±εQ±γ_·δsΏηΖι‚ΗλuΓλc»κT΅ηN²ζN³θO΄ιQ΅ιύS΅ιΰWΈκœ]ΊλKnΐμ@ͺαm.›Σ.žΧ3¦αfΌθŒΚκu½βY΄γQ²εM²ζM³ηN³ηO³ηT΅θZΈθi½ι‡Ιλ‰Ιλ{Ελi½ιWΆηN³ηM²ζN²ηO³ηR΅θρV·ιΌYΆζl]Άδ%sΕπC­γm:¨ΰE­αQ²γpΏηŽΛλ‰Ικ|ΓθjΊδX΄δN²εM²ζN³ηN³ηO³ηTΆιcΌκkΏλ^ΊιT΅ηN²ζN²ηP³ηϋS΅θΧW·ιŽ_Ίθ?qΐθ aΉζ_Y΅δωT²γP±δL±εP³ζ^ΉθrΑλΗλƒΖιvΐζcΈδT΄εN²ζN³ηO΄θN΄θO΄θTΆι[Ήι`»ιοY·θ­X·θ^a»ι~ΘοyΑη]·ζYR³ε¬O±διM±ζώL±εK°εM²ζUΆθfΌιyΔκ„Θλ€Ειo½ζ\ΆεQ΄ηO΄θQ΅θόTΆιΪXΈκ’hΏμ?ˆΝρh½θ[·ζ0T²γ|Q²εΙN²εφM±εL²ζL±εO³ζ\ΉιoΑλΗμ†ΘλƒΕηυkΊβΐXΆηfaΌλ wΖξc΅ΰ[ΆεLT΅ηQ΄ηίN²ζόM²ζM²ηO΄θϊYΈιΦzΔ돠ΘέG°ΐΗqΒμ^Ίι,WΆη}S΅ηΥT΅ηΝY·θo]Ήι!L―δώψπππψΰΰΰωΐΰΰΰΰΰΰΰΰΰΰΰΰΰΰΰΰΰψΐψόόόόόόόόόόόόόώΐπώ( @   # 1?l8SlΞTyšΘHi‡]3I\/J%0ƒ8VqρEg†n—Ύ\…ͺσ:_΅=^{V0DV "?S`g-;—?]yϋCg…\†©T{ -Uy1Y}φ9^»>_|Z2H\   (>)6w1JaΔ2Ka½!*Š ,7›2QjΪ,gŒ$~―BΟIŠ΄Dn’4[~,Tx0W{χBgˆΏLnŒ^3J^"0?!2B†:XtυAb€Ef…9\xφ*iϊu¨ {΅‡ΐ;­η<―ιF₯Ψc˜ΌLu—2UvIn‘k•»ψGnΒ=_}b>Wo , =FP+>Pž?]x:`~*l”w« |Ά ~Ή Ί‰Γ<¬ζ;―κA±λqΓνYάEŽΊP~’cŠ?f‹.Vzω7]Ζ=_~f5Oe  1?^3NgΉ9XtΔ"3CŠ+?Q€0\yη)n–| }· {΄ q₯ q₯€»Ζ;¬ε;ι;ιM΄ιG²ι9­θB₯ΩJ’½I|’«δEœΝO‰±`‹―ψf޲I1\x)q ΰw±ˆ½-Α Ή Ί†ΎŒΔ{±p q‘z¬‹Ζ%–Ο:«δ8¬η8«ζ8¬ζ8¬ζ8¬ζ?­ζ@―θ:¬ζ5žΣ59«ε<¬εEŸΡΫR…©#qœ }ΆΧ }Ή €Ί Ό‚½ƒΎ‰Β!Η€Άs£{ˆΐ’Ν'™9©β5¦ΰ8«ζ7«ζ7«ζ7«ε>­ε@―θ6’Ω/½4šΟ4›Ο9¬ζ?°ιO°ΰ%†Ά‚ΌΥ‚½„Ώ†Α‡Α‡Β Ε$’ʍȇ½ŒΔ ”Ο#•Π0›@©ί7§ΰ:¬ζK²ζ;¬ε6ͺε>¬ε?―θ5‘Ψ/ŽΏ0Α.ŒΌ6’Ω>―θM―ΰ*Š»‡ΐՇ‰ċƍǍΘ%‘Κ'•Ν“Ξ!•Π&–Π+•Λ'ŽΒ(ΓCͺίE«ΰH­αpΐθN³ζ3¦α<©α?η6₯ή.‹»-ŠΊ/ΐ3Σ=θMί.ΐŒΕΥŒΗŽΙΛ!”Ο"“Ν+–Ξ,™Π(–Ξ7™ΛM Λˆ½‚ΌŒΖ=­η<―κAε\΅βS±α<§ή>©ΰ>­ζ7ͺε2›Ρ0’Ε/Β4 Χ=­ηMί3”Ε!’ΛΥ’Ν&—Ρ6 Φ*œΧ,Φ9‘Χ2–ΘˆΎ2“ΔP£ΞˆΑ†Α Ι=­η<―κ;―κ;ι>θB­γM°βI―γ;«ε7©γ3 Χ3žΥ6©γ<¬ζL­ί;œΝ'–ΟΥ#—B¨άiΉβEͺήL°γP±γ!ŽΖƒΎŒΔ%ΗŠΕ‹Ζ#“Ν=­η:¬ζ5›Π4šΞ9¨α:κD±θH±ζF­βώF¬αώ@¬γ8ͺε5©δ:«δK¬έL­ί2ŸΦΥ6’Ω]ΆγŠΘιrΎζ\ΆεM±δ#’ΚˆΓ‹ΖΘŽΙΙ&–Π=­η7€Ϋ/½3™Ν3™Ν9ͺδC±ιB±κ;―κE°ηm½εώS±ΰώA«ΰ@¬γΡL­έeΊδT²βΆQ±γόQ²εYΆηjΎιwΒιqΎζ.˜ΞΘΛ‘Μ’Μ’Ν*™Σ<­ζ6€ά/ΐ/ŽΎ.Œ»5 ΦB°θB±ι;κ@°κkΑνTΆι?«βI­ΰΞX­Ψe»ηS³ε[P²ε­M±εκL±εQ΄η\·ζ0›’Ν!•Π#–Ρ#–Ρ#–Ρ.œΥ<¬ε7¨β/ŽΏ.ŒΌ/ΐ3œA―θA°θ:ι;ιA°ι@―θ9­θ>­ζΟI€fΉδZΆε1S΄ζ~P³ηΛM±εχ/Φ#—&šΤ'›Φ)Ψ(™Σ1Φ;«ε7«ζ4 Ψ0”Η/‘Γ4 ΨA―η@―θ:­θ:­θ9­θ9¬η:­θ>­ζΟG£_ΊκQ±γZ1ŸΨθ(œΧ. Ϊ;¦ά1£έ0 Ϊ=¦έ@­ε7ͺε6ͺε5€έ4’Ϊ6©δ@ζ@η9¬η9¬η9¬η9¬η9¬η=¬εΟF£ΡB€Φ1 ΨΨ+ŸΪE¬αjΌζF­βK±δT΄ζT΅θL³ηAζ8«ζ6ͺε5©δ?­εώ?ζώ7«ζ8«ζ8¬ζ8¬ζ8«ζ<¬εΟJ¦ΥG©Ϋ6£ΫΨ7₯έ\·ζ‹Κκo½εY΅εN²ζM²ηQ΄θTΆθQ΅θG°η;«δ?­εώ=«γώ4₯ί7«ζ7«ζ7«ζ7«ε>­ζΟ^ΉθO«ΪO°βΨQ²γS³ε_ΉηnΏιxΓιqΎζ_ΈζR΄ηN³θP΄ιSΆιTΆιUΆθώK±εώ<ͺγ<¬εTΆη?­ε6ͺε=­ζΟ`»κ:Π0œΤΨ9€ΪF­βK°εM±εU΅ηeΌιvΒκxΒιk½η[ΈηS΅θTΆθS΅θR΄ηR΄ζV΅εzΔκQ΄ζ3₯ί:§ίΟaΎξ?€Ψ)šΤΨ&šΥ,žΨ9¦ήE­γK±ζM²ζQ΄η_ΊιrΑκdΊηO²ζL±ζN²ζXΆηj½θ|Δι„Θκ`ΉζGγD­βΟb½λD©έ.ŸΩΨ*žΩ;§ήV²β9¨ΰEδU΅ζX·θS΄ζM²ζK°δQ²εaΉζsΐθyΓκnΐκ]ΊιR΅ιQ΄θύV·θβ_Ήθ†|ΔκH―γ1ŸΨΨ. ΪV΅εΔθ[΅γR³εO³ζQ΄ηU΅ηX·ηnΎθ{ΓιsΑιb»θT΅θN³ηP΄θρSΆθ½UΆθl[Ίλ%fΐπS΄ζE¬αΧJβ^ΈζzΓιzΓιoΎζ]·εQ³ζM²ηP΄θ\Ήκb»κY·θR΄ηϋP΄ηΧT΅θYΈθ?gΌθ vΒι^·εoR²δΛM±εχL±εU΅ηgΌιvΒιwΒθiΌηYΆηP΄θP΅θρXΈι»cΌκe^ΉιqΒλZ·ζT³δLQ²εN²εΰM²ζόP³ζ\ΉιpΑλϋ‚ΖιάuΎγ—XΆη?`Όμ r½εZ·η+T΅η}Q΄ηΧQ΄ηΠUΆθrzΒη%ΡΚΒώψψ€ώώΰΐΐΐΐΐΐΐΐΐΐΐπώ€€€€€€€€€ΐπώ(  &J>[uΛY~ Λ:^]6Sl #%8Hh ,8!9L¦5m“ϊK‰²:e‰τ4Xz·EhˆUKk‡  8 -:v9]zς+hωr£ϊ…Ύ9©βR¦ΥHƒ«R€χAf‰Ό3WwY7Vr/EZ8Tm°:^yΝ d‹άy« z± s¨ˆΑ8«ε@±κ?ηD£ΦAˆ΄:iŽψRx›·k’Ά"3_~/%l–ζ.…΄€Ή†Ώvͺt¦Η8ͺδ8¬η9¬η>―θ:©β=ŸΣL˜Ζε^’Ή/}± €ΊΪ„Ύ…ΐΕƒΊˆΏ(—Π9§ί>­ε:¬ε=­ζ3šΞ1–Ι9©αΨE±η ‹ΑŠΔٍȐΛ(•Ν*–Ν-”Θ"Ζ=ͺαQ³ζFβ=«δ4žΤ/‘Γ7€ΫΨE³κ+–Μ$•ΟΩ@₯Ψ@§ά3œΡ$Γ(ΖΙ9ͺδ9¦έ>¬γF―ε@«β:¦ά9©βΨB­δE©ΫB©έΘ`ΈεiΌθB₯ΨŒΗΚ%–Π7₯έ0’Γ5ΣA°ιD±ιVΆηB¬βΧH­ΰ~ΕιYΆζ)P²εvU΅ηΕB¨άφ"–Ρ%™Σ,œΦ8¨α0–Ι2™Ν?η;ι>―θ<­ζΦD«ί`»λ 4’Ϊ’6£ΫH­ΰBͺΰE―ζ;ͺβ6§α=­ζ8«ζ7¬η:¬ζΦB«ΰ?§έyN°βl½ηcΊηXΆηP΄θJ²ηF―εώ=«δ@ζ9«εΦH±ζ1žΦy7£ΫGγWΆηe»θaΊθR΄ηWΆηcΊηc»ηA¬βΦK±ε0 Ωy>¨ήY΄γO²εS΄ηY·ηe»ηd»θ]ΉιςW·θΏVΆηbcΊηJαWR²δαdΊηόe»η_Ήη[Έθό]ΉιΫUΆθP΄η?VΆη sΒλR²ε+O²ε}T΅ηΧc»ιΤrΏηyWΆη&oΔρώψπ€€€€€€ΰπψψψψώcargo-0.86.0/src/doc/theme/head.hbs000064400000000000000000000000741046102023000150500ustar 00000000000000 cargo-0.86.0/src/etc/_cargo000064400000000000000000000576371046102023000135530ustar 00000000000000#compdef cargo autoload -U regexp-replace _cargo() { local curcontext="$curcontext" ret=1 local -a command_scope_spec common parallel features msgfmt triple target registry local -a state line state_descr # These are set by _arguments typeset -A opt_args common=( '(-q --quiet)*'{-v,--verbose}'[use verbose output]' '(-q --quiet -v --verbose)'{-q,--quiet}'[no output printed to stdout]' '-Z+[pass unstable (nightly-only) flags to cargo]: :_cargo_unstable_flags' '--frozen[require that Cargo.lock and cache are up-to-date]' '--locked[require that Cargo.lock is up-to-date]' '--color=[specify colorization option]:coloring:(auto always never)' '(- 1 *)'{-h,--help}'[show help message]' ) # leading items in parentheses are an exclusion list for the arguments following that arg # See: http://zsh.sourceforge.net/Doc/Release/Completion-System.html#Completion-Functions # - => exclude all other options # 1 => exclude positional arg 1 # * => exclude all other args # +blah => exclude +blah _arguments -s -S -C $common \ '(- 1 *)--list[list installed commands]' \ '(- 1 *)--explain=[provide a detailed explanation of an error message]:error code' \ '(- 1 *)'{-V,--version}'[show version information]' \ '(+beta +nightly)+stable[use the stable toolchain]' \ '(+stable +nightly)+beta[use the beta toolchain]' \ '(+stable +beta)+nightly[use the nightly toolchain]' \ '1: :_cargo_cmds' \ '*:: :->args' # These flags are mutually exclusive specifiers for the scope of a command; as # they are used in multiple places without change, they are expanded into the # appropriate command's `_arguments` where appropriate. command_scope_spec=( '(--bin --example --test --lib)--bench=[specify benchmark name]: :_cargo_benchmark_names' '(--bench --bin --test --lib)--example=[specify example name]:example name:_cargo_example_names' '(--bench --example --test --lib)--bin=[specify binary name]:binary name' '(--bench --bin --example --test)--lib=[specify library name]:library name' '(--bench --bin --example --lib)--test=[specify test name]:test name' ) jobs=( '(-j --jobs)'{-j+,--jobs=}'[specify number of parallel jobs]:jobs [# of CPUs]' ) parallel=( "${jobs[@]}" '--keep-going[do not abort build on first build error]' ) features=( '(--all-features)'{-F+,--features=}'[specify features to activate]:feature' '(--features -F)--all-features[activate all available features]' "--no-default-features[don't build the default features]" ) msgfmt='--message-format=[specify error format]:error format [human]:(human json short)' triple='--target=[specify target triple]:target triple:_cargo_target_triple' target='--target-dir=[specify directory for all generated artifacts]:directory:_directories' manifest='--manifest-path=[specify path to manifest]:path:_directories' registry='--registry=[specify registry to use]:registry' case $state in args) curcontext="${curcontext%:*}-${words[1]}:" case ${words[1]} in add) _arguments -s -A "^--" $common $manifest $registry \ {-F+,--features=}'[specify features to activate]:feature' \ "--default-features[enable the default features]" \ "--no-default-features[don't enable the default features]" \ "--optional[mark the dependency as optional]" \ "--no-optional[mark the dependency as required]" \ "--dev[add as a dev dependency]" \ "--build[add as a build dependency]" \ "--target=[add as a dependency to the given target platform]" \ "--rename=[rename the dependency]" \ "--dry-run[don't actually write the manifest]" \ '--branch=[branch to use when adding from git]:branch' \ '--git=[specify URL from which to add the crate]:url:_urls' \ '--path=[local filesystem path to crate to add]: :_directories' \ '--rev=[specific commit to use when adding from git]:commit' \ '--tag=[tag to use when adding from git]:tag' \ '--ignore-rust-version[Ignore rust-version specification in packages]' \ '1: :_guard "^-*" "crate name"' \ '*:args:_default' ;; bench) _arguments -s -A "^--" $common $jobs $features $msgfmt $triple $target $manifest \ "${command_scope_spec[@]}" \ '--all-targets[benchmark all targets]' \ "--no-run[compile but don't run]" \ '(-p --package)'{-p+,--package=}'[specify package to run benchmarks for]:package:_cargo_package_names' \ '--exclude=[exclude packages from the benchmark]:spec' \ '--no-fail-fast[run all benchmarks regardless of failure]' \ '--ignore-rust-version[Ignore rust-version specification in packages]' \ '1: :_guard "^-*" "bench name"' \ '*:args:_default' ;; build | b) _arguments -s -S $common $parallel $features $msgfmt $triple $target $manifest \ '--all-targets[equivalent to specifying --lib --bins --tests --benches --examples]' \ "${command_scope_spec[@]}" \ '(-p --package)'{-p+,--package=}'[specify package to build]:package:_cargo_package_names' \ '--release[build in release mode]' \ '--build-plan[output the build plan in JSON]' \ '--ignore-rust-version[Ignore rust-version specification in packages]' ;; check | c) _arguments -s -S $common $parallel $features $msgfmt $triple $target $manifest \ '--all-targets[equivalent to specifying --lib --bins --tests --benches --examples]' \ "${command_scope_spec[@]}" \ '(-p --package)'{-p+,--package=}'[specify package to check]:package:_cargo_package_names' \ '--release[check in release mode]' \ '--ignore-rust-version[Ignore rust-version specification in packages]' ;; clean) _arguments -s -S $common $triple $target $manifest \ '(-p --package)'{-p+,--package=}'[specify package to clean]:package:_cargo_package_names' \ '--release[clean release artifacts]' \ '--doc[clean just the documentation directory]' ;; doc | d) _arguments -s -S $common $parallel $features $msgfmt $triple $target $manifest \ '--no-deps[do not build docs for dependencies]' \ '--document-private-items[include non-public items in the documentation]' \ '--open[open docs in browser after the build]' \ '(-p --package)'{-p+,--package=}'[specify package to document]:package:_cargo_package_names' \ '--release[build artifacts in release mode, with optimizations]' \ '--ignore-rust-version[Ignore rust-version specification in packages]' ;; fetch) _arguments -s -S $common $triple $manifest ;; fix) _arguments -s -S $common $parallel $features $msgfmt $triple $target $manifest \ "${command_scope_spec[@]}" \ '--broken-code[fix code even if it already has compiler errors]' \ '--edition[fix in preparation for the next edition]' \ '--edition-idioms[fix warnings to migrate to the idioms of an edition]' \ '--allow-no-vcs[fix code even if a VCS was not detected]' \ '--allow-dirty[fix code even if the working directory is dirty]' \ '--allow-staged[fix code even if the working directory has staged changes]' \ '--ignore-rust-version[Ignore rust-version specification in packages]' ;; generate-lockfile) _arguments -s -S $common $manifest ;; help) _cargo_cmds ;; info) _arguments -s -A "^--" $common $registry \ '--index=[specify registry index]:index' \ '*: :_guard "^-*" "crate"' ;; init) _arguments -s -S $common $registry \ '--lib[use library template]' \ '--edition=[specify edition to set for the crate generated]:edition:(2015 2018 2021)' \ '--vcs=[initialize a new repo with a given VCS]:vcs:(git hg pijul fossil none)' \ '--name=[set the resulting package name]:name' \ '1:path:_directories' ;; install) _arguments -s -S $common $parallel $features $triple $registry \ '(-f --force)'{-f,--force}'[force overwriting of existing crates or binaries]' \ '--bin=[only install the specified binary]:binary' \ '--branch=[branch to use when installing from git]:branch' \ '--debug[Build in debug mode (with the "dev" profile) instead of release mode]' \ '--example=[install the specified example instead of binaries]:example:_cargo_example_names' \ '--git=[specify URL from which to install the crate]:url:_urls' \ '--path=[local filesystem path to crate to install]: :_directories' \ '--rev=[specific commit to use when installing from git]:commit' \ '--root=[directory to install packages into]: :_directories' \ '--tag=[tag to use when installing from git]:tag' \ '--version=[version to install from crates.io]:version' \ '--list[list all installed packages and their versions]' \ '--ignore-rust-version[Ignore rust-version specification in packages]' \ '*: :_guard "^-*" "crate"' ;; locate-project) _arguments -s -S $common $manifest \ '--message-format=[specify output representation]:output representation [json]:(json plain)' \ '--workspace[locate Cargo.toml of the workspace root]' ;; login) _arguments -s -S $common $registry \ '*: :_guard "^-*" "token"' ;; metadata) _arguments -s -S $common $features $manifest \ "--no-deps[output information only about the root package and don't fetch dependencies]" \ '--format-version=[specify format version]:version [1]:(1)' ;; new) _arguments -s -S $common $registry \ '--lib[use library template]' \ '--vcs:initialize a new repo with a given VCS:(git hg none)' \ '--name=[set the resulting package name]' ;; owner) _arguments -s -S $common $registry \ '(-a --add)'{-a,--add}'[specify name of a user or team to invite as an owner]:name' \ '--index=[specify registry index]:index' \ '(-l --list)'{-l,--list}'[list owners of a crate]' \ '(-r --remove)'{-r,--remove}'[specify name of a user or team to remove as an owner]:name' \ '--token=[specify API token to use when authenticating]:token' \ '*: :_guard "^-*" "crate"' ;; package) _arguments -s -S $common $parallel $features $triple $target $manifest $registry \ '--index=[specify registry index]:index' \ '(-l --list)'{-l,--list}'[print files included in a package without making one]' \ '--no-metadata[ignore warnings about a lack of human-usable metadata]' \ '--allow-dirty[allow dirty working directories to be packaged]' \ "--no-verify[don't build to verify contents]" ;; pkgid) _arguments -s -S $common $manifest \ '(-p --package)'{-p+,--package=}'[specify package to get ID specifier for]:package:_cargo_package_names' \ '*: :_guard "^-*" "spec"' ;; publish) _arguments -s -S $common $parallel $features $triple $target $manifest $registry \ '--index=[specify registry index]:index' \ '--allow-dirty[allow dirty working directories to be packaged]' \ "--no-verify[don't verify the contents by building them]" \ '--token=[specify token to use when uploading]:token' \ '--dry-run[perform all checks without uploading]' ;; remove | rm) _arguments -s -A "^--" $common $manifest \ "--dev[remove as a dev dependency]" \ "--build[remove as a build dependency]" \ "--target=[remove as a dependency from the given target platform]" \ "--dry-run[don't actually write the manifest]" \ '(-p --package)'{-p+,--package=}'[package to remove from]:package:_cargo_package_names' \ '1: :_guard "^-*" "crate name"' \ '*:args:_default' ;; run | r) _arguments -s -S $common $parallel $features $msgfmt $triple $target $manifest \ '--example=[name of the bin target]:name:_cargo_example_names' \ '--bin=[name of the bin target]:name' \ '(-p --package)'{-p+,--package=}'[specify package with the target to run]:package:_cargo_package_names' \ '--release[build in release mode]' \ '--ignore-rust-version[Ignore rust-version specification in packages]' \ '*: :_default' ;; rustc) _arguments -s -S $common $parallel $features $msgfmt $triple $target $manifest \ '(-p --package)'{-p+,--package=}'[specify package to build]:package:_cargo_package_names' \ '--profile=[specify profile to build the selected target for]:profile' \ '--release[build artifacts in release mode, with optimizations]' \ "${command_scope_spec[@]}" \ '--ignore-rust-version[Ignore rust-version specification in packages]' \ '*: : _dispatch rustc rustc -default-' ;; rustdoc) _arguments -s -S $common $parallel $features $msgfmt $triple $target $manifest \ '--document-private-items[include non-public items in the documentation]' \ '--open[open the docs in a browser after the operation]' \ '(-p --package)'{-p+,--package=}'[specify package to document]:package:_cargo_package_names' \ '--release[build artifacts in release mode, with optimizations]' \ "${command_scope_spec[@]}" \ '--ignore-rust-version[Ignore rust-version specification in packages]' \ '*: : _dispatch rustdoc rustdoc -default-' ;; search) _arguments -s -S $common $registry \ '--index=[specify registry index]:index' \ '--limit=[limit the number of results]:results [10]' \ '*: :_guard "^-*" "query"' ;; test | t) _arguments -s -S $common $jobs $features $msgfmt $triple $target $manifest \ '--test=[test name]: :_cargo_test_names' \ '--no-fail-fast[run all tests regardless of failure]' \ '--no-run[compile but do not run]' \ '(-p --package)'{-p+,--package=}'[package to run tests for]:package:_cargo_package_names' \ '--all[test all packages in the workspace]' \ '--release[build artifacts in release mode, with optimizations]' \ '1: :_cargo_test_names' \ '(--doc --bin --example --test --bench)--lib[only test library]' \ '(--lib --bin --example --test --bench)--doc[only test documentation]' \ '(--lib --doc --example --test --bench)--bin=[binary name]' \ '(--lib --doc --bin --test --bench)--example=[example name]:_cargo_example_names' \ '(--lib --doc --bin --example --bench)--test=[test name]' \ '(--lib --doc --bin --example --test)--bench=[benchmark name]' \ '--ignore-rust-version[Ignore rust-version specification in packages]' \ '*: :_default' ;; tree) _arguments -s -S $common $features $triple $manifest \ '(-p --package)'{-p+,--package=}'[package to use as the root]:package:_cargo_package_names' \ '(-i --invert)'{-i+,--invert=}'[invert the tree for the given package]:package:_cargo_package_names' \ '--prefix=[line prefix]:prefix:(depth indent none)' \ '--no-dedupe[repeat shared dependencies]' \ '(-d --duplicates)'{-d,--duplicates}'[packages with multiple versions]' \ '--charset=[utf8 or ascii]:charset:(utf8 ascii)' \ '(-f --format)'{-f,--format=}'[format string]:format' \ '(-e --edges)'{-e,--edges=}'[edge kinds]:kind:(features normal build dev all no-dev no-build no-normal)' \ ;; uninstall) _arguments -s -S $common \ '(-p --package)'{-p+,--package=}'[specify package to uninstall]:package:_cargo_package_names' \ '--bin=[only uninstall the specified binary]:name' \ '--root=[directory to uninstall packages from]: :_files -/' \ '*:crate:_cargo_installed_crates -F line' ;; update) _arguments -s -S $common $manifest \ '--aggressive=[force dependency update]' \ '--recursive=[force dependency update]' \ "--dry-run[don't actually write the lockfile]" \ '(-p --package)'{-p+,--package=}'[specify package to update]:package:_cargo_package_names' \ '--precise=[update single dependency to precise release]:release' \ '*:package:_cargo_package_names' ;; version) _arguments -s -S $common ;; yank) _arguments -s -S $common $registry \ '--version=[specify yank version]:version' \ '--undo[undo a yank, putting a version back into the index]' \ '--index=[specify registry index to yank from]:registry index' \ '--token=[specify API token to use when authenticating]:token' \ '*: :_guard "^-*" "crate"' ;; *) # allow plugins to define their own functions if ! _call_function ret _cargo-${words[1]}; then # fallback on default completion for unknown commands _default && ret=0 fi (( ! ret )) ;; esac ;; esac } _cargo_unstable_flags() { local flags flags=( help ${${${(M)${(f)"$(_call_program flags cargo -Z help)"}:#*--*}/ #-- #/:}##*-Z } ) _describe -t flags 'unstable flag' flags } _cargo_installed_crates() { local expl _description crates expl 'crate' compadd "$@" "$expl[@]" - ${${${(f)"$(cargo install --list)"}:# *}%% *} } _cargo_cmds() { local -a commands # This uses Parameter Expansion Flags, which are a built-in Zsh feature. # See more: http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion-Flags # and http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion # # # How this work? # # First it splits the result of `cargo --list` at newline, then it removes the first line. # Then it removes indentation (4 whitespaces) before each items. (Note the x## pattern [1]). # Then it replaces those spaces between item and description with a `:` # # [1]: https://github.com/zsh-users/zsh-completions/blob/master/zsh-completions-howto.org#patterns commands=( ${${${(M)"${(f)$(_call_program commands cargo --list)}":# *}/ ##/}/ ##/:} ) _describe -t commands 'command' commands } _cargo_target_triple() { local -a result if (( $+commands[rustup] )); then result=( ${(f)"$(rustup target list --installed)"} ) else result=( ${(f)"$(rustc --print target-list)"} ) fi _describe 'target triple' result } #FIXME: Disabled until fixed #gets package names from the manifest file _cargo_package_names() { _message -e packages package } # Extracts the values of "name" from the array given in $1 and shows them as # command line options for completion _cargo_names_from_array() { local manifest=$(cargo locate-project --message-format plain) if [[ -z $manifest ]]; then return 0 fi local last_line local -a names; local in_block=false local block_name=$1 names=() while read -r line; do if [[ $last_line == "[[$block_name]]" ]]; then in_block=true else if [[ $last_line =~ '\s*\[\[.*' ]]; then in_block=false fi fi if [[ $in_block == true ]]; then if [[ $line =~ '\s*name\s*=' ]]; then regexp-replace line '^\s*name\s*=\s*|"' '' names+=( "$line" ) fi fi last_line=$line done < "$manifest" _describe "$block_name" names } #Gets the test names from the manifest file _cargo_test_names() { _cargo_names_from_array "test" } #Gets the bench names from the manifest file _cargo_benchmark_names() { _cargo_names_from_array "bench" } _cargo_example_names() { if [[ -d examples ]]; then local -a files=(${(@f)$(echo examples/*.rs(:t:r))}) _values 'example' "${files[@]}" fi } _cargo cargo-0.86.0/src/etc/cargo.bashcomp.sh000064400000000000000000000247061046102023000156070ustar 00000000000000# Required for bash versions < 4.1 # Default bash version is 3.2 on latest macOS. See #6874 shopt -s extglob command -v cargo >/dev/null 2>&1 && _cargo() { local cur prev words cword _get_comp_words_by_ref cur prev words cword COMPREPLY=() # Skip past - and + options to find the command. local nwords=${#words[@]} local cmd_i cmd dd_i for (( cmd_i=1; cmd_i<$nwords; cmd_i++ )); do if [[ ! "${words[$cmd_i]}" =~ ^[+-] ]]; then cmd="${words[$cmd_i]}" break fi done # Find the location of the -- separator. for (( dd_i=1; dd_i<$nwords-1; dd_i++ )); do if [[ "${words[$dd_i]}" = "--" ]]; then break fi done local vcs='git hg none pijul fossil' local color='auto always never' local msg_format='human json short' local opt_help='-h --help' local opt_verbose='-v --verbose' local opt_quiet='-q --quiet' local opt_color='--color' local opt_common="$opt_help $opt_verbose $opt_quiet $opt_color" local opt_pkg_spec='-p --package --all --exclude --workspace' local opt_pkg='-p --package' local opt_feat='-F --features --all-features --no-default-features' local opt_mani='--manifest-path' local opt_jobs='-j --jobs' local opt_parallel="$opt_jobs --keep-going" local opt_force='-f --force' local opt_sync='-s --sync' local opt_lock='--frozen --locked --offline' local opt_targets="--lib --bin --bins --example --examples --test --tests --bench --benches --all-targets" local opt___nocmd="$opt_common -V --version --list --explain" local opt__add="$opt_common -p --package --features --default-features --no-default-features $opt_mani --optional --no-optional --rename --dry-run --path --git --branch --tag --rev --registry --dev --build --target --ignore-rust-version" local opt__bench="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_jobs $opt_targets --message-format --target --no-run --no-fail-fast --target-dir --ignore-rust-version" local opt__build="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_parallel $opt_targets --message-format --target --release --profile --target-dir --ignore-rust-version" local opt__b="$opt__build" local opt__check="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_parallel $opt_targets --message-format --target --release --profile --target-dir --ignore-rust-version" local opt__c="$opt__check" local opt__clean="$opt_common $opt_pkg $opt_mani $opt_lock --target --release --doc --target-dir --profile" local opt__clippy="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_parallel $opt_targets --message-format --target --release --profile --target-dir --no-deps --fix" local opt__doc="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_parallel --message-format --bin --bins --lib --target --open --no-deps --release --document-private-items --target-dir --profile --ignore-rust-version" local opt__d="$opt__doc" local opt__fetch="$opt_common $opt_mani $opt_lock --target" local opt__fix="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_parallel $opt_targets $opt_lock --release --target --message-format --broken-code --edition --edition-idioms --allow-no-vcs --allow-dirty --allow-staged --profile --target-dir --ignore-rust-version" local opt__generate_lockfile="$opt_common $opt_mani $opt_lock" local opt__help="$opt_help" local opt__info="$opt_common $opt_lock --registry --index" local opt__init="$opt_common $opt_lock --bin --lib --name --vcs --edition --registry" local opt__install="$opt_common $opt_feat $opt_parallel $opt_lock $opt_force --bin --bins --branch --debug --example --examples --git --list --path --rev --root --tag --version --registry --target --profile --no-track --ignore-rust-version" local opt__locate_project="$opt_common $opt_mani $opt_lock --message-format --workspace" local opt__login="$opt_common $opt_lock --registry" local opt__metadata="$opt_common $opt_feat $opt_mani $opt_lock --format-version=1 --no-deps --filter-platform" local opt__new="$opt_common $opt_lock --vcs --bin --lib --name --edition --registry" local opt__owner="$opt_common $opt_lock -a --add -r --remove -l --list --index --token --registry" local opt__package="$opt_common $opt_mani $opt_feat $opt_lock $opt_parallel --allow-dirty -l --list --no-verify --no-metadata --index --registry --target --target-dir" local opt__pkgid="$opt_common $opt_mani $opt_lock $opt_pkg" local opt__publish="$opt_common $opt_mani $opt_feat $opt_lock $opt_parallel --allow-dirty --dry-run --token --no-verify --index --registry --target --target-dir" local opt__remove="$opt_common $opt_pkg $opt_lock $opt_mani --dry-run --dev --build --target" local opt__rm="$opt__remove" local opt__report="$opt_help $opt_verbose $opt_color future-incompat future-incompatibilities" local opt__report__future_incompat="$opt_help $opt_verbose $opt_color $opt_pkg --id" local opt__run="$opt_common $opt_pkg $opt_feat $opt_mani $opt_lock $opt_parallel --message-format --target --bin --example --release --target-dir --profile --ignore-rust-version" local opt__r="$opt__run" local opt__rustc="$opt_common $opt_pkg $opt_feat $opt_mani $opt_lock $opt_parallel $opt_targets -L --crate-type --extern --message-format --profile --target --release --target-dir --ignore-rust-version" local opt__rustdoc="$opt_common $opt_pkg $opt_feat $opt_mani $opt_lock $opt_parallel $opt_targets --message-format --target --release --open --target-dir --profile --ignore-rust-version" local opt__search="$opt_common $opt_lock --limit --index --registry" local opt__test="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_jobs $opt_targets --message-format --doc --target --no-run --release --no-fail-fast --target-dir --profile --ignore-rust-version" local opt__t="$opt__test" local opt__tree="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock --target -i --invert --prefix --no-dedupe --duplicates -d --charset -f --format -e --edges" local opt__uninstall="$opt_common $opt_lock $opt_pkg --bin --root" local opt__update="$opt_common $opt_mani $opt_lock $opt_pkg --aggressive --recursive --precise --dry-run" local opt__vendor="$opt_common $opt_mani $opt_lock $opt_sync --no-delete --respect-source-config --versioned-dirs" local opt__version="$opt_common $opt_lock" local opt__yank="$opt_common $opt_lock --version --undo --index --token --registry" local opt__libtest="--help --include-ignored --ignored --test --bench --list --logfile --nocapture --test-threads --skip -q --quiet --exact --color --format" if [[ $cword -gt $dd_i ]]; then # Completion after -- separator. if [[ "${cmd}" = @(test|bench) ]]; then COMPREPLY=( $( compgen -W "${opt__libtest}" -- "$cur" ) ) else # Fallback to filename completion, useful with `cargo run`. _filedir fi elif [[ $cword -le $cmd_i ]]; then # Completion before or at the command. if [[ "$cur" == -* ]]; then COMPREPLY=( $( compgen -W "${opt___nocmd}" -- "$cur" ) ) elif [[ "$cur" == +* ]]; then COMPREPLY=( $( compgen -W "$(_toolchains)" -- "$cur" ) ) else _ensure_cargo_commands_cache_filled COMPREPLY=( $( compgen -W "$__cargo_commands_cache" -- "$cur" ) ) fi else case "${prev}" in --vcs) COMPREPLY=( $( compgen -W "$vcs" -- "$cur" ) ) ;; --color) COMPREPLY=( $( compgen -W "$color" -- "$cur" ) ) ;; --message-format) COMPREPLY=( $( compgen -W "$msg_format" -- "$cur" ) ) ;; --manifest-path) _filedir toml ;; --bin) COMPREPLY=( $( compgen -W "$(_bin_names)" -- "$cur" ) ) ;; --test) COMPREPLY=( $( compgen -W "$(_test_names)" -- "$cur" ) ) ;; --bench) COMPREPLY=( $( compgen -W "$(_benchmark_names)" -- "$cur" ) ) ;; --example) COMPREPLY=( $( compgen -W "$(_get_examples)" -- "$cur" ) ) ;; --target) COMPREPLY=( $( compgen -W "$(_get_targets)" -- "$cur" ) ) ;; --target-dir|--path) _filedir -d ;; help) _ensure_cargo_commands_cache_filled COMPREPLY=( $( compgen -W "$__cargo_commands_cache" -- "$cur" ) ) ;; *) if [[ "$cmd" == "report" && "$prev" == future-incompat* ]]; then local opt_var=opt__${cmd//-/_}__${prev//-/_} else local opt_var=opt__${cmd//-/_} fi if [[ -z "${!opt_var-}" ]]; then # Fallback to filename completion. _filedir else COMPREPLY=( $( compgen -W "${!opt_var}" -- "$cur" ) ) fi ;; esac fi # compopt does not work in bash version 3 return 0 } && complete -F _cargo cargo __cargo_commands_cache= _ensure_cargo_commands_cache_filled(){ if [[ -z $__cargo_commands_cache ]]; then __cargo_commands_cache="$(cargo --list 2>/dev/null | awk 'NR>1 {print $1}')" fi } _locate_manifest(){ cargo locate-project --message-format plain 2>/dev/null } # Extracts the values of "name" from the array given in $1 and shows them as # command line options for completion _get_names_from_array() { local manifest=$(_locate_manifest) if [[ -z $manifest ]]; then return 0 fi local last_line local -a names local in_block=false local block_name=$1 while read line do if [[ $last_line == "[[$block_name]]" ]]; then in_block=true else if [[ $last_line =~ .*\[\[.* ]]; then in_block=false fi fi if [[ $in_block == true ]]; then if [[ $line =~ .*name.*\= ]]; then line=${line##*=} line=${line%%\"} line=${line##*\"} names+=("$line") fi fi last_line=$line done < "$manifest" echo "${names[@]}" } #Gets the bin names from the manifest file _bin_names() { _get_names_from_array "bin" } #Gets the test names from the manifest file _test_names() { _get_names_from_array "test" } #Gets the bench names from the manifest file _benchmark_names() { _get_names_from_array "bench" } _get_examples(){ local manifest=$(_locate_manifest) [ -z "$manifest" ] && return 0 local files=("${manifest%/*}"/examples/*.rs) local names=("${files[@]##*/}") local names=("${names[@]%.*}") # "*" means no examples found if [[ "${names[@]}" != "*" ]]; then echo "${names[@]}" fi } _get_targets(){ if command -v rustup >/dev/null 2>/dev/null; then rustup target list --installed else rustc --print target-list fi } _toolchains(){ local result=() local toolchains=$(rustup toolchain list) local channels="nightly|beta|stable|[0-9]\.[0-9]{1,2}\.[0-9]" local date="[0-9]{4}-[0-9]{2}-[0-9]{2}" while read line do # Strip " (default)" line=${line%% *} if [[ "$line" =~ ^($channels)(-($date))?(-.*) ]]; then if [[ -z ${BASH_REMATCH[3]} ]]; then result+=("+${BASH_REMATCH[1]}") else # channel-date result+=("+${BASH_REMATCH[1]}-${BASH_REMATCH[3]}") fi result+=("+$line") else result+=("+$line") fi done <<< "$toolchains" echo "${result[@]}" } # vim:ft=sh cargo-0.86.0/src/etc/man/cargo-add.1000064400000000000000000000266251046102023000150450ustar 00000000000000'\" t .TH "CARGO\-ADD" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-add \[em] Add dependencies to a Cargo.toml manifest file .SH "SYNOPSIS" \fBcargo add\fR [\fIoptions\fR] \fIcrate\fR\[u2026] .br \fBcargo add\fR [\fIoptions\fR] \fB\-\-path\fR \fIpath\fR .br \fBcargo add\fR [\fIoptions\fR] \fB\-\-git\fR \fIurl\fR [\fIcrate\fR\[u2026]] .SH "DESCRIPTION" This command can add or modify dependencies. .sp The source for the dependency can be specified with: .sp .RS 4 \h'-04'\(bu\h'+02'\fIcrate\fR\fB@\fR\fIversion\fR: Fetch from a registry with a version constraint of \[lq]\fIversion\fR\[rq] .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB\-\-path\fR \fIpath\fR: Fetch from the specified \fIpath\fR .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB\-\-git\fR \fIurl\fR: Pull from a git repo at \fIurl\fR .RE .sp If no source is specified, then a best effort will be made to select one, including: .sp .RS 4 \h'-04'\(bu\h'+02'Existing dependencies in other tables (like \fBdev\-dependencies\fR) .RE .sp .RS 4 \h'-04'\(bu\h'+02'Workspace members .RE .sp .RS 4 \h'-04'\(bu\h'+02'Latest release in the registry .RE .sp When you add a package that is already present, the existing entry will be updated with the flags specified. .sp Upon successful invocation, the enabled (\fB+\fR) and disabled (\fB\-\fR) \fIfeatures\fR of the specified dependency will be listed in the command\[cq]s output. .SH "OPTIONS" .SS "Source options" .sp \fB\-\-git\fR \fIurl\fR .RS 4 \fIGit URL to add the specified crate from\fR \&. .RE .sp \fB\-\-branch\fR \fIbranch\fR .RS 4 Branch to use when adding from git. .RE .sp \fB\-\-tag\fR \fItag\fR .RS 4 Tag to use when adding from git. .RE .sp \fB\-\-rev\fR \fIsha\fR .RS 4 Specific commit to use when adding from git. .RE .sp \fB\-\-path\fR \fIpath\fR .RS 4 \fIFilesystem path\fR to local crate to add. .RE .sp \fB\-\-base\fR \fIbase\fR .RS 4 The \fIpath base\fR to use when adding a local crate. .sp \fIUnstable (nightly\-only)\fR .RE .sp \fB\-\-registry\fR \fIregistry\fR .RS 4 Name of the registry to use. Registry names are defined in \fICargo config files\fR \&. If not specified, the default registry is used, which is defined by the \fBregistry.default\fR config key which defaults to \fBcrates\-io\fR\&. .RE .SS "Section options" .sp \fB\-\-dev\fR .RS 4 Add as a \fIdevelopment dependency\fR \&. .RE .sp \fB\-\-build\fR .RS 4 Add as a \fIbuild dependency\fR \&. .RE .sp \fB\-\-target\fR \fItarget\fR .RS 4 Add as a dependency to the \fIgiven target platform\fR \&. .sp To avoid unexpected shell expansions, you may use quotes around each target, e.g., \fB\-\-target 'cfg(unix)'\fR\&. .RE .SS "Dependency options" .sp \fB\-\-dry\-run\fR .RS 4 Don\[cq]t actually write the manifest .RE .sp \fB\-\-rename\fR \fIname\fR .RS 4 \fIRename\fR the dependency. .RE .sp \fB\-\-optional\fR .RS 4 Mark the dependency as \fIoptional\fR \&. .RE .sp \fB\-\-no\-optional\fR .RS 4 Mark the dependency as \fIrequired\fR \&. .RE .sp \fB\-\-public\fR .RS 4 Mark the dependency as public. .sp The dependency can be referenced in your library\[cq]s public API. .sp \fIUnstable (nightly\-only)\fR .RE .sp \fB\-\-no\-public\fR .RS 4 Mark the dependency as private. .sp While you can use the crate in your implementation, it cannot be referenced in your public API. .sp \fIUnstable (nightly\-only)\fR .RE .sp \fB\-\-no\-default\-features\fR .RS 4 Disable the \fIdefault features\fR \&. .RE .sp \fB\-\-default\-features\fR .RS 4 Re\-enable the \fIdefault features\fR \&. .RE .sp \fB\-F\fR \fIfeatures\fR, \fB\-\-features\fR \fIfeatures\fR .RS 4 Space or comma separated list of \fIfeatures to activate\fR \&. When adding multiple crates, the features for a specific crate may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-p\fR \fIspec\fR, \fB\-\-package\fR \fIspec\fR .RS 4 Add dependencies to only the specified package. .RE .sp \fB\-\-ignore\-rust\-version\fR .RS 4 Ignore \fBrust\-version\fR specification in packages. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Add \fBregex\fR as a dependency .sp .RS 4 .nf cargo add regex .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Add \fBtrybuild\fR as a dev\-dependency .sp .RS 4 .nf cargo add \-\-dev trybuild .fi .RE .RE .sp .RS 4 \h'-04' 3.\h'+01'Add an older version of \fBnom\fR as a dependency .sp .RS 4 .nf cargo add nom@5 .fi .RE .RE .sp .RS 4 \h'-04' 4.\h'+01'Add support for serializing data structures to json with \fBderive\fRs .sp .RS 4 .nf cargo add serde serde_json \-F serde/derive .fi .RE .RE .sp .RS 4 \h'-04' 5.\h'+01'Add \fBwindows\fR as a platform specific dependency on \fBcfg(windows)\fR .sp .RS 4 .nf cargo add windows \-\-target 'cfg(windows)' .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-remove\fR(1) cargo-0.86.0/src/etc/man/cargo-bench.1000064400000000000000000000512651046102023000153720ustar 00000000000000'\" t .TH "CARGO\-BENCH" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-bench \[em] Execute benchmarks of a package .SH "SYNOPSIS" \fBcargo bench\fR [\fIoptions\fR] [\fIbenchname\fR] [\fB\-\-\fR \fIbench\-options\fR] .SH "DESCRIPTION" Compile and execute benchmarks. .sp The benchmark filtering argument \fIbenchname\fR and all the arguments following the two dashes (\fB\-\-\fR) are passed to the benchmark binaries and thus to \fIlibtest\fR (rustc\[cq]s built in unit\-test and micro\-benchmarking framework). If you are passing arguments to both Cargo and the binary, the ones after \fB\-\-\fR go to the binary, the ones before go to Cargo. For details about libtest\[cq]s arguments see the output of \fBcargo bench \-\- \-\-help\fR and check out the rustc book\[cq]s chapter on how tests work at \&. .sp As an example, this will run only the benchmark named \fBfoo\fR (and skip other similarly named benchmarks like \fBfoobar\fR): .sp .RS 4 .nf cargo bench \-\- foo \-\-exact .fi .RE .sp Benchmarks are built with the \fB\-\-test\fR option to \fBrustc\fR which creates a special executable by linking your code with libtest. The executable automatically runs all functions annotated with the \fB#[bench]\fR attribute. Cargo passes the \fB\-\-bench\fR flag to the test harness to tell it to run only benchmarks, regardless of whether the harness is libtest or a custom harness. .sp The libtest harness may be disabled by setting \fBharness = false\fR in the target manifest settings, in which case your code will need to provide its own \fBmain\fR function to handle running benchmarks. .RS 3 .ll -5 .sp \fBNote\fR: The \fI\f(BI#[bench]\fI attribute\fR is currently unstable and only available on the \fInightly channel\fR \&. There are some packages available on \fIcrates.io\fR that may help with running benchmarks on the stable channel, such as \fICriterion\fR \&. .br .RE .ll .sp By default, \fBcargo bench\fR uses the \fI\f(BIbench\fI profile\fR , which enables optimizations and disables debugging information. If you need to debug a benchmark, you can use the \fB\-\-profile=dev\fR command\-line option to switch to the dev profile. You can then run the debug\-enabled benchmark within a debugger. .SS "Working directory of benchmarks" The working directory of every benchmark is set to the root directory of the package the benchmark belongs to. Setting the working directory of benchmarks to the package\[cq]s root directory makes it possible for benchmarks to reliably access the package\[cq]s files using relative paths, regardless from where \fBcargo bench\fR was executed from. .SH "OPTIONS" .SS "Benchmark Options" .sp \fB\-\-no\-run\fR .RS 4 Compile, but don\[cq]t run benchmarks. .RE .sp \fB\-\-no\-fail\-fast\fR .RS 4 Run all benchmarks regardless of failure. Without this flag, Cargo will exit after the first executable fails. The Rust test harness will run all benchmarks within the executable to completion, this flag only applies to the executable as a whole. .RE .SS "Package Selection" By default, when no package selection options are given, the packages selected depend on the selected manifest file (based on the current working directory if \fB\-\-manifest\-path\fR is not given). If the manifest is the root of a workspace then the workspaces default members are selected, otherwise only the package defined by the manifest will be selected. .sp The default members of a workspace can be set explicitly with the \fBworkspace.default\-members\fR key in the root manifest. If this is not set, a virtual workspace will include all workspace members (equivalent to passing \fB\-\-workspace\fR), and a non\-virtual workspace will include only the root crate itself. .sp \fB\-p\fR \fIspec\fR\[u2026], \fB\-\-package\fR \fIspec\fR\[u2026] .RS 4 Benchmark only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .sp \fB\-\-workspace\fR .RS 4 Benchmark all members in the workspace. .RE .sp \fB\-\-all\fR .RS 4 Deprecated alias for \fB\-\-workspace\fR\&. .RE .sp \fB\-\-exclude\fR \fISPEC\fR\[u2026] .RS 4 Exclude the specified packages. Must be used in conjunction with the \fB\-\-workspace\fR flag. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .SS "Target Selection" When no target selection options are given, \fBcargo bench\fR will build the following targets of the selected packages: .sp .RS 4 \h'-04'\(bu\h'+02'lib \[em] used to link with binaries and benchmarks .RE .sp .RS 4 \h'-04'\(bu\h'+02'bins (only if benchmark targets are built and required features are available) .RE .sp .RS 4 \h'-04'\(bu\h'+02'lib as a benchmark .RE .sp .RS 4 \h'-04'\(bu\h'+02'bins as benchmarks .RE .sp .RS 4 \h'-04'\(bu\h'+02'benchmark targets .RE .sp The default behavior can be changed by setting the \fBbench\fR flag for the target in the manifest settings. Setting examples to \fBbench = true\fR will build and run the example as a benchmark, replacing the example\[cq]s \fBmain\fR function with the libtest harness. .sp Setting targets to \fBbench = false\fR will stop them from being benchmarked by default. Target selection options that take a target by name (such as \fB\-\-example foo\fR) ignore the \fBbench\fR flag and will always benchmark the given target. .sp See \fIConfiguring a target\fR for more information on per\-target settings. .sp Binary targets are automatically built if there is an integration test or benchmark being selected to benchmark. This allows an integration test to execute the binary to exercise and test its behavior. The \fBCARGO_BIN_EXE_\fR \fIenvironment variable\fR is set when the integration test is built so that it can use the \fI\f(BIenv\fI macro\fR to locate the executable. .sp Passing target selection flags will benchmark only the specified targets. .sp Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each glob pattern. .sp \fB\-\-lib\fR .RS 4 Benchmark the package\[cq]s library. .RE .sp \fB\-\-bin\fR \fIname\fR\[u2026] .RS 4 Benchmark the specified binary. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-bins\fR .RS 4 Benchmark all binary targets. .RE .sp \fB\-\-example\fR \fIname\fR\[u2026] .RS 4 Benchmark the specified example. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-examples\fR .RS 4 Benchmark all example targets. .RE .sp \fB\-\-test\fR \fIname\fR\[u2026] .RS 4 Benchmark the specified integration test. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-tests\fR .RS 4 Benchmark all targets that have the \fBtest = true\fR manifest flag set. By default this includes the library and binaries built as unittests, and integration tests. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a unittest, and once as a dependency for binaries, integration tests, etc.). Targets may be enabled or disabled by setting the \fBtest\fR flag in the manifest settings for the target. .RE .sp \fB\-\-bench\fR \fIname\fR\[u2026] .RS 4 Benchmark the specified benchmark. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-benches\fR .RS 4 Benchmark all targets that have the \fBbench = true\fR manifest flag set. By default this includes the library and binaries built as benchmarks, and bench targets. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a benchmark, and once as a dependency for binaries, benchmarks, etc.). Targets may be enabled or disabled by setting the \fBbench\fR flag in the manifest settings for the target. .RE .sp \fB\-\-all\-targets\fR .RS 4 Benchmark all targets. This is equivalent to specifying \fB\-\-lib \-\-bins \-\-tests \-\-benches \-\-examples\fR\&. .RE .SS "Feature Selection" The feature flags allow you to control which features are enabled. When no feature options are given, the \fBdefault\fR feature is activated for every selected package. .sp See \fIthe features documentation\fR for more details. .sp \fB\-F\fR \fIfeatures\fR, \fB\-\-features\fR \fIfeatures\fR .RS 4 Space or comma separated list of features to activate. Features of workspace members may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE .sp \fB\-\-all\-features\fR .RS 4 Activate all available features of all selected packages. .RE .sp \fB\-\-no\-default\-features\fR .RS 4 Do not activate the \fBdefault\fR feature of the selected packages. .RE .SS "Compilation Options" .sp \fB\-\-target\fR \fItriple\fR .RS 4 Benchmark for the given architecture. The default is the host architecture. The general format of the triple is \fB\-\-\-\fR\&. Run \fBrustc \-\-print target\-list\fR for a list of supported targets. This flag may be specified multiple times. .sp This may also be specified with the \fBbuild.target\fR \fIconfig value\fR \&. .sp Note that specifying this flag makes Cargo run in a different mode where the target artifacts are placed in a separate directory. See the \fIbuild cache\fR documentation for more details. .RE .sp \fB\-\-profile\fR \fIname\fR .RS 4 Benchmark with the given profile. See \fIthe reference\fR for more details on profiles. .RE .sp \fB\-\-timings=\fR\fIfmts\fR .RS 4 Output information how long each compilation takes, and track concurrency information over time. Accepts an optional comma\-separated list of output formats; \fB\-\-timings\fR without an argument will default to \fB\-\-timings=html\fR\&. Specifying an output format (rather than the default) is unstable and requires \fB\-Zunstable\-options\fR\&. Valid output formats: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhtml\fR (unstable, requires \fB\-Zunstable\-options\fR): Write a human\-readable file \fBcargo\-timing.html\fR to the \fBtarget/cargo\-timings\fR directory with a report of the compilation. Also write a report to the same directory with a timestamp in the filename if you want to look at older runs. HTML output is suitable for human consumption only, and does not provide machine\-readable timing data. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR (unstable, requires \fB\-Zunstable\-options\fR): Emit machine\-readable JSON information about timing information. .RE .RE .SS "Output Options" .sp \fB\-\-target\-dir\fR \fIdirectory\fR .RS 4 Directory for all generated artifacts and intermediate files. May also be specified with the \fBCARGO_TARGET_DIR\fR environment variable, or the \fBbuild.target\-dir\fR \fIconfig value\fR \&. Defaults to \fBtarget\fR in the root of the workspace. .RE .SS "Display Options" By default the Rust test harness hides output from benchmark execution to keep results readable. Benchmark output can be recovered (e.g., for debugging) by passing \fB\-\-nocapture\fR to the benchmark binaries: .sp .RS 4 .nf cargo bench \-\- \-\-nocapture .fi .RE .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .sp \fB\-\-message\-format\fR \fIfmt\fR .RS 4 The output format for diagnostic messages. Can be specified multiple times and consists of comma\-separated values. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhuman\fR (default): Display in a human\-readable text format. Conflicts with \fBshort\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBshort\fR: Emit shorter, human\-readable text messages. Conflicts with \fBhuman\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR: Emit JSON messages to stdout. See \fIthe reference\fR for more details. Conflicts with \fBhuman\fR and \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-short\fR: Ensure the \fBrendered\fR field of JSON messages contains the \[lq]short\[rq] rendering from rustc. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-rendered\-ansi\fR: Ensure the \fBrendered\fR field of JSON messages contains embedded ANSI color codes for respecting rustc\[cq]s default color scheme. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-render\-diagnostics\fR: Instruct Cargo to not include rustc diagnostics in JSON messages printed, but instead Cargo itself should render the JSON diagnostics coming from rustc. Cargo\[cq]s own JSON diagnostics and others coming from rustc are still emitted. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-ignore\-rust\-version\fR .RS 4 Ignore \fBrust\-version\fR specification in packages. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SS "Miscellaneous Options" The \fB\-\-jobs\fR argument affects the building of the benchmark executable but does not affect how many threads are used when running the benchmarks. The Rust test harness runs benchmarks serially in a single thread. .sp \fB\-j\fR \fIN\fR, \fB\-\-jobs\fR \fIN\fR .RS 4 Number of parallel jobs to run. May also be specified with the \fBbuild.jobs\fR \fIconfig value\fR \&. 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 \fBdefault\fR is provided, it sets the value back to defaults. Should not be 0. .RE .sp While \fBcargo bench\fR involves compilation, it does not provide a \fB\-\-keep\-going\fR flag. Use \fB\-\-no\-fail\-fast\fR to run as many benchmarks as possible without stopping at the first failure. To \[lq]compile\[rq] as many benchmarks as possible, use \fB\-\-benches\fR to build benchmark binaries separately. For example: .sp .RS 4 .nf cargo build \-\-benches \-\-release \-\-keep\-going cargo bench \-\-no\-fail\-fast .fi .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Build and execute all the benchmarks of the current package: .sp .RS 4 .nf cargo bench .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Run only a specific benchmark within a specific benchmark target: .sp .RS 4 .nf cargo bench \-\-bench bench_name \-\- modname::some_benchmark .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-test\fR(1) cargo-0.86.0/src/etc/man/cargo-build.1000064400000000000000000000425401046102023000154060ustar 00000000000000'\" t .TH "CARGO\-BUILD" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-build \[em] Compile the current package .SH "SYNOPSIS" \fBcargo build\fR [\fIoptions\fR] .SH "DESCRIPTION" Compile local packages and all of their dependencies. .SH "OPTIONS" .SS "Package Selection" By default, when no package selection options are given, the packages selected depend on the selected manifest file (based on the current working directory if \fB\-\-manifest\-path\fR is not given). If the manifest is the root of a workspace then the workspaces default members are selected, otherwise only the package defined by the manifest will be selected. .sp The default members of a workspace can be set explicitly with the \fBworkspace.default\-members\fR key in the root manifest. If this is not set, a virtual workspace will include all workspace members (equivalent to passing \fB\-\-workspace\fR), and a non\-virtual workspace will include only the root crate itself. .sp \fB\-p\fR \fIspec\fR\[u2026], \fB\-\-package\fR \fIspec\fR\[u2026] .RS 4 Build only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .sp \fB\-\-workspace\fR .RS 4 Build all members in the workspace. .RE .sp \fB\-\-all\fR .RS 4 Deprecated alias for \fB\-\-workspace\fR\&. .RE .sp \fB\-\-exclude\fR \fISPEC\fR\[u2026] .RS 4 Exclude the specified packages. Must be used in conjunction with the \fB\-\-workspace\fR flag. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .SS "Target Selection" When no target selection options are given, \fBcargo build\fR will build all binary and library targets of the selected packages. Binaries are skipped if they have \fBrequired\-features\fR that are missing. .sp Binary targets are automatically built if there is an integration test or benchmark being selected to build. This allows an integration test to execute the binary to exercise and test its behavior. The \fBCARGO_BIN_EXE_\fR \fIenvironment variable\fR is set when the integration test is built so that it can use the \fI\f(BIenv\fI macro\fR to locate the executable. .sp Passing target selection flags will build only the specified targets. .sp Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each glob pattern. .sp \fB\-\-lib\fR .RS 4 Build the package\[cq]s library. .RE .sp \fB\-\-bin\fR \fIname\fR\[u2026] .RS 4 Build the specified binary. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-bins\fR .RS 4 Build all binary targets. .RE .sp \fB\-\-example\fR \fIname\fR\[u2026] .RS 4 Build the specified example. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-examples\fR .RS 4 Build all example targets. .RE .sp \fB\-\-test\fR \fIname\fR\[u2026] .RS 4 Build the specified integration test. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-tests\fR .RS 4 Build all targets that have the \fBtest = true\fR manifest flag set. By default this includes the library and binaries built as unittests, and integration tests. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a unittest, and once as a dependency for binaries, integration tests, etc.). Targets may be enabled or disabled by setting the \fBtest\fR flag in the manifest settings for the target. .RE .sp \fB\-\-bench\fR \fIname\fR\[u2026] .RS 4 Build the specified benchmark. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-benches\fR .RS 4 Build all targets that have the \fBbench = true\fR manifest flag set. By default this includes the library and binaries built as benchmarks, and bench targets. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a benchmark, and once as a dependency for binaries, benchmarks, etc.). Targets may be enabled or disabled by setting the \fBbench\fR flag in the manifest settings for the target. .RE .sp \fB\-\-all\-targets\fR .RS 4 Build all targets. This is equivalent to specifying \fB\-\-lib \-\-bins \-\-tests \-\-benches \-\-examples\fR\&. .RE .SS "Feature Selection" The feature flags allow you to control which features are enabled. When no feature options are given, the \fBdefault\fR feature is activated for every selected package. .sp See \fIthe features documentation\fR for more details. .sp \fB\-F\fR \fIfeatures\fR, \fB\-\-features\fR \fIfeatures\fR .RS 4 Space or comma separated list of features to activate. Features of workspace members may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE .sp \fB\-\-all\-features\fR .RS 4 Activate all available features of all selected packages. .RE .sp \fB\-\-no\-default\-features\fR .RS 4 Do not activate the \fBdefault\fR feature of the selected packages. .RE .SS "Compilation Options" .sp \fB\-\-target\fR \fItriple\fR .RS 4 Build for the given architecture. The default is the host architecture. The general format of the triple is \fB\-\-\-\fR\&. Run \fBrustc \-\-print target\-list\fR for a list of supported targets. This flag may be specified multiple times. .sp This may also be specified with the \fBbuild.target\fR \fIconfig value\fR \&. .sp Note that specifying this flag makes Cargo run in a different mode where the target artifacts are placed in a separate directory. See the \fIbuild cache\fR documentation for more details. .RE .sp \fB\-r\fR, \fB\-\-release\fR .RS 4 Build optimized artifacts with the \fBrelease\fR profile. See also the \fB\-\-profile\fR option for choosing a specific profile by name. .RE .sp \fB\-\-profile\fR \fIname\fR .RS 4 Build with the given profile. See \fIthe reference\fR for more details on profiles. .RE .sp \fB\-\-timings=\fR\fIfmts\fR .RS 4 Output information how long each compilation takes, and track concurrency information over time. Accepts an optional comma\-separated list of output formats; \fB\-\-timings\fR without an argument will default to \fB\-\-timings=html\fR\&. Specifying an output format (rather than the default) is unstable and requires \fB\-Zunstable\-options\fR\&. Valid output formats: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhtml\fR (unstable, requires \fB\-Zunstable\-options\fR): Write a human\-readable file \fBcargo\-timing.html\fR to the \fBtarget/cargo\-timings\fR directory with a report of the compilation. Also write a report to the same directory with a timestamp in the filename if you want to look at older runs. HTML output is suitable for human consumption only, and does not provide machine\-readable timing data. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR (unstable, requires \fB\-Zunstable\-options\fR): Emit machine\-readable JSON information about timing information. .RE .RE .SS "Output Options" .sp \fB\-\-target\-dir\fR \fIdirectory\fR .RS 4 Directory for all generated artifacts and intermediate files. May also be specified with the \fBCARGO_TARGET_DIR\fR environment variable, or the \fBbuild.target\-dir\fR \fIconfig value\fR \&. Defaults to \fBtarget\fR in the root of the workspace. .RE .sp \fB\-\-artifact\-dir\fR \fIdirectory\fR .RS 4 Copy final artifacts to this directory. .sp This option is unstable and available only on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable. See for more information. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .sp \fB\-\-message\-format\fR \fIfmt\fR .RS 4 The output format for diagnostic messages. Can be specified multiple times and consists of comma\-separated values. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhuman\fR (default): Display in a human\-readable text format. Conflicts with \fBshort\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBshort\fR: Emit shorter, human\-readable text messages. Conflicts with \fBhuman\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR: Emit JSON messages to stdout. See \fIthe reference\fR for more details. Conflicts with \fBhuman\fR and \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-short\fR: Ensure the \fBrendered\fR field of JSON messages contains the \[lq]short\[rq] rendering from rustc. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-rendered\-ansi\fR: Ensure the \fBrendered\fR field of JSON messages contains embedded ANSI color codes for respecting rustc\[cq]s default color scheme. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-render\-diagnostics\fR: Instruct Cargo to not include rustc diagnostics in JSON messages printed, but instead Cargo itself should render the JSON diagnostics coming from rustc. Cargo\[cq]s own JSON diagnostics and others coming from rustc are still emitted. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .RE .sp \fB\-\-build\-plan\fR .RS 4 Outputs a series of JSON messages to stdout that indicate the commands to run the build. .sp This option is unstable and available only on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable. See for more information. .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-ignore\-rust\-version\fR .RS 4 Ignore \fBrust\-version\fR specification in packages. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SS "Miscellaneous Options" .sp \fB\-j\fR \fIN\fR, \fB\-\-jobs\fR \fIN\fR .RS 4 Number of parallel jobs to run. May also be specified with the \fBbuild.jobs\fR \fIconfig value\fR \&. 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 \fBdefault\fR is provided, it sets the value back to defaults. Should not be 0. .RE .sp \fB\-\-keep\-going\fR .RS 4 Build as many crates in the dependency graph as possible, rather than aborting the build on the first one that fails to build. .sp For example if the current package depends on dependencies \fBfails\fR and \fBworks\fR, one of which fails to build, \fBcargo build \-j1\fR may or may not build the one that succeeds (depending on which one of the two builds Cargo picked to run first), whereas \fBcargo build \-j1 \-\-keep\-going\fR would definitely run both builds, even if the one run first fails. .RE .sp \fB\-\-future\-incompat\-report\fR .RS 4 Displays a future\-incompat report for any future\-incompatible warnings produced during execution of this command .sp See \fBcargo\-report\fR(1) .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Build the local package and all of its dependencies: .sp .RS 4 .nf cargo build .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Build with optimizations: .sp .RS 4 .nf cargo build \-\-release .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-rustc\fR(1) cargo-0.86.0/src/etc/man/cargo-check.1000064400000000000000000000413461046102023000153670ustar 00000000000000'\" t .TH "CARGO\-CHECK" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-check \[em] Check the current package .SH "SYNOPSIS" \fBcargo check\fR [\fIoptions\fR] .SH "DESCRIPTION" Check a local package and all of its dependencies for errors. This will essentially compile the packages without performing the final step of code generation, which is faster than running \fBcargo build\fR\&. The compiler will save metadata files to disk so that future runs will reuse them if the source has not been modified. Some diagnostics and errors are only emitted during code generation, so they inherently won\[cq]t be reported with \fBcargo check\fR\&. .SH "OPTIONS" .SS "Package Selection" By default, when no package selection options are given, the packages selected depend on the selected manifest file (based on the current working directory if \fB\-\-manifest\-path\fR is not given). If the manifest is the root of a workspace then the workspaces default members are selected, otherwise only the package defined by the manifest will be selected. .sp The default members of a workspace can be set explicitly with the \fBworkspace.default\-members\fR key in the root manifest. If this is not set, a virtual workspace will include all workspace members (equivalent to passing \fB\-\-workspace\fR), and a non\-virtual workspace will include only the root crate itself. .sp \fB\-p\fR \fIspec\fR\[u2026], \fB\-\-package\fR \fIspec\fR\[u2026] .RS 4 Check only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .sp \fB\-\-workspace\fR .RS 4 Check all members in the workspace. .RE .sp \fB\-\-all\fR .RS 4 Deprecated alias for \fB\-\-workspace\fR\&. .RE .sp \fB\-\-exclude\fR \fISPEC\fR\[u2026] .RS 4 Exclude the specified packages. Must be used in conjunction with the \fB\-\-workspace\fR flag. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .SS "Target Selection" When no target selection options are given, \fBcargo check\fR will check all binary and library targets of the selected packages. Binaries are skipped if they have \fBrequired\-features\fR that are missing. .sp Passing target selection flags will check only the specified targets. .sp Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each glob pattern. .sp \fB\-\-lib\fR .RS 4 Check the package\[cq]s library. .RE .sp \fB\-\-bin\fR \fIname\fR\[u2026] .RS 4 Check the specified binary. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-bins\fR .RS 4 Check all binary targets. .RE .sp \fB\-\-example\fR \fIname\fR\[u2026] .RS 4 Check the specified example. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-examples\fR .RS 4 Check all example targets. .RE .sp \fB\-\-test\fR \fIname\fR\[u2026] .RS 4 Check the specified integration test. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-tests\fR .RS 4 Check all targets that have the \fBtest = true\fR manifest flag set. By default this includes the library and binaries built as unittests, and integration tests. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a unittest, and once as a dependency for binaries, integration tests, etc.). Targets may be enabled or disabled by setting the \fBtest\fR flag in the manifest settings for the target. .RE .sp \fB\-\-bench\fR \fIname\fR\[u2026] .RS 4 Check the specified benchmark. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-benches\fR .RS 4 Check all targets that have the \fBbench = true\fR manifest flag set. By default this includes the library and binaries built as benchmarks, and bench targets. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a benchmark, and once as a dependency for binaries, benchmarks, etc.). Targets may be enabled or disabled by setting the \fBbench\fR flag in the manifest settings for the target. .RE .sp \fB\-\-all\-targets\fR .RS 4 Check all targets. This is equivalent to specifying \fB\-\-lib \-\-bins \-\-tests \-\-benches \-\-examples\fR\&. .RE .SS "Feature Selection" The feature flags allow you to control which features are enabled. When no feature options are given, the \fBdefault\fR feature is activated for every selected package. .sp See \fIthe features documentation\fR for more details. .sp \fB\-F\fR \fIfeatures\fR, \fB\-\-features\fR \fIfeatures\fR .RS 4 Space or comma separated list of features to activate. Features of workspace members may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE .sp \fB\-\-all\-features\fR .RS 4 Activate all available features of all selected packages. .RE .sp \fB\-\-no\-default\-features\fR .RS 4 Do not activate the \fBdefault\fR feature of the selected packages. .RE .SS "Compilation Options" .sp \fB\-\-target\fR \fItriple\fR .RS 4 Check for the given architecture. The default is the host architecture. The general format of the triple is \fB\-\-\-\fR\&. Run \fBrustc \-\-print target\-list\fR for a list of supported targets. This flag may be specified multiple times. .sp This may also be specified with the \fBbuild.target\fR \fIconfig value\fR \&. .sp Note that specifying this flag makes Cargo run in a different mode where the target artifacts are placed in a separate directory. See the \fIbuild cache\fR documentation for more details. .RE .sp \fB\-r\fR, \fB\-\-release\fR .RS 4 Check optimized artifacts with the \fBrelease\fR profile. See also the \fB\-\-profile\fR option for choosing a specific profile by name. .RE .sp \fB\-\-profile\fR \fIname\fR .RS 4 Check with the given profile. .sp As a special case, specifying the \fBtest\fR profile will also enable checking in test mode which will enable checking tests and enable the \fBtest\fR cfg option. See \fIrustc tests\fR for more detail. .sp See \fIthe reference\fR for more details on profiles. .RE .sp \fB\-\-timings=\fR\fIfmts\fR .RS 4 Output information how long each compilation takes, and track concurrency information over time. Accepts an optional comma\-separated list of output formats; \fB\-\-timings\fR without an argument will default to \fB\-\-timings=html\fR\&. Specifying an output format (rather than the default) is unstable and requires \fB\-Zunstable\-options\fR\&. Valid output formats: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhtml\fR (unstable, requires \fB\-Zunstable\-options\fR): Write a human\-readable file \fBcargo\-timing.html\fR to the \fBtarget/cargo\-timings\fR directory with a report of the compilation. Also write a report to the same directory with a timestamp in the filename if you want to look at older runs. HTML output is suitable for human consumption only, and does not provide machine\-readable timing data. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR (unstable, requires \fB\-Zunstable\-options\fR): Emit machine\-readable JSON information about timing information. .RE .RE .SS "Output Options" .sp \fB\-\-target\-dir\fR \fIdirectory\fR .RS 4 Directory for all generated artifacts and intermediate files. May also be specified with the \fBCARGO_TARGET_DIR\fR environment variable, or the \fBbuild.target\-dir\fR \fIconfig value\fR \&. Defaults to \fBtarget\fR in the root of the workspace. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .sp \fB\-\-message\-format\fR \fIfmt\fR .RS 4 The output format for diagnostic messages. Can be specified multiple times and consists of comma\-separated values. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhuman\fR (default): Display in a human\-readable text format. Conflicts with \fBshort\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBshort\fR: Emit shorter, human\-readable text messages. Conflicts with \fBhuman\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR: Emit JSON messages to stdout. See \fIthe reference\fR for more details. Conflicts with \fBhuman\fR and \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-short\fR: Ensure the \fBrendered\fR field of JSON messages contains the \[lq]short\[rq] rendering from rustc. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-rendered\-ansi\fR: Ensure the \fBrendered\fR field of JSON messages contains embedded ANSI color codes for respecting rustc\[cq]s default color scheme. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-render\-diagnostics\fR: Instruct Cargo to not include rustc diagnostics in JSON messages printed, but instead Cargo itself should render the JSON diagnostics coming from rustc. Cargo\[cq]s own JSON diagnostics and others coming from rustc are still emitted. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-ignore\-rust\-version\fR .RS 4 Ignore \fBrust\-version\fR specification in packages. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SS "Miscellaneous Options" .sp \fB\-j\fR \fIN\fR, \fB\-\-jobs\fR \fIN\fR .RS 4 Number of parallel jobs to run. May also be specified with the \fBbuild.jobs\fR \fIconfig value\fR \&. 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 \fBdefault\fR is provided, it sets the value back to defaults. Should not be 0. .RE .sp \fB\-\-keep\-going\fR .RS 4 Build as many crates in the dependency graph as possible, rather than aborting the build on the first one that fails to build. .sp For example if the current package depends on dependencies \fBfails\fR and \fBworks\fR, one of which fails to build, \fBcargo check \-j1\fR may or may not build the one that succeeds (depending on which one of the two builds Cargo picked to run first), whereas \fBcargo check \-j1 \-\-keep\-going\fR would definitely run both builds, even if the one run first fails. .RE .sp \fB\-\-future\-incompat\-report\fR .RS 4 Displays a future\-incompat report for any future\-incompatible warnings produced during execution of this command .sp See \fBcargo\-report\fR(1) .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Check the local package for errors: .sp .RS 4 .nf cargo check .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Check all targets, including unit tests: .sp .RS 4 .nf cargo check \-\-all\-targets \-\-profile=test .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-build\fR(1) cargo-0.86.0/src/etc/man/cargo-clean.1000064400000000000000000000175001046102023000153670ustar 00000000000000'\" t .TH "CARGO\-CLEAN" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-clean \[em] Remove generated artifacts .SH "SYNOPSIS" \fBcargo clean\fR [\fIoptions\fR] .SH "DESCRIPTION" Remove artifacts from the target directory that Cargo has generated in the past. .sp With no options, \fBcargo clean\fR will delete the entire target directory. .SH "OPTIONS" .SS "Package Selection" When no packages are selected, all packages and all dependencies in the workspace are cleaned. .sp \fB\-p\fR \fIspec\fR\[u2026], \fB\-\-package\fR \fIspec\fR\[u2026] .RS 4 Clean only the specified packages. This flag may be specified multiple times. See \fBcargo\-pkgid\fR(1) for the SPEC format. .RE .SS "Clean Options" .sp \fB\-\-dry\-run\fR .RS 4 Displays a summary of what would be deleted without deleting anything. Use with \fB\-\-verbose\fR to display the actual files that would be deleted. .RE .sp \fB\-\-doc\fR .RS 4 This option will cause \fBcargo clean\fR to remove only the \fBdoc\fR directory in the target directory. .RE .sp \fB\-\-release\fR .RS 4 Remove all artifacts in the \fBrelease\fR directory. .RE .sp \fB\-\-profile\fR \fIname\fR .RS 4 Remove all artifacts in the directory with the given profile name. .RE .sp \fB\-\-target\-dir\fR \fIdirectory\fR .RS 4 Directory for all generated artifacts and intermediate files. May also be specified with the \fBCARGO_TARGET_DIR\fR environment variable, or the \fBbuild.target\-dir\fR \fIconfig value\fR \&. Defaults to \fBtarget\fR in the root of the workspace. .RE .sp \fB\-\-target\fR \fItriple\fR .RS 4 Clean for the given architecture. The default is the host architecture. The general format of the triple is \fB\-\-\-\fR\&. Run \fBrustc \-\-print target\-list\fR for a list of supported targets. This flag may be specified multiple times. .sp This may also be specified with the \fBbuild.target\fR \fIconfig value\fR \&. .sp Note that specifying this flag makes Cargo run in a different mode where the target artifacts are placed in a separate directory. See the \fIbuild cache\fR documentation for more details. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Remove the entire target directory: .sp .RS 4 .nf cargo clean .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Remove only the release artifacts: .sp .RS 4 .nf cargo clean \-\-release .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-build\fR(1) cargo-0.86.0/src/etc/man/cargo-doc.1000064400000000000000000000357371046102023000150660ustar 00000000000000'\" t .TH "CARGO\-DOC" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-doc \[em] Build a package\[cq]s documentation .SH "SYNOPSIS" \fBcargo doc\fR [\fIoptions\fR] .SH "DESCRIPTION" Build the documentation for the local package and all dependencies. The output is placed in \fBtarget/doc\fR in rustdoc\[cq]s usual format. .SH "OPTIONS" .SS "Documentation Options" .sp \fB\-\-open\fR .RS 4 Open the docs in a browser after building them. This will use your default browser unless you define another one in the \fBBROWSER\fR environment variable or use the \fI\f(BIdoc.browser\fI\fR configuration option. .RE .sp \fB\-\-no\-deps\fR .RS 4 Do not build documentation for dependencies. .RE .sp \fB\-\-document\-private\-items\fR .RS 4 Include non\-public items in the documentation. This will be enabled by default if documenting a binary target. .RE .SS "Package Selection" By default, when no package selection options are given, the packages selected depend on the selected manifest file (based on the current working directory if \fB\-\-manifest\-path\fR is not given). If the manifest is the root of a workspace then the workspaces default members are selected, otherwise only the package defined by the manifest will be selected. .sp The default members of a workspace can be set explicitly with the \fBworkspace.default\-members\fR key in the root manifest. If this is not set, a virtual workspace will include all workspace members (equivalent to passing \fB\-\-workspace\fR), and a non\-virtual workspace will include only the root crate itself. .sp \fB\-p\fR \fIspec\fR\[u2026], \fB\-\-package\fR \fIspec\fR\[u2026] .RS 4 Document only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .sp \fB\-\-workspace\fR .RS 4 Document all members in the workspace. .RE .sp \fB\-\-all\fR .RS 4 Deprecated alias for \fB\-\-workspace\fR\&. .RE .sp \fB\-\-exclude\fR \fISPEC\fR\[u2026] .RS 4 Exclude the specified packages. Must be used in conjunction with the \fB\-\-workspace\fR flag. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .SS "Target Selection" When no target selection options are given, \fBcargo doc\fR will document all binary and library targets of the selected package. The binary will be skipped if its name is the same as the lib target. Binaries are skipped if they have \fBrequired\-features\fR that are missing. .sp The default behavior can be changed by setting \fBdoc = false\fR for the target in the manifest settings. Using target selection options will ignore the \fBdoc\fR flag and will always document the given target. .sp \fB\-\-lib\fR .RS 4 Document the package\[cq]s library. .RE .sp \fB\-\-bin\fR \fIname\fR\[u2026] .RS 4 Document the specified binary. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-bins\fR .RS 4 Document all binary targets. .RE .sp \fB\-\-example\fR \fIname\fR\[u2026] .RS 4 Document the specified example. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-examples\fR .RS 4 Document all example targets. .RE .SS "Feature Selection" The feature flags allow you to control which features are enabled. When no feature options are given, the \fBdefault\fR feature is activated for every selected package. .sp See \fIthe features documentation\fR for more details. .sp \fB\-F\fR \fIfeatures\fR, \fB\-\-features\fR \fIfeatures\fR .RS 4 Space or comma separated list of features to activate. Features of workspace members may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE .sp \fB\-\-all\-features\fR .RS 4 Activate all available features of all selected packages. .RE .sp \fB\-\-no\-default\-features\fR .RS 4 Do not activate the \fBdefault\fR feature of the selected packages. .RE .SS "Compilation Options" .sp \fB\-\-target\fR \fItriple\fR .RS 4 Document for the given architecture. The default is the host architecture. The general format of the triple is \fB\-\-\-\fR\&. Run \fBrustc \-\-print target\-list\fR for a list of supported targets. This flag may be specified multiple times. .sp This may also be specified with the \fBbuild.target\fR \fIconfig value\fR \&. .sp Note that specifying this flag makes Cargo run in a different mode where the target artifacts are placed in a separate directory. See the \fIbuild cache\fR documentation for more details. .RE .sp \fB\-r\fR, \fB\-\-release\fR .RS 4 Document optimized artifacts with the \fBrelease\fR profile. See also the \fB\-\-profile\fR option for choosing a specific profile by name. .RE .sp \fB\-\-profile\fR \fIname\fR .RS 4 Document with the given profile. See \fIthe reference\fR for more details on profiles. .RE .sp \fB\-\-timings=\fR\fIfmts\fR .RS 4 Output information how long each compilation takes, and track concurrency information over time. Accepts an optional comma\-separated list of output formats; \fB\-\-timings\fR without an argument will default to \fB\-\-timings=html\fR\&. Specifying an output format (rather than the default) is unstable and requires \fB\-Zunstable\-options\fR\&. Valid output formats: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhtml\fR (unstable, requires \fB\-Zunstable\-options\fR): Write a human\-readable file \fBcargo\-timing.html\fR to the \fBtarget/cargo\-timings\fR directory with a report of the compilation. Also write a report to the same directory with a timestamp in the filename if you want to look at older runs. HTML output is suitable for human consumption only, and does not provide machine\-readable timing data. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR (unstable, requires \fB\-Zunstable\-options\fR): Emit machine\-readable JSON information about timing information. .RE .RE .SS "Output Options" .sp \fB\-\-target\-dir\fR \fIdirectory\fR .RS 4 Directory for all generated artifacts and intermediate files. May also be specified with the \fBCARGO_TARGET_DIR\fR environment variable, or the \fBbuild.target\-dir\fR \fIconfig value\fR \&. Defaults to \fBtarget\fR in the root of the workspace. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .sp \fB\-\-message\-format\fR \fIfmt\fR .RS 4 The output format for diagnostic messages. Can be specified multiple times and consists of comma\-separated values. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhuman\fR (default): Display in a human\-readable text format. Conflicts with \fBshort\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBshort\fR: Emit shorter, human\-readable text messages. Conflicts with \fBhuman\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR: Emit JSON messages to stdout. See \fIthe reference\fR for more details. Conflicts with \fBhuman\fR and \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-short\fR: Ensure the \fBrendered\fR field of JSON messages contains the \[lq]short\[rq] rendering from rustc. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-rendered\-ansi\fR: Ensure the \fBrendered\fR field of JSON messages contains embedded ANSI color codes for respecting rustc\[cq]s default color scheme. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-render\-diagnostics\fR: Instruct Cargo to not include rustc diagnostics in JSON messages printed, but instead Cargo itself should render the JSON diagnostics coming from rustc. Cargo\[cq]s own JSON diagnostics and others coming from rustc are still emitted. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-ignore\-rust\-version\fR .RS 4 Ignore \fBrust\-version\fR specification in packages. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SS "Miscellaneous Options" .sp \fB\-j\fR \fIN\fR, \fB\-\-jobs\fR \fIN\fR .RS 4 Number of parallel jobs to run. May also be specified with the \fBbuild.jobs\fR \fIconfig value\fR \&. 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 \fBdefault\fR is provided, it sets the value back to defaults. Should not be 0. .RE .sp \fB\-\-keep\-going\fR .RS 4 Build as many crates in the dependency graph as possible, rather than aborting the build on the first one that fails to build. .sp For example if the current package depends on dependencies \fBfails\fR and \fBworks\fR, one of which fails to build, \fBcargo doc \-j1\fR may or may not build the one that succeeds (depending on which one of the two builds Cargo picked to run first), whereas \fBcargo doc \-j1 \-\-keep\-going\fR would definitely run both builds, even if the one run first fails. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Build the local package documentation and its dependencies and output to \fBtarget/doc\fR\&. .sp .RS 4 .nf cargo doc .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-rustdoc\fR(1), \fBrustdoc\fR(1) cargo-0.86.0/src/etc/man/cargo-fetch.1000064400000000000000000000160461046102023000154020ustar 00000000000000'\" t .TH "CARGO\-FETCH" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-fetch \[em] Fetch dependencies of a package from the network .SH "SYNOPSIS" \fBcargo fetch\fR [\fIoptions\fR] .SH "DESCRIPTION" If a \fBCargo.lock\fR file is available, this command will ensure that all of the git dependencies and/or registry dependencies are downloaded and locally available. Subsequent Cargo commands will be able to run offline after a \fBcargo fetch\fR unless the lock file changes. .sp If the lock file is not available, then this command will generate the lock file before fetching the dependencies. .sp If \fB\-\-target\fR is not specified, then all target dependencies are fetched. .sp See also the \fIcargo\-prefetch\fR plugin which adds a command to download popular crates. This may be useful if you plan to use Cargo without a network with the \fB\-\-offline\fR flag. .SH "OPTIONS" .SS "Fetch options" .sp \fB\-\-target\fR \fItriple\fR .RS 4 Fetch for the given architecture. The default is all architectures. The general format of the triple is \fB\-\-\-\fR\&. Run \fBrustc \-\-print target\-list\fR for a list of supported targets. This flag may be specified multiple times. .sp This may also be specified with the \fBbuild.target\fR \fIconfig value\fR \&. .sp Note that specifying this flag makes Cargo run in a different mode where the target artifacts are placed in a separate directory. See the \fIbuild cache\fR documentation for more details. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Fetch all dependencies: .sp .RS 4 .nf cargo fetch .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-update\fR(1), \fBcargo\-generate\-lockfile\fR(1) cargo-0.86.0/src/etc/man/cargo-fix.1000064400000000000000000000473741046102023000151070ustar 00000000000000'\" t .TH "CARGO\-FIX" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-fix \[em] Automatically fix lint warnings reported by rustc .SH "SYNOPSIS" \fBcargo fix\fR [\fIoptions\fR] .SH "DESCRIPTION" This Cargo subcommand will automatically take rustc\[cq]s suggestions from diagnostics like warnings and apply them to your source code. This is intended to help automate tasks that rustc itself already knows how to tell you to fix! .sp Executing \fBcargo fix\fR will under the hood execute \fBcargo\-check\fR(1). Any warnings applicable to your crate will be automatically fixed (if possible) and all remaining warnings will be displayed when the check process is finished. For example if you\[cq]d like to apply all fixes to the current package, you can run: .sp .RS 4 .nf cargo fix .fi .RE .sp which behaves the same as \fBcargo check \-\-all\-targets\fR\&. .sp \fBcargo fix\fR is only capable of fixing code that is normally compiled with \fBcargo check\fR\&. If code is conditionally enabled with optional features, you will need to enable those features for that code to be analyzed: .sp .RS 4 .nf cargo fix \-\-features foo .fi .RE .sp Similarly, other \fBcfg\fR expressions like platform\-specific code will need to pass \fB\-\-target\fR to fix code for the given target. .sp .RS 4 .nf cargo fix \-\-target x86_64\-pc\-windows\-gnu .fi .RE .sp If you encounter any problems with \fBcargo fix\fR or otherwise have any questions or feature requests please don\[cq]t hesitate to file an issue at \&. .SS "Edition migration" The \fBcargo fix\fR subcommand can also be used to migrate a package from one \fIedition\fR to the next. The general procedure is: .sp .RS 4 \h'-04' 1.\h'+01'Run \fBcargo fix \-\-edition\fR\&. Consider also using the \fB\-\-all\-features\fR flag if your project has multiple features. You may also want to run \fBcargo fix \-\-edition\fR multiple times with different \fB\-\-target\fR flags if your project has platform\-specific code gated by \fBcfg\fR attributes. .RE .sp .RS 4 \h'-04' 2.\h'+01'Modify \fBCargo.toml\fR to set the \fIedition field\fR to the new edition. .RE .sp .RS 4 \h'-04' 3.\h'+01'Run your project tests to verify that everything still works. If new warnings are issued, you may want to consider running \fBcargo fix\fR again (without the \fB\-\-edition\fR flag) to apply any suggestions given by the compiler. .RE .sp And hopefully that\[cq]s it! Just keep in mind of the caveats mentioned above that \fBcargo fix\fR cannot update code for inactive features or \fBcfg\fR expressions. Also, in some rare cases the compiler is unable to automatically migrate all code to the new edition, and this may require manual changes after building with the new edition. .SH "OPTIONS" .SS "Fix options" .sp \fB\-\-broken\-code\fR .RS 4 Fix code even if it already has compiler errors. This is useful if \fBcargo fix\fR fails to apply the changes. It will apply the changes and leave the broken code in the working directory for you to inspect and manually fix. .RE .sp \fB\-\-edition\fR .RS 4 Apply changes that will update the code to the next edition. This will not update the edition in the \fBCargo.toml\fR manifest, which must be updated manually after \fBcargo fix \-\-edition\fR has finished. .RE .sp \fB\-\-edition\-idioms\fR .RS 4 Apply suggestions that will update code to the preferred style for the current edition. .RE .sp \fB\-\-allow\-no\-vcs\fR .RS 4 Fix code even if a VCS was not detected. .RE .sp \fB\-\-allow\-dirty\fR .RS 4 Fix code even if the working directory has changes. .RE .sp \fB\-\-allow\-staged\fR .RS 4 Fix code even if the working directory has staged changes. .RE .SS "Package Selection" By default, when no package selection options are given, the packages selected depend on the selected manifest file (based on the current working directory if \fB\-\-manifest\-path\fR is not given). If the manifest is the root of a workspace then the workspaces default members are selected, otherwise only the package defined by the manifest will be selected. .sp The default members of a workspace can be set explicitly with the \fBworkspace.default\-members\fR key in the root manifest. If this is not set, a virtual workspace will include all workspace members (equivalent to passing \fB\-\-workspace\fR), and a non\-virtual workspace will include only the root crate itself. .sp \fB\-p\fR \fIspec\fR\[u2026], \fB\-\-package\fR \fIspec\fR\[u2026] .RS 4 Fix only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .sp \fB\-\-workspace\fR .RS 4 Fix all members in the workspace. .RE .sp \fB\-\-all\fR .RS 4 Deprecated alias for \fB\-\-workspace\fR\&. .RE .sp \fB\-\-exclude\fR \fISPEC\fR\[u2026] .RS 4 Exclude the specified packages. Must be used in conjunction with the \fB\-\-workspace\fR flag. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .SS "Target Selection" When no target selection options are given, \fBcargo fix\fR will fix all targets (\fB\-\-all\-targets\fR implied). Binaries are skipped if they have \fBrequired\-features\fR that are missing. .sp Passing target selection flags will fix only the specified targets. .sp Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each glob pattern. .sp \fB\-\-lib\fR .RS 4 Fix the package\[cq]s library. .RE .sp \fB\-\-bin\fR \fIname\fR\[u2026] .RS 4 Fix the specified binary. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-bins\fR .RS 4 Fix all binary targets. .RE .sp \fB\-\-example\fR \fIname\fR\[u2026] .RS 4 Fix the specified example. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-examples\fR .RS 4 Fix all example targets. .RE .sp \fB\-\-test\fR \fIname\fR\[u2026] .RS 4 Fix the specified integration test. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-tests\fR .RS 4 Fix all targets that have the \fBtest = true\fR manifest flag set. By default this includes the library and binaries built as unittests, and integration tests. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a unittest, and once as a dependency for binaries, integration tests, etc.). Targets may be enabled or disabled by setting the \fBtest\fR flag in the manifest settings for the target. .RE .sp \fB\-\-bench\fR \fIname\fR\[u2026] .RS 4 Fix the specified benchmark. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-benches\fR .RS 4 Fix all targets that have the \fBbench = true\fR manifest flag set. By default this includes the library and binaries built as benchmarks, and bench targets. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a benchmark, and once as a dependency for binaries, benchmarks, etc.). Targets may be enabled or disabled by setting the \fBbench\fR flag in the manifest settings for the target. .RE .sp \fB\-\-all\-targets\fR .RS 4 Fix all targets. This is equivalent to specifying \fB\-\-lib \-\-bins \-\-tests \-\-benches \-\-examples\fR\&. .RE .SS "Feature Selection" The feature flags allow you to control which features are enabled. When no feature options are given, the \fBdefault\fR feature is activated for every selected package. .sp See \fIthe features documentation\fR for more details. .sp \fB\-F\fR \fIfeatures\fR, \fB\-\-features\fR \fIfeatures\fR .RS 4 Space or comma separated list of features to activate. Features of workspace members may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE .sp \fB\-\-all\-features\fR .RS 4 Activate all available features of all selected packages. .RE .sp \fB\-\-no\-default\-features\fR .RS 4 Do not activate the \fBdefault\fR feature of the selected packages. .RE .SS "Compilation Options" .sp \fB\-\-target\fR \fItriple\fR .RS 4 Fix for the given architecture. The default is the host architecture. The general format of the triple is \fB\-\-\-\fR\&. Run \fBrustc \-\-print target\-list\fR for a list of supported targets. This flag may be specified multiple times. .sp This may also be specified with the \fBbuild.target\fR \fIconfig value\fR \&. .sp Note that specifying this flag makes Cargo run in a different mode where the target artifacts are placed in a separate directory. See the \fIbuild cache\fR documentation for more details. .RE .sp \fB\-r\fR, \fB\-\-release\fR .RS 4 Fix optimized artifacts with the \fBrelease\fR profile. See also the \fB\-\-profile\fR option for choosing a specific profile by name. .RE .sp \fB\-\-profile\fR \fIname\fR .RS 4 Fix with the given profile. .sp As a special case, specifying the \fBtest\fR profile will also enable checking in test mode which will enable checking tests and enable the \fBtest\fR cfg option. See \fIrustc tests\fR for more detail. .sp See \fIthe reference\fR for more details on profiles. .RE .sp \fB\-\-timings=\fR\fIfmts\fR .RS 4 Output information how long each compilation takes, and track concurrency information over time. Accepts an optional comma\-separated list of output formats; \fB\-\-timings\fR without an argument will default to \fB\-\-timings=html\fR\&. Specifying an output format (rather than the default) is unstable and requires \fB\-Zunstable\-options\fR\&. Valid output formats: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhtml\fR (unstable, requires \fB\-Zunstable\-options\fR): Write a human\-readable file \fBcargo\-timing.html\fR to the \fBtarget/cargo\-timings\fR directory with a report of the compilation. Also write a report to the same directory with a timestamp in the filename if you want to look at older runs. HTML output is suitable for human consumption only, and does not provide machine\-readable timing data. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR (unstable, requires \fB\-Zunstable\-options\fR): Emit machine\-readable JSON information about timing information. .RE .RE .SS "Output Options" .sp \fB\-\-target\-dir\fR \fIdirectory\fR .RS 4 Directory for all generated artifacts and intermediate files. May also be specified with the \fBCARGO_TARGET_DIR\fR environment variable, or the \fBbuild.target\-dir\fR \fIconfig value\fR \&. Defaults to \fBtarget\fR in the root of the workspace. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .sp \fB\-\-message\-format\fR \fIfmt\fR .RS 4 The output format for diagnostic messages. Can be specified multiple times and consists of comma\-separated values. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhuman\fR (default): Display in a human\-readable text format. Conflicts with \fBshort\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBshort\fR: Emit shorter, human\-readable text messages. Conflicts with \fBhuman\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR: Emit JSON messages to stdout. See \fIthe reference\fR for more details. Conflicts with \fBhuman\fR and \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-short\fR: Ensure the \fBrendered\fR field of JSON messages contains the \[lq]short\[rq] rendering from rustc. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-rendered\-ansi\fR: Ensure the \fBrendered\fR field of JSON messages contains embedded ANSI color codes for respecting rustc\[cq]s default color scheme. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-render\-diagnostics\fR: Instruct Cargo to not include rustc diagnostics in JSON messages printed, but instead Cargo itself should render the JSON diagnostics coming from rustc. Cargo\[cq]s own JSON diagnostics and others coming from rustc are still emitted. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-ignore\-rust\-version\fR .RS 4 Ignore \fBrust\-version\fR specification in packages. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SS "Miscellaneous Options" .sp \fB\-j\fR \fIN\fR, \fB\-\-jobs\fR \fIN\fR .RS 4 Number of parallel jobs to run. May also be specified with the \fBbuild.jobs\fR \fIconfig value\fR \&. 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 \fBdefault\fR is provided, it sets the value back to defaults. Should not be 0. .RE .sp \fB\-\-keep\-going\fR .RS 4 Build as many crates in the dependency graph as possible, rather than aborting the build on the first one that fails to build. .sp For example if the current package depends on dependencies \fBfails\fR and \fBworks\fR, one of which fails to build, \fBcargo fix \-j1\fR may or may not build the one that succeeds (depending on which one of the two builds Cargo picked to run first), whereas \fBcargo fix \-j1 \-\-keep\-going\fR would definitely run both builds, even if the one run first fails. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Apply compiler suggestions to the local package: .sp .RS 4 .nf cargo fix .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Update a package to prepare it for the next edition: .sp .RS 4 .nf cargo fix \-\-edition .fi .RE .RE .sp .RS 4 \h'-04' 3.\h'+01'Apply suggested idioms for the current edition: .sp .RS 4 .nf cargo fix \-\-edition\-idioms .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-check\fR(1) cargo-0.86.0/src/etc/man/cargo-generate-lockfile.1000064400000000000000000000143211046102023000176630ustar 00000000000000'\" t .TH "CARGO\-GENERATE\-LOCKFILE" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-generate\-lockfile \[em] Generate the lockfile for a package .SH "SYNOPSIS" \fBcargo generate\-lockfile\fR [\fIoptions\fR] .SH "DESCRIPTION" This command will create the \fBCargo.lock\fR lockfile for the current package or workspace. If the lockfile already exists, it will be rebuilt with the latest available version of every package. .sp See also \fBcargo\-update\fR(1) which is also capable of creating a \fBCargo.lock\fR lockfile and has more options for controlling update behavior. .SH "OPTIONS" .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-ignore\-rust\-version\fR .RS 4 Ignore \fBrust\-version\fR specification in packages. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Create or update the lockfile for the current package or workspace: .sp .RS 4 .nf cargo generate\-lockfile .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-update\fR(1) cargo-0.86.0/src/etc/man/cargo-help.1000064400000000000000000000007521046102023000152360ustar 00000000000000'\" t .TH "CARGO\-HELP" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-help \[em] Get help for a Cargo command .SH "SYNOPSIS" \fBcargo help\fR [\fIsubcommand\fR] .SH "DESCRIPTION" Prints a help message for the given command. .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Get help for a command: .sp .RS 4 .nf cargo help build .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Help is also available with the \fB\-\-help\fR flag: .sp .RS 4 .nf cargo build \-\-help .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1) cargo-0.86.0/src/etc/man/cargo-info.1000064400000000000000000000137451046102023000152470ustar 00000000000000'\" t .TH "CARGO\-INFO" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-info \[em] Display information about a package. .SH "SYNOPSIS" \fBcargo info\fR [\fIoptions\fR] \fIspec\fR .SH "DESCRIPTION" This command displays information about a package. It fetches data from the package\[cq]s Cargo.toml file and presents it in a human\-readable format. .SH "OPTIONS" .SS "Info Options" .sp \fIspec\fR .RS 4 Fetch information about the specified package. The \fIspec\fR can be a package ID, see \fBcargo\-pkgid\fR(1) for the SPEC format. If the specified package is part of the current workspace, information from the local Cargo.toml file will be displayed. If the \fBCargo.lock\fR file does not exist, it will be created. If no version is specified, the appropriate version will be selected based on the Minimum Supported Rust Version (MSRV). .RE .sp \fB\-\-index\fR \fIindex\fR .RS 4 The URL of the registry index to use. .RE .sp \fB\-\-registry\fR \fIregistry\fR .RS 4 Name of the registry to use. Registry names are defined in \fICargo config files\fR \&. If not specified, the default registry is used, which is defined by the \fBregistry.default\fR config key which defaults to \fBcrates\-io\fR\&. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Manifest Options" .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Inspect the \fBserde\fR package from crates.io: .sp .RS 4 .nf cargo info serde .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Inspect the \fBserde\fR package with version \fB1.0.0\fR: .sp .RS 4 .nf cargo info serde@1.0.0 .fi .RE .RE .sp .RS 4 \h'-04' 3.\h'+01'Inspect the \fBserde\fR package form the local registry: .sp .RS 4 .nf cargo info serde \-\-registry my\-registry .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-search\fR(1) cargo-0.86.0/src/etc/man/cargo-init.1000064400000000000000000000123141046102023000152460ustar 00000000000000'\" t .TH "CARGO\-INIT" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-init \[em] Create a new Cargo package in an existing directory .SH "SYNOPSIS" \fBcargo init\fR [\fIoptions\fR] [\fIpath\fR] .SH "DESCRIPTION" This command will create a new Cargo manifest in the current directory. Give a path as an argument to create in the given directory. .sp If there are typically\-named Rust source files already in the directory, those will be used. If not, then a sample \fBsrc/main.rs\fR file will be created, or \fBsrc/lib.rs\fR if \fB\-\-lib\fR is passed. .sp If the directory is not already in a VCS repository, then a new repository is created (see \fB\-\-vcs\fR below). .sp See \fBcargo\-new\fR(1) for a similar command which will create a new package in a new directory. .SH "OPTIONS" .SS "Init Options" .sp \fB\-\-bin\fR .RS 4 Create a package with a binary target (\fBsrc/main.rs\fR). This is the default behavior. .RE .sp \fB\-\-lib\fR .RS 4 Create a package with a library target (\fBsrc/lib.rs\fR). .RE .sp \fB\-\-edition\fR \fIedition\fR .RS 4 Specify the Rust edition to use. Default is 2024. Possible values: 2015, 2018, 2021, 2024 .RE .sp \fB\-\-name\fR \fIname\fR .RS 4 Set the package name. Defaults to the directory name. .RE .sp \fB\-\-vcs\fR \fIvcs\fR .RS 4 Initialize a new VCS repository for the given version control system (git, hg, pijul, or fossil) or do not initialize any version control at all (none). If not specified, defaults to \fBgit\fR or the configuration value \fBcargo\-new.vcs\fR, or \fBnone\fR if already inside a VCS repository. .RE .sp \fB\-\-registry\fR \fIregistry\fR .RS 4 This sets the \fBpublish\fR field in \fBCargo.toml\fR to the given registry name which will restrict publishing only to that registry. .sp Registry names are defined in \fICargo config files\fR \&. If not specified, the default registry defined by the \fBregistry.default\fR config key is used. If the default registry is not set and \fB\-\-registry\fR is not used, the \fBpublish\fR field will not be set which means that publishing will not be restricted. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Create a binary Cargo package in the current directory: .sp .RS 4 .nf cargo init .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-new\fR(1) cargo-0.86.0/src/etc/man/cargo-install.1000064400000000000000000000435101046102023000157530ustar 00000000000000'\" t .TH "CARGO\-INSTALL" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-install \[em] Build and install a Rust binary .SH "SYNOPSIS" \fBcargo install\fR [\fIoptions\fR] \fIcrate\fR[@\fIversion\fR]\[u2026] .br \fBcargo install\fR [\fIoptions\fR] \fB\-\-path\fR \fIpath\fR .br \fBcargo install\fR [\fIoptions\fR] \fB\-\-git\fR \fIurl\fR [\fIcrate\fR\[u2026]] .br \fBcargo install\fR [\fIoptions\fR] \fB\-\-list\fR .SH "DESCRIPTION" 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. By default only binaries, not examples, are installed. .sp The installation root is determined, in order of precedence: .sp .RS 4 \h'-04'\(bu\h'+02'\fB\-\-root\fR option .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBCARGO_INSTALL_ROOT\fR environment variable .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBinstall.root\fR Cargo \fIconfig value\fR .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBCARGO_HOME\fR environment variable .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB$HOME/.cargo\fR .RE .sp There are multiple sources from which a crate can be installed. The default source location is crates.io but the \fB\-\-git\fR, \fB\-\-path\fR, and \fB\-\-registry\fR flags can change this source. If the source contains more than one package (such as crates.io or a git repository with multiple crates) the \fIcrate\fR argument is required to indicate which crate should be installed. .sp Crates from crates.io can optionally specify the version they wish to install via the \fB\-\-version\fR flags, and similarly packages from git repositories can optionally specify the branch, tag, or revision that should be installed. If a crate has multiple binaries, the \fB\-\-bin\fR argument can selectively install only one of them, and if you\[cq]d rather install examples the \fB\-\-example\fR argument can be used as well. .sp If the package is already installed, Cargo will reinstall it if the installed version does not appear to be up\-to\-date. If any of the following values change, then Cargo will reinstall the package: .sp .RS 4 \h'-04'\(bu\h'+02'The package version and source. .RE .sp .RS 4 \h'-04'\(bu\h'+02'The set of binary names installed. .RE .sp .RS 4 \h'-04'\(bu\h'+02'The chosen features. .RE .sp .RS 4 \h'-04'\(bu\h'+02'The profile (\fB\-\-profile\fR). .RE .sp .RS 4 \h'-04'\(bu\h'+02'The target (\fB\-\-target\fR). .RE .sp Installing with \fB\-\-path\fR will always build and install, unless there are conflicting binaries from another package. The \fB\-\-force\fR flag may be used to force Cargo to always reinstall the package. .sp If the source is crates.io or \fB\-\-git\fR then by default the crate will be built in a temporary target directory. To avoid this, the target directory can be specified by setting the \fBCARGO_TARGET_DIR\fR environment variable to a relative path. In particular, this can be useful for caching build artifacts on continuous integration systems. .SS "Dealing with the Lockfile" By default, the \fBCargo.lock\fR file that is included with the package will be ignored. This means that Cargo will recompute which versions of dependencies to use, possibly using newer versions that have been released since the package was published. The \fB\-\-locked\fR flag can be used to force Cargo to use the packaged \fBCargo.lock\fR file if it is available. This may be useful for ensuring reproducible builds, to use the exact same set of dependencies that were available when the package was published. It may also be useful if a newer version of a dependency is published that no longer builds on your system, or has other problems. The downside to using \fB\-\-locked\fR is that you will not receive any fixes or updates to any dependency. Note that Cargo did not start publishing \fBCargo.lock\fR files until version 1.37, which means packages published with prior versions will not have a \fBCargo.lock\fR file available. .SS "Configuration Discovery" This command operates on system or user level, not project level. This means that the local \fIconfiguration discovery\fR is ignored. Instead, the configuration discovery begins at \fB$CARGO_HOME/config.toml\fR\&. If the package is installed with \fB\-\-path $PATH\fR, the local configuration will be used, beginning discovery at \fB$PATH/.cargo/config.toml\fR\&. .SH "OPTIONS" .SS "Install Options" .sp \fB\-\-vers\fR \fIversion\fR, \fB\-\-version\fR \fIversion\fR .RS 4 Specify a version to install. This may be a \fIversion requirement\fR , like \fB~1.2\fR, to have Cargo select the newest version from the given requirement. If the version does not have a requirement operator (such as \fB^\fR or \fB~\fR), then it must be in the form \fIMAJOR.MINOR.PATCH\fR, and will install exactly that version; it is \fInot\fR treated as a caret requirement like Cargo dependencies are. .RE .sp \fB\-\-git\fR \fIurl\fR .RS 4 Git URL to install the specified crate from. .RE .sp \fB\-\-branch\fR \fIbranch\fR .RS 4 Branch to use when installing from git. .RE .sp \fB\-\-tag\fR \fItag\fR .RS 4 Tag to use when installing from git. .RE .sp \fB\-\-rev\fR \fIsha\fR .RS 4 Specific commit to use when installing from git. .RE .sp \fB\-\-path\fR \fIpath\fR .RS 4 Filesystem path to local crate to install from. .RE .sp \fB\-\-list\fR .RS 4 List all installed packages and their versions. .RE .sp \fB\-n\fR, \fB\-\-dry\-run\fR .RS 4 (unstable) Perform all checks without installing. .RE .sp \fB\-f\fR, \fB\-\-force\fR .RS 4 Force overwriting existing crates or binaries. This can be used if a package has installed a binary with the same name as another package. This is also useful if something has changed on the system that you want to rebuild with, such as a newer version of \fBrustc\fR\&. .RE .sp \fB\-\-no\-track\fR .RS 4 By default, Cargo keeps track of the installed packages with a metadata file stored in the installation root directory. This flag tells Cargo not to use or create that file. With this flag, Cargo will refuse to overwrite any existing files unless the \fB\-\-force\fR flag is used. This also disables Cargo\[cq]s ability to protect against multiple concurrent invocations of Cargo installing at the same time. .RE .sp \fB\-\-bin\fR \fIname\fR\[u2026] .RS 4 Install only the specified binary. .RE .sp \fB\-\-bins\fR .RS 4 Install all binaries. This is the default behavior. .RE .sp \fB\-\-example\fR \fIname\fR\[u2026] .RS 4 Install only the specified example. .RE .sp \fB\-\-examples\fR .RS 4 Install all examples. .RE .sp \fB\-\-root\fR \fIdir\fR .RS 4 Directory to install packages into. .RE .sp \fB\-\-registry\fR \fIregistry\fR .RS 4 Name of the registry to use. Registry names are defined in \fICargo config files\fR \&. If not specified, the default registry is used, which is defined by the \fBregistry.default\fR config key which defaults to \fBcrates\-io\fR\&. .RE .sp \fB\-\-index\fR \fIindex\fR .RS 4 The URL of the registry index to use. .RE .SS "Feature Selection" The feature flags allow you to control which features are enabled. When no feature options are given, the \fBdefault\fR feature is activated for every selected package. .sp See \fIthe features documentation\fR for more details. .sp \fB\-F\fR \fIfeatures\fR, \fB\-\-features\fR \fIfeatures\fR .RS 4 Space or comma separated list of features to activate. Features of workspace members may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE .sp \fB\-\-all\-features\fR .RS 4 Activate all available features of all selected packages. .RE .sp \fB\-\-no\-default\-features\fR .RS 4 Do not activate the \fBdefault\fR feature of the selected packages. .RE .SS "Compilation Options" .sp \fB\-\-target\fR \fItriple\fR .RS 4 Install for the given architecture. The default is the host architecture. The general format of the triple is \fB\-\-\-\fR\&. Run \fBrustc \-\-print target\-list\fR for a list of supported targets. .sp This may also be specified with the \fBbuild.target\fR \fIconfig value\fR \&. .sp Note that specifying this flag makes Cargo run in a different mode where the target artifacts are placed in a separate directory. See the \fIbuild cache\fR documentation for more details. .RE .sp \fB\-\-target\-dir\fR \fIdirectory\fR .RS 4 Directory for all generated artifacts and intermediate files. May also be specified with the \fBCARGO_TARGET_DIR\fR environment variable, or the \fBbuild.target\-dir\fR \fIconfig value\fR \&. Defaults to a new temporary folder located in the temporary directory of the platform. .sp When using \fB\-\-path\fR, by default it will use \fBtarget\fR directory in the workspace of the local crate unless \fB\-\-target\-dir\fR is specified. .RE .sp \fB\-\-debug\fR .RS 4 Build with the \fBdev\fR profile instead of the \fBrelease\fR profile. See also the \fB\-\-profile\fR option for choosing a specific profile by name. .RE .sp \fB\-\-profile\fR \fIname\fR .RS 4 Install with the given profile. See \fIthe reference\fR for more details on profiles. .RE .sp \fB\-\-timings=\fR\fIfmts\fR .RS 4 Output information how long each compilation takes, and track concurrency information over time. Accepts an optional comma\-separated list of output formats; \fB\-\-timings\fR without an argument will default to \fB\-\-timings=html\fR\&. Specifying an output format (rather than the default) is unstable and requires \fB\-Zunstable\-options\fR\&. Valid output formats: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhtml\fR (unstable, requires \fB\-Zunstable\-options\fR): Write a human\-readable file \fBcargo\-timing.html\fR to the \fBtarget/cargo\-timings\fR directory with a report of the compilation. Also write a report to the same directory with a timestamp in the filename if you want to look at older runs. HTML output is suitable for human consumption only, and does not provide machine\-readable timing data. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR (unstable, requires \fB\-Zunstable\-options\fR): Emit machine\-readable JSON information about timing information. .RE .RE .SS "Manifest Options" .sp \fB\-\-ignore\-rust\-version\fR .RS 4 Ignore \fBrust\-version\fR specification in packages. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .SS "Miscellaneous Options" .sp \fB\-j\fR \fIN\fR, \fB\-\-jobs\fR \fIN\fR .RS 4 Number of parallel jobs to run. May also be specified with the \fBbuild.jobs\fR \fIconfig value\fR \&. 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 \fBdefault\fR is provided, it sets the value back to defaults. Should not be 0. .RE .sp \fB\-\-keep\-going\fR .RS 4 Build as many crates in the dependency graph as possible, rather than aborting the build on the first one that fails to build. .sp For example if the current package depends on dependencies \fBfails\fR and \fBworks\fR, one of which fails to build, \fBcargo install \-j1\fR may or may not build the one that succeeds (depending on which one of the two builds Cargo picked to run first), whereas \fBcargo install \-j1 \-\-keep\-going\fR would definitely run both builds, even if the one run first fails. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .sp \fB\-\-message\-format\fR \fIfmt\fR .RS 4 The output format for diagnostic messages. Can be specified multiple times and consists of comma\-separated values. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhuman\fR (default): Display in a human\-readable text format. Conflicts with \fBshort\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBshort\fR: Emit shorter, human\-readable text messages. Conflicts with \fBhuman\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR: Emit JSON messages to stdout. See \fIthe reference\fR for more details. Conflicts with \fBhuman\fR and \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-short\fR: Ensure the \fBrendered\fR field of JSON messages contains the \[lq]short\[rq] rendering from rustc. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-rendered\-ansi\fR: Ensure the \fBrendered\fR field of JSON messages contains embedded ANSI color codes for respecting rustc\[cq]s default color scheme. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-render\-diagnostics\fR: Instruct Cargo to not include rustc diagnostics in JSON messages printed, but instead Cargo itself should render the JSON diagnostics coming from rustc. Cargo\[cq]s own JSON diagnostics and others coming from rustc are still emitted. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Install or upgrade a package from crates.io: .sp .RS 4 .nf cargo install ripgrep .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Install or reinstall the package in the current directory: .sp .RS 4 .nf cargo install \-\-path . .fi .RE .RE .sp .RS 4 \h'-04' 3.\h'+01'View the list of installed packages: .sp .RS 4 .nf cargo install \-\-list .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-uninstall\fR(1), \fBcargo\-search\fR(1), \fBcargo\-publish\fR(1) cargo-0.86.0/src/etc/man/cargo-locate-project.1000064400000000000000000000110711046102023000172150ustar 00000000000000'\" t .TH "CARGO\-LOCATE\-PROJECT" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-locate\-project \[em] Print a JSON representation of a Cargo.toml file\[cq]s location .SH "SYNOPSIS" \fBcargo locate\-project\fR [\fIoptions\fR] .SH "DESCRIPTION" This command will print a JSON object to stdout with the full path to the manifest. The manifest is found by searching upward for a file named \fBCargo.toml\fR starting from the current working directory. .sp If the project happens to be a part of a workspace, the manifest of the project, rather than the workspace root, is output. This can be overridden by the \fB\-\-workspace\fR flag. The root workspace is found by traversing further upward or by using the field \fBpackage.workspace\fR after locating the manifest of a workspace member. .SH "OPTIONS" .sp \fB\-\-workspace\fR .RS 4 Locate the \fBCargo.toml\fR at the root of the workspace, as opposed to the current workspace member. .RE .SS "Display Options" .sp \fB\-\-message\-format\fR \fIfmt\fR .RS 4 The representation in which to print the project location. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR (default): JSON object with the path under the key \[lq]root\[rq]\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBplain\fR: Just the path. .RE .RE .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Display the path to the manifest based on the current directory: .sp .RS 4 .nf cargo locate\-project .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-metadata\fR(1) cargo-0.86.0/src/etc/man/cargo-login.1000064400000000000000000000113461046102023000154170ustar 00000000000000'\" t .TH "CARGO\-LOGIN" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-login \[em] Log in to a registry .SH "SYNOPSIS" \fBcargo login\fR [\fIoptions\fR] [\fItoken\fR] [\fB\-\-\fR \fIargs\fR] .SH "DESCRIPTION" This command will run a credential provider to save a token so that commands that require authentication, such as \fBcargo\-publish\fR(1), will be automatically authenticated. .sp All the arguments following the two dashes (\fB\-\-\fR) are passed to the credential provider. .sp For the default \fBcargo:token\fR credential provider, the token is saved in \fB$CARGO_HOME/credentials.toml\fR\&. \fBCARGO_HOME\fR defaults to \fB\&.cargo\fR in your home directory. .sp If a registry has a credential\-provider specified, it will be used. Otherwise, the providers from the config value \fBregistry.global\-credential\-providers\fR will be attempted, starting from the end of the list. .sp If the \fItoken\fR argument is not specified, it will be read from stdin. .sp The API token for crates.io may be retrieved from \&. .sp Take care to keep the token secret, it should not be shared with anyone else. .SH "OPTIONS" .SS "Login Options" .sp \fB\-\-registry\fR \fIregistry\fR .RS 4 Name of the registry to use. Registry names are defined in \fICargo config files\fR \&. If not specified, the default registry is used, which is defined by the \fBregistry.default\fR config key which defaults to \fBcrates\-io\fR\&. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Save the token for the default registry: .sp .RS 4 .nf cargo login .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Save the token for a specific registry: .sp .RS 4 .nf cargo login \-\-registry my\-registry .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-logout\fR(1), \fBcargo\-publish\fR(1) cargo-0.86.0/src/etc/man/cargo-logout.1000064400000000000000000000113531046102023000156160ustar 00000000000000'\" t .TH "CARGO\-LOGOUT" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-logout \[em] Remove an API token from the registry locally .SH "SYNOPSIS" \fBcargo logout\fR [\fIoptions\fR] .SH "DESCRIPTION" This command will run a credential provider to remove a saved token. .sp For the default \fBcargo:token\fR credential provider, credentials are stored in \fB$CARGO_HOME/credentials.toml\fR where \fB$CARGO_HOME\fR defaults to \fB\&.cargo\fR in your home directory. .sp If a registry has a credential\-provider specified, it will be used. Otherwise, the providers from the config value \fBregistry.global\-credential\-providers\fR will be attempted, starting from the end of the list. .sp If \fB\-\-registry\fR is not specified, then the credentials for the default registry will be removed (configured by \fI\f(BIregistry.default\fI\fR , which defaults to ). .sp This will not revoke the token on the server. If you need to revoke the token, visit the registry website and follow its instructions (see to revoke the token for ). .SH "OPTIONS" .SS "Logout Options" .sp \fB\-\-registry\fR \fIregistry\fR .RS 4 Name of the registry to use. Registry names are defined in \fICargo config files\fR \&. If not specified, the default registry is used, which is defined by the \fBregistry.default\fR config key which defaults to \fBcrates\-io\fR\&. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Remove the default registry token: .sp .RS 4 .nf cargo logout .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Remove the token for a specific registry: .sp .RS 4 .nf cargo logout \-\-registry my\-registry .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-login\fR(1) cargo-0.86.0/src/etc/man/cargo-metadata.1000064400000000000000000000540271046102023000160720ustar 00000000000000'\" t .TH "CARGO\-METADATA" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-metadata \[em] Machine\-readable metadata about the current package .SH "SYNOPSIS" \fBcargo metadata\fR [\fIoptions\fR] .SH "DESCRIPTION" Output JSON to stdout containing information about the workspace members and resolved dependencies of the current package. .sp The format of the output is subject to change in futures versions of Cargo. It is recommended to include the \fB\-\-format\-version\fR flag to future\-proof your code to ensure the output is in the format you are expecting. For more on the expectations, see \[lq]Compatibility\[rq]\&. .sp See the \fIcargo_metadata crate\fR for a Rust API for reading the metadata. .SH "OUTPUT FORMAT" .SS "Compatibility" Within the same output format version, the compatibility is maintained, except some scenarios. The following is a non\-exhaustive list of changes that are not considered as incompatible: .sp .RS 4 \h'-04'\(bu\h'+02'\fBAdding new fields\fR \[em] New fields will be added when needed. Reserving this helps Cargo evolve without bumping the format version too often. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBAdding new values for enum\-like fields\fR \[em] Same as adding new fields. It keeps metadata evolving without stagnation. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBChanging opaque representations\fR \[em] The inner representations of some fields are implementation details. For example, fields related to \[lq]Source ID\[rq] are treated as opaque identifiers to differentiate packages or sources. Consumers shouldn\[cq]t rely on those representations unless specified. .RE .SS "JSON format" The JSON output has the following format: .sp .RS 4 .nf { /* Array of all packages in the workspace. It also includes all feature\-enabled dependencies unless \-\-no\-deps is used. */ "packages": [ { /* The name of the package. */ "name": "my\-package", /* The version of the package. */ "version": "0.1.0", /* The Package ID for referring to the package within the document and as the `\-\-package` argument to many commands */ "id": "file:///path/to/my\-package#0.1.0", /* The license value from the manifest, or null. */ "license": "MIT/Apache\-2.0", /* The license\-file value from the manifest, or null. */ "license_file": "LICENSE", /* The description value from the manifest, or null. */ "description": "Package description.", /* The source ID of the package, an "opaque" identifier representing where a package is retrieved from. See "Compatibility" above for the stability guarantee. This is null for path dependencies and workspace members. For other dependencies, it is a string with the format: \- "registry+URL" for registry\-based dependencies. Example: "registry+https://github.com/rust\-lang/crates.io\-index" \- "git+URL" for git\-based dependencies. Example: "git+https://github.com/rust\-lang/cargo?rev=5e85ba14aaa20f8133863373404cb0af69eeef2c#5e85ba14aaa20f8133863373404cb0af69eeef2c" \- "sparse+URL" for dependencies from a sparse registry Example: "sparse+https://my\-sparse\-registry.org" The value after the `+` is not explicitly defined, and may change between versions of Cargo and may not directly correlate to other things, such as registry definitions in a config file. New source kinds may be added in the future which will have different `+` prefixed identifiers. */ "source": null, /* Array of dependencies declared in the package's manifest. */ "dependencies": [ { /* The name of the dependency. */ "name": "bitflags", /* The source ID of the dependency. May be null, see description for the package source. */ "source": "registry+https://github.com/rust\-lang/crates.io\-index", /* The version requirement for the dependency. Dependencies without a version requirement have a value of "*". */ "req": "^1.0", /* The dependency kind. "dev", "build", or null for a normal dependency. */ "kind": null, /* If the dependency is renamed, this is the new name for the dependency as a string. null if it is not renamed. */ "rename": null, /* Boolean of whether or not this is an optional dependency. */ "optional": false, /* Boolean of whether or not default features are enabled. */ "uses_default_features": true, /* Array of features enabled. */ "features": [], /* The target platform for the dependency. null if not a target dependency. */ "target": "cfg(windows)", /* The file system path for a local path dependency. not present if not a path dependency. */ "path": "/path/to/dep", /* A string of the URL of the registry this dependency is from. If not specified or null, the dependency is from the default registry (crates.io). */ "registry": null, /* (unstable) Boolean flag of whether or not this is a pulbic dependency. This field is only present when `\-Zpublic\-dependency` is enabled. */ "public": false } ], /* Array of Cargo targets. */ "targets": [ { /* Array of target kinds. \- lib targets list the `crate\-type` values from the manifest such as "lib", "rlib", "dylib", "proc\-macro", etc. (default ["lib"]) \- binary is ["bin"] \- example is ["example"] \- integration test is ["test"] \- benchmark is ["bench"] \- build script is ["custom\-build"] */ "kind": [ "bin" ], /* Array of crate types. \- lib and example libraries list the `crate\-type` values from the manifest such as "lib", "rlib", "dylib", "proc\-macro", etc. (default ["lib"]) \- all other target kinds are ["bin"] */ "crate_types": [ "bin" ], /* The name of the target. For lib targets, dashes will be replaced with underscores. */ "name": "my\-package", /* Absolute path to the root source file of the target. */ "src_path": "/path/to/my\-package/src/main.rs", /* The Rust edition of the target. Defaults to the package edition. */ "edition": "2018", /* Array of required features. This property is not included if no required features are set. */ "required\-features": ["feat1"], /* Whether the target should be documented by `cargo doc`. */ "doc": true, /* Whether or not this target has doc tests enabled, and the target is compatible with doc testing. */ "doctest": false, /* Whether or not this target should be built and run with `\-\-test` */ "test": true } ], /* Set of features defined for the package. Each feature maps to an array of features or dependencies it enables. */ "features": { "default": [ "feat1" ], "feat1": [], "feat2": [] }, /* Absolute path to this package's manifest. */ "manifest_path": "/path/to/my\-package/Cargo.toml", /* Package metadata. This is null if no metadata is specified. */ "metadata": { "docs": { "rs": { "all\-features": true } } }, /* List of registries to which this package may be published. Publishing is unrestricted if null, and forbidden if an empty array. */ "publish": [ "crates\-io" ], /* Array of authors from the manifest. Empty array if no authors specified. */ "authors": [ "Jane Doe " ], /* Array of categories from the manifest. */ "categories": [ "command\-line\-utilities" ], /* Optional string that is the default binary picked by cargo run. */ "default_run": null, /* Optional string that is the minimum supported rust version */ "rust_version": "1.56", /* Array of keywords from the manifest. */ "keywords": [ "cli" ], /* The readme value from the manifest or null if not specified. */ "readme": "README.md", /* The repository value from the manifest or null if not specified. */ "repository": "https://github.com/rust\-lang/cargo", /* The homepage value from the manifest or null if not specified. */ "homepage": "https://rust\-lang.org", /* The documentation value from the manifest or null if not specified. */ "documentation": "https://doc.rust\-lang.org/stable/std", /* The default edition of the package. Note that individual targets may have different editions. */ "edition": "2018", /* Optional string that is the name of a native library the package is linking to. */ "links": null, } ], /* Array of members of the workspace. Each entry is the Package ID for the package. */ "workspace_members": [ "file:///path/to/my\-package#0.1.0", ], /* Array of default members of the workspace. Each entry is the Package ID for the package. */ "workspace_default_members": [ "file:///path/to/my\-package#0.1.0", ], // The resolved dependency graph for the entire workspace. The enabled // features are based on the enabled features for the "current" package. // Inactivated optional dependencies are not listed. // // This is null if \-\-no\-deps is specified. // // By default, this includes all dependencies for all target platforms. // The `\-\-filter\-platform` flag may be used to narrow to a specific // target triple. "resolve": { /* Array of nodes within the dependency graph. Each node is a package. */ "nodes": [ { /* The Package ID of this node. */ "id": "file:///path/to/my\-package#0.1.0", /* The dependencies of this package, an array of Package IDs. */ "dependencies": [ "https://github.com/rust\-lang/crates.io\-index#bitflags@1.0.4" ], /* The dependencies of this package. This is an alternative to "dependencies" which contains additional information. In particular, this handles renamed dependencies. */ "deps": [ { /* The name of the dependency's library target. If this is a renamed dependency, this is the new name. */ "name": "bitflags", /* The Package ID of the dependency. */ "pkg": "https://github.com/rust\-lang/crates.io\-index#bitflags@1.0.4" /* Array of dependency kinds. Added in Cargo 1.40. */ "dep_kinds": [ { /* The dependency kind. "dev", "build", or null for a normal dependency. */ "kind": null, /* The target platform for the dependency. null if not a target dependency. */ "target": "cfg(windows)" } ] } ], /* Array of features enabled on this package. */ "features": [ "default" ] } ], /* The root package of the workspace. This is null if this is a virtual workspace. Otherwise it is the Package ID of the root package. */ "root": "file:///path/to/my\-package#0.1.0", }, /* The absolute path to the build directory where Cargo places its output. */ "target_directory": "/path/to/my\-package/target", /* The version of the schema for this metadata structure. This will be changed if incompatible changes are ever made. */ "version": 1, /* The absolute path to the root of the workspace. */ "workspace_root": "/path/to/my\-package" /* Workspace metadata. This is null if no metadata is specified. */ "metadata": { "docs": { "rs": { "all\-features": true } } } } .fi .RE .sp Notes: .sp .RS 4 \h'-04'\(bu\h'+02'For \fB"id"\fR field syntax, see \fIPackage ID Specifications\fR in the reference. .RE .SH "OPTIONS" .SS "Output Options" .sp \fB\-\-no\-deps\fR .RS 4 Output information only about the workspace members and don\[cq]t fetch dependencies. .RE .sp \fB\-\-format\-version\fR \fIversion\fR .RS 4 Specify the version of the output format to use. Currently \fB1\fR is the only possible value. .RE .sp \fB\-\-filter\-platform\fR \fItriple\fR .RS 4 This filters the \fBresolve\fR output to only include dependencies for the given \fItarget triple\fR \&. Without this flag, the resolve includes all targets. .sp Note that the dependencies listed in the \[lq]packages\[rq] array still includes all dependencies. Each package definition is intended to be an unaltered reproduction of the information within \fBCargo.toml\fR\&. .RE .SS "Feature Selection" The feature flags allow you to control which features are enabled. When no feature options are given, the \fBdefault\fR feature is activated for every selected package. .sp See \fIthe features documentation\fR for more details. .sp \fB\-F\fR \fIfeatures\fR, \fB\-\-features\fR \fIfeatures\fR .RS 4 Space or comma separated list of features to activate. Features of workspace members may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE .sp \fB\-\-all\-features\fR .RS 4 Activate all available features of all selected packages. .RE .sp \fB\-\-no\-default\-features\fR .RS 4 Do not activate the \fBdefault\fR feature of the selected packages. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Output JSON about the current package: .sp .RS 4 .nf cargo metadata \-\-format\-version=1 .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-pkgid\fR(1), \fIPackage ID Specifications\fR , \fIJSON messages\fR cargo-0.86.0/src/etc/man/cargo-new.1000064400000000000000000000120201046102023000150660ustar 00000000000000'\" t .TH "CARGO\-NEW" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-new \[em] Create a new Cargo package .SH "SYNOPSIS" \fBcargo new\fR [\fIoptions\fR] \fIpath\fR .SH "DESCRIPTION" This command will create a new Cargo package in the given directory. This includes a simple template with a \fBCargo.toml\fR manifest, sample source file, and a VCS ignore file. If the directory is not already in a VCS repository, then a new repository is created (see \fB\-\-vcs\fR below). .sp See \fBcargo\-init\fR(1) for a similar command which will create a new manifest in an existing directory. .SH "OPTIONS" .SS "New Options" .sp \fB\-\-bin\fR .RS 4 Create a package with a binary target (\fBsrc/main.rs\fR). This is the default behavior. .RE .sp \fB\-\-lib\fR .RS 4 Create a package with a library target (\fBsrc/lib.rs\fR). .RE .sp \fB\-\-edition\fR \fIedition\fR .RS 4 Specify the Rust edition to use. Default is 2024. Possible values: 2015, 2018, 2021, 2024 .RE .sp \fB\-\-name\fR \fIname\fR .RS 4 Set the package name. Defaults to the directory name. .RE .sp \fB\-\-vcs\fR \fIvcs\fR .RS 4 Initialize a new VCS repository for the given version control system (git, hg, pijul, or fossil) or do not initialize any version control at all (none). If not specified, defaults to \fBgit\fR or the configuration value \fBcargo\-new.vcs\fR, or \fBnone\fR if already inside a VCS repository. .RE .sp \fB\-\-registry\fR \fIregistry\fR .RS 4 This sets the \fBpublish\fR field in \fBCargo.toml\fR to the given registry name which will restrict publishing only to that registry. .sp Registry names are defined in \fICargo config files\fR \&. If not specified, the default registry defined by the \fBregistry.default\fR config key is used. If the default registry is not set and \fB\-\-registry\fR is not used, the \fBpublish\fR field will not be set which means that publishing will not be restricted. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Create a binary Cargo package in the given directory: .sp .RS 4 .nf cargo new foo .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-init\fR(1) cargo-0.86.0/src/etc/man/cargo-owner.1000064400000000000000000000131661046102023000154430ustar 00000000000000'\" t .TH "CARGO\-OWNER" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-owner \[em] Manage the owners of a crate on the registry .SH "SYNOPSIS" \fBcargo owner\fR [\fIoptions\fR] \fB\-\-add\fR \fIlogin\fR [\fIcrate\fR] .br \fBcargo owner\fR [\fIoptions\fR] \fB\-\-remove\fR \fIlogin\fR [\fIcrate\fR] .br \fBcargo owner\fR [\fIoptions\fR] \fB\-\-list\fR [\fIcrate\fR] .SH "DESCRIPTION" This command will modify the owners for a crate on the registry. Owners of a crate can upload new versions and yank old versions. Non\-team owners can also modify the set of owners, so take care! .sp This command requires you to be authenticated with either the \fB\-\-token\fR option or using \fBcargo\-login\fR(1). .sp If the crate name is not specified, it will use the package name from the current directory. .sp See \fIthe reference\fR for more information about owners and publishing. .SH "OPTIONS" .SS "Owner Options" .sp \fB\-a\fR, \fB\-\-add\fR \fIlogin\fR\[u2026] .RS 4 Invite the given user or team as an owner. .RE .sp \fB\-r\fR, \fB\-\-remove\fR \fIlogin\fR\[u2026] .RS 4 Remove the given user or team as an owner. .RE .sp \fB\-l\fR, \fB\-\-list\fR .RS 4 List owners of a crate. .RE .sp \fB\-\-token\fR \fItoken\fR .RS 4 API token to use when authenticating. This overrides the token stored in the credentials file (which is created by \fBcargo\-login\fR(1)). .sp \fICargo config\fR environment variables can be used to override the tokens stored in the credentials file. The token for crates.io may be specified with the \fBCARGO_REGISTRY_TOKEN\fR environment variable. Tokens for other registries may be specified with environment variables of the form \fBCARGO_REGISTRIES_NAME_TOKEN\fR where \fBNAME\fR is the name of the registry in all capital letters. .RE .sp \fB\-\-index\fR \fIindex\fR .RS 4 The URL of the registry index to use. .RE .sp \fB\-\-registry\fR \fIregistry\fR .RS 4 Name of the registry to use. Registry names are defined in \fICargo config files\fR \&. If not specified, the default registry is used, which is defined by the \fBregistry.default\fR config key which defaults to \fBcrates\-io\fR\&. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'List owners of a package: .sp .RS 4 .nf cargo owner \-\-list foo .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Invite an owner to a package: .sp .RS 4 .nf cargo owner \-\-add username foo .fi .RE .RE .sp .RS 4 \h'-04' 3.\h'+01'Remove an owner from a package: .sp .RS 4 .nf cargo owner \-\-remove username foo .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-login\fR(1), \fBcargo\-publish\fR(1) cargo-0.86.0/src/etc/man/cargo-package.1000064400000000000000000000341631046102023000157040ustar 00000000000000'\" t .TH "CARGO\-PACKAGE" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-package \[em] Assemble the local package into a distributable tarball .SH "SYNOPSIS" \fBcargo package\fR [\fIoptions\fR] .SH "DESCRIPTION" This command will create a distributable, compressed \fB\&.crate\fR file with the source code of the package in the current directory. The resulting file will be stored in the \fBtarget/package\fR directory. This performs the following steps: .sp .RS 4 \h'-04' 1.\h'+01'Load and check the current workspace, performing some basic checks. .sp .RS 4 \h'-04'\(bu\h'+02'Path dependencies are not allowed unless they have a version key. Cargo will ignore the path key for dependencies in published packages. \fBdev\-dependencies\fR do not have this restriction. .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Create the compressed \fB\&.crate\fR file. .sp .RS 4 \h'-04'\(bu\h'+02'The original \fBCargo.toml\fR file is rewritten and normalized. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB[patch]\fR, \fB[replace]\fR, and \fB[workspace]\fR sections are removed from the manifest. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBCargo.lock\fR is automatically included if the package contains an executable binary or example target. \fBcargo\-install\fR(1) will use the packaged lock file if the \fB\-\-locked\fR flag is used. .RE .sp .RS 4 \h'-04'\(bu\h'+02'A \fB\&.cargo_vcs_info.json\fR file is included that contains information about the current VCS checkout hash if available, as well as a flag if the worktree is dirty. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Symlinks are flattened to their target files. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Files and directories are included or excluded based on rules mentioned in \fIthe \f(BI[include]\fI and \f(BI[exclude]\fI fields\fR \&. .RE .RE .sp .RS 4 \h'-04' 3.\h'+01'Extract the \fB\&.crate\fR file and build it to verify it can build. .sp .RS 4 \h'-04'\(bu\h'+02'This will rebuild your package from scratch to ensure that it can be built from a pristine state. The \fB\-\-no\-verify\fR flag can be used to skip this step. .RE .RE .sp .RS 4 \h'-04' 4.\h'+01'Check that build scripts did not modify any source files. .RE .sp The list of files included can be controlled with the \fBinclude\fR and \fBexclude\fR fields in the manifest. .sp See \fIthe reference\fR for more details about packaging and publishing. .SS ".cargo_vcs_info.json format" Will generate a \fB\&.cargo_vcs_info.json\fR in the following format .sp .RS 4 .nf { "git": { "sha1": "aac20b6e7e543e6dd4118b246c77225e3a3a1302", "dirty": true }, "path_in_vcs": "" } .fi .RE .sp \fBdirty\fR indicates that the Git worktree was dirty when the package was built. .sp \fBpath_in_vcs\fR will be set to a repo\-relative path for packages in subdirectories of the version control repository. .sp The compatibility of this file is maintained under the same policy as the JSON output of \fBcargo\-metadata\fR(1). .sp Note that this file provides a best\-effort snapshot of the VCS information. However, the provenance of the package is not verified. There is no guarantee that the source code in the tarball matches the VCS information. .SH "OPTIONS" .SS "Package Options" .sp \fB\-l\fR, \fB\-\-list\fR .RS 4 Print files included in a package without making one. .RE .sp \fB\-\-no\-verify\fR .RS 4 Don\[cq]t verify the contents by building them. .RE .sp \fB\-\-no\-metadata\fR .RS 4 Ignore warnings about a lack of human\-usable metadata (such as the description or the license). .RE .sp \fB\-\-allow\-dirty\fR .RS 4 Allow working directories with uncommitted VCS changes to be packaged. .RE .sp \fB\-\-index\fR \fIindex\fR .RS 4 The URL of the registry index to use. .RE .sp \fB\-\-registry\fR \fIregistry\fR .RS 4 Name of the registry to package for; see \fBcargo publish \-\-help\fR for more details about configuration of registry names. The packages will not be published to this registry, but if we are packaging multiple inter\-dependent crates, lock\-files will be generated under the assumption that dependencies will be published to this registry. .RE .SS "Package Selection" By default, when no package selection options are given, the packages selected depend on the selected manifest file (based on the current working directory if \fB\-\-manifest\-path\fR is not given). If the manifest is the root of a workspace then the workspaces default members are selected, otherwise only the package defined by the manifest will be selected. .sp The default members of a workspace can be set explicitly with the \fBworkspace.default\-members\fR key in the root manifest. If this is not set, a virtual workspace will include all workspace members (equivalent to passing \fB\-\-workspace\fR), and a non\-virtual workspace will include only the root crate itself. .sp \fB\-p\fR \fIspec\fR\[u2026], \fB\-\-package\fR \fIspec\fR\[u2026] .RS 4 Package only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .sp \fB\-\-workspace\fR .RS 4 Package all members in the workspace. .RE .sp \fB\-\-exclude\fR \fISPEC\fR\[u2026] .RS 4 Exclude the specified packages. Must be used in conjunction with the \fB\-\-workspace\fR flag. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .SS "Compilation Options" .sp \fB\-\-target\fR \fItriple\fR .RS 4 Package for the given architecture. The default is the host architecture. The general format of the triple is \fB\-\-\-\fR\&. Run \fBrustc \-\-print target\-list\fR for a list of supported targets. This flag may be specified multiple times. .sp This may also be specified with the \fBbuild.target\fR \fIconfig value\fR \&. .sp Note that specifying this flag makes Cargo run in a different mode where the target artifacts are placed in a separate directory. See the \fIbuild cache\fR documentation for more details. .RE .sp \fB\-\-target\-dir\fR \fIdirectory\fR .RS 4 Directory for all generated artifacts and intermediate files. May also be specified with the \fBCARGO_TARGET_DIR\fR environment variable, or the \fBbuild.target\-dir\fR \fIconfig value\fR \&. Defaults to \fBtarget\fR in the root of the workspace. .RE .SS "Feature Selection" The feature flags allow you to control which features are enabled. When no feature options are given, the \fBdefault\fR feature is activated for every selected package. .sp See \fIthe features documentation\fR for more details. .sp \fB\-F\fR \fIfeatures\fR, \fB\-\-features\fR \fIfeatures\fR .RS 4 Space or comma separated list of features to activate. Features of workspace members may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE .sp \fB\-\-all\-features\fR .RS 4 Activate all available features of all selected packages. .RE .sp \fB\-\-no\-default\-features\fR .RS 4 Do not activate the \fBdefault\fR feature of the selected packages. .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Miscellaneous Options" .sp \fB\-j\fR \fIN\fR, \fB\-\-jobs\fR \fIN\fR .RS 4 Number of parallel jobs to run. May also be specified with the \fBbuild.jobs\fR \fIconfig value\fR \&. 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 \fBdefault\fR is provided, it sets the value back to defaults. Should not be 0. .RE .sp \fB\-\-keep\-going\fR .RS 4 Build as many crates in the dependency graph as possible, rather than aborting the build on the first one that fails to build. .sp For example if the current package depends on dependencies \fBfails\fR and \fBworks\fR, one of which fails to build, \fBcargo package \-j1\fR may or may not build the one that succeeds (depending on which one of the two builds Cargo picked to run first), whereas \fBcargo package \-j1 \-\-keep\-going\fR would definitely run both builds, even if the one run first fails. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Create a compressed \fB\&.crate\fR file of the current package: .sp .RS 4 .nf cargo package .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-publish\fR(1) cargo-0.86.0/src/etc/man/cargo-pkgid.1000064400000000000000000000202151046102023000154000ustar 00000000000000'\" t .TH "CARGO\-PKGID" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-pkgid \[em] Print a fully qualified package specification .SH "SYNOPSIS" \fBcargo pkgid\fR [\fIoptions\fR] [\fIspec\fR] .SH "DESCRIPTION" Given a \fIspec\fR argument, print out the fully qualified package ID specifier for a package or dependency in the current workspace. This command will generate an error if \fIspec\fR is ambiguous as to which package it refers to in the dependency graph. If no \fIspec\fR is given, then the specifier for the local package is printed. .sp This command requires that a lockfile is available and dependencies have been fetched. .sp A package specifier consists of a name, version, and source URL. You are allowed to use partial specifiers to succinctly match a specific package as long as it matches only one package. This specifier is also used by other parts in Cargo, such as \fBcargo\-metadata\fR(1) and \fIJSON messages\fR emitted by Cargo. .sp The format of a \fIspec\fR can be one of the following: .TS allbox tab(:); lt lt. T{ SPEC Structure T}:T{ Example SPEC T} T{ \fIname\fR T}:T{ \fBbitflags\fR T} T{ \fIname\fR\fB@\fR\fIversion\fR T}:T{ \fBbitflags@1.0.4\fR T} T{ \fIurl\fR T}:T{ \fBhttps://github.com/rust\-lang/cargo\fR T} T{ \fIurl\fR\fB#\fR\fIversion\fR T}:T{ \fBhttps://github.com/rust\-lang/cargo#0.33.0\fR T} T{ \fIurl\fR\fB#\fR\fIname\fR T}:T{ \fBhttps://github.com/rust\-lang/crates.io\-index#bitflags\fR T} T{ \fIurl\fR\fB#\fR\fIname\fR\fB@\fR\fIversion\fR T}:T{ \fBhttps://github.com/rust\-lang/cargo#crates\-io@0.21.0\fR T} .TE .sp .sp The specification grammar can be found in chapter \fIPackage ID Specifications\fR \&. .SH "OPTIONS" .SS "Package Selection" .sp \fB\-p\fR \fIspec\fR, \fB\-\-package\fR \fIspec\fR .RS 4 Get the package ID for the given package instead of the current package. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Retrieve package specification for \fBfoo\fR package: .sp .RS 4 .nf cargo pkgid foo .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Retrieve package specification for version 1.0.0 of \fBfoo\fR: .sp .RS 4 .nf cargo pkgid foo@1.0.0 .fi .RE .RE .sp .RS 4 \h'-04' 3.\h'+01'Retrieve package specification for \fBfoo\fR from crates.io: .sp .RS 4 .nf cargo pkgid https://github.com/rust\-lang/crates.io\-index#foo .fi .RE .RE .sp .RS 4 \h'-04' 4.\h'+01'Retrieve package specification for \fBfoo\fR from a local package: .sp .RS 4 .nf cargo pkgid file:///path/to/local/package#foo .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-generate\-lockfile\fR(1), \fBcargo\-metadata\fR(1), \fIPackage ID Specifications\fR , \fIJSON messages\fR cargo-0.86.0/src/etc/man/cargo-publish.1000064400000000000000000000341511046102023000157540ustar 00000000000000'\" t .TH "CARGO\-PUBLISH" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-publish \[em] Upload a package to the registry .SH "SYNOPSIS" \fBcargo publish\fR [\fIoptions\fR] .SH "DESCRIPTION" This command will create a distributable, compressed \fB\&.crate\fR file with the source code of the package in the current directory and upload it to a registry. The default registry is \&. This performs the following steps: .sp .RS 4 \h'-04' 1.\h'+01'Performs a few checks, including: .sp .RS 4 \h'-04'\(bu\h'+02'Checks the \fBpackage.publish\fR key in the manifest for restrictions on which registries you are allowed to publish to. .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Create a \fB\&.crate\fR file by following the steps in \fBcargo\-package\fR(1). .RE .sp .RS 4 \h'-04' 3.\h'+01'Upload the crate to the registry. The server will perform additional checks on the crate. .RE .sp .RS 4 \h'-04' 4.\h'+01'The client will poll waiting for the package to appear in the index, and may timeout. In that case, you will need to check for completion manually. This timeout does not affect the upload. .RE .sp This command requires you to be authenticated with either the \fB\-\-token\fR option or using \fBcargo\-login\fR(1). .sp See \fIthe reference\fR for more details about packaging and publishing. .SH "OPTIONS" .SS "Publish Options" .sp \fB\-\-dry\-run\fR .RS 4 Perform all checks without uploading. .RE .sp \fB\-\-token\fR \fItoken\fR .RS 4 API token to use when authenticating. This overrides the token stored in the credentials file (which is created by \fBcargo\-login\fR(1)). .sp \fICargo config\fR environment variables can be used to override the tokens stored in the credentials file. The token for crates.io may be specified with the \fBCARGO_REGISTRY_TOKEN\fR environment variable. Tokens for other registries may be specified with environment variables of the form \fBCARGO_REGISTRIES_NAME_TOKEN\fR where \fBNAME\fR is the name of the registry in all capital letters. .RE .sp \fB\-\-no\-verify\fR .RS 4 Don\[cq]t verify the contents by building them. .RE .sp \fB\-\-allow\-dirty\fR .RS 4 Allow working directories with uncommitted VCS changes to be packaged. .RE .sp \fB\-\-index\fR \fIindex\fR .RS 4 The URL of the registry index to use. .RE .sp \fB\-\-registry\fR \fIregistry\fR .RS 4 Name of the registry to publish to. Registry names are defined in \fICargo config files\fR \&. If not specified, and there is a \fI\f(BIpackage.publish\fI\fR field in \fBCargo.toml\fR with a single registry, then it will publish to that registry. Otherwise it will use the default registry, which is defined by the \fI\f(BIregistry.default\fI\fR config key which defaults to \fBcrates\-io\fR\&. .RE .SS "Package Selection" By default, when no package selection options are given, the packages selected depend on the selected manifest file (based on the current working directory if \fB\-\-manifest\-path\fR is not given). If the manifest is the root of a workspace then the workspaces default members are selected, otherwise only the package defined by the manifest will be selected. .sp The default members of a workspace can be set explicitly with the \fBworkspace.default\-members\fR key in the root manifest. If this is not set, a virtual workspace will include all workspace members (equivalent to passing \fB\-\-workspace\fR), and a non\-virtual workspace will include only the root crate itself. .sp Selecting more than one package is unstable and available only on the \fInightly channel\fR and requires the \fB\-Z package\-workspace\fR flag to enable. See for more information. .sp \fB\-p\fR \fIspec\fR\[u2026], \fB\-\-package\fR \fIspec\fR\[u2026] .RS 4 Publish only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE Selecting more than one package with this option is unstable and available only on the [nightly channel](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html) and requires the `-Z package-workspace` flag to enable. See for more information. .sp \fB\-\-workspace\fR .RS 4 Publish all members in the workspace. .sp This option is unstable and available only on the \fInightly channel\fR and requires the \fB\-Z package\-workspace\fR flag to enable. See for more information. .RE .sp \fB\-\-exclude\fR \fISPEC\fR\[u2026] .RS 4 Exclude the specified packages. Must be used in conjunction with the \fB\-\-workspace\fR flag. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .sp This option is unstable and available only on the \fInightly channel\fR and requires the \fB\-Z package\-workspace\fR flag to enable. See for more information. .RE .SS "Compilation Options" .sp \fB\-\-target\fR \fItriple\fR .RS 4 Publish for the given architecture. The default is the host architecture. The general format of the triple is \fB\-\-\-\fR\&. Run \fBrustc \-\-print target\-list\fR for a list of supported targets. This flag may be specified multiple times. .sp This may also be specified with the \fBbuild.target\fR \fIconfig value\fR \&. .sp Note that specifying this flag makes Cargo run in a different mode where the target artifacts are placed in a separate directory. See the \fIbuild cache\fR documentation for more details. .RE .sp \fB\-\-target\-dir\fR \fIdirectory\fR .RS 4 Directory for all generated artifacts and intermediate files. May also be specified with the \fBCARGO_TARGET_DIR\fR environment variable, or the \fBbuild.target\-dir\fR \fIconfig value\fR \&. Defaults to \fBtarget\fR in the root of the workspace. .RE .SS "Feature Selection" The feature flags allow you to control which features are enabled. When no feature options are given, the \fBdefault\fR feature is activated for every selected package. .sp See \fIthe features documentation\fR for more details. .sp \fB\-F\fR \fIfeatures\fR, \fB\-\-features\fR \fIfeatures\fR .RS 4 Space or comma separated list of features to activate. Features of workspace members may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE .sp \fB\-\-all\-features\fR .RS 4 Activate all available features of all selected packages. .RE .sp \fB\-\-no\-default\-features\fR .RS 4 Do not activate the \fBdefault\fR feature of the selected packages. .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Miscellaneous Options" .sp \fB\-j\fR \fIN\fR, \fB\-\-jobs\fR \fIN\fR .RS 4 Number of parallel jobs to run. May also be specified with the \fBbuild.jobs\fR \fIconfig value\fR \&. 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 \fBdefault\fR is provided, it sets the value back to defaults. Should not be 0. .RE .sp \fB\-\-keep\-going\fR .RS 4 Build as many crates in the dependency graph as possible, rather than aborting the build on the first one that fails to build. .sp For example if the current package depends on dependencies \fBfails\fR and \fBworks\fR, one of which fails to build, \fBcargo publish \-j1\fR may or may not build the one that succeeds (depending on which one of the two builds Cargo picked to run first), whereas \fBcargo publish \-j1 \-\-keep\-going\fR would definitely run both builds, even if the one run first fails. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Publish the current package: .sp .RS 4 .nf cargo publish .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-package\fR(1), \fBcargo\-login\fR(1) cargo-0.86.0/src/etc/man/cargo-remove.1000064400000000000000000000157751046102023000156160ustar 00000000000000'\" t .TH "CARGO\-REMOVE" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-remove \[em] Remove dependencies from a Cargo.toml manifest file .SH "SYNOPSIS" \fBcargo remove\fR [\fIoptions\fR] \fIdependency\fR\[u2026] .SH "DESCRIPTION" Remove one or more dependencies from a \fBCargo.toml\fR manifest. .SH "OPTIONS" .SS "Section options" .sp \fB\-\-dev\fR .RS 4 Remove as a \fIdevelopment dependency\fR \&. .RE .sp \fB\-\-build\fR .RS 4 Remove as a \fIbuild dependency\fR \&. .RE .sp \fB\-\-target\fR \fItarget\fR .RS 4 Remove as a dependency to the \fIgiven target platform\fR \&. .sp To avoid unexpected shell expansions, you may use quotes around each target, e.g., \fB\-\-target 'cfg(unix)'\fR\&. .RE .SS "Miscellaneous Options" .sp \fB\-\-dry\-run\fR .RS 4 Don\[cq]t actually write to the manifest. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Package Selection" .sp \fB\-p\fR \fIspec\fR\[u2026], \fB\-\-package\fR \fIspec\fR\[u2026] .RS 4 Package to remove from. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Remove \fBregex\fR as a dependency .sp .RS 4 .nf cargo remove regex .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Remove \fBtrybuild\fR as a dev\-dependency .sp .RS 4 .nf cargo remove \-\-dev trybuild .fi .RE .RE .sp .RS 4 \h'-04' 3.\h'+01'Remove \fBnom\fR from the \fBx86_64\-pc\-windows\-gnu\fR dependencies table .sp .RS 4 .nf cargo remove \-\-target x86_64\-pc\-windows\-gnu nom .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-add\fR(1) cargo-0.86.0/src/etc/man/cargo-report.1000064400000000000000000000017511046102023000156210ustar 00000000000000'\" t .TH "CARGO\-REPORT" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-report \[em] Generate and display various kinds of reports .SH "SYNOPSIS" \fBcargo report\fR \fItype\fR [\fIoptions\fR] .SS "DESCRIPTION" Displays a report of the given \fItype\fR \[em] currently, only \fBfuture\-incompat\fR is supported .SH "OPTIONS" .sp \fB\-\-id\fR \fIid\fR .RS 4 Show the report with the specified Cargo\-generated id .RE .sp \fB\-p\fR \fIspec\fR\[u2026], \fB\-\-package\fR \fIspec\fR\[u2026] .RS 4 Only display a report for the specified package .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Display the latest future\-incompat report: .sp .RS 4 .nf cargo report future\-incompat .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Display the latest future\-incompat report for a specific package: .sp .RS 4 .nf cargo report future\-incompat \-\-package my\-dep:0.0.1 .fi .RE .RE .SH "SEE ALSO" \fIFuture incompat report\fR .sp \fBcargo\fR(1) cargo-0.86.0/src/etc/man/cargo-run.1000064400000000000000000000316231046102023000151130ustar 00000000000000'\" t .TH "CARGO\-RUN" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-run \[em] Run the current package .SH "SYNOPSIS" \fBcargo run\fR [\fIoptions\fR] [\fB\-\-\fR \fIargs\fR] .SH "DESCRIPTION" Run a binary or example of the local package. .sp All the arguments following the two dashes (\fB\-\-\fR) are passed to the binary to run. If you\[cq]re passing arguments to both Cargo and the binary, the ones after \fB\-\-\fR go to the binary, the ones before go to Cargo. .sp Unlike \fBcargo\-test\fR(1) and \fBcargo\-bench\fR(1), \fBcargo run\fR sets the working directory of the binary executed to the current working directory, same as if it was executed in the shell directly. .SH "OPTIONS" .SS "Package Selection" By default, the package in the current working directory is selected. The \fB\-p\fR flag can be used to choose a different package in a workspace. .sp \fB\-p\fR \fIspec\fR, \fB\-\-package\fR \fIspec\fR .RS 4 The package to run. See \fBcargo\-pkgid\fR(1) for the SPEC format. .RE .SS "Target Selection" When no target selection options are given, \fBcargo run\fR will run the binary target. If there are multiple binary targets, you must pass a target flag to choose one. Or, the \fBdefault\-run\fR field may be specified in the \fB[package]\fR section of \fBCargo.toml\fR to choose the name of the binary to run by default. .sp \fB\-\-bin\fR \fIname\fR .RS 4 Run the specified binary. .RE .sp \fB\-\-example\fR \fIname\fR .RS 4 Run the specified example. .RE .SS "Feature Selection" The feature flags allow you to control which features are enabled. When no feature options are given, the \fBdefault\fR feature is activated for every selected package. .sp See \fIthe features documentation\fR for more details. .sp \fB\-F\fR \fIfeatures\fR, \fB\-\-features\fR \fIfeatures\fR .RS 4 Space or comma separated list of features to activate. Features of workspace members may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE .sp \fB\-\-all\-features\fR .RS 4 Activate all available features of all selected packages. .RE .sp \fB\-\-no\-default\-features\fR .RS 4 Do not activate the \fBdefault\fR feature of the selected packages. .RE .SS "Compilation Options" .sp \fB\-\-target\fR \fItriple\fR .RS 4 Run for the given architecture. The default is the host architecture. The general format of the triple is \fB\-\-\-\fR\&. Run \fBrustc \-\-print target\-list\fR for a list of supported targets. .sp This may also be specified with the \fBbuild.target\fR \fIconfig value\fR \&. .sp Note that specifying this flag makes Cargo run in a different mode where the target artifacts are placed in a separate directory. See the \fIbuild cache\fR documentation for more details. .RE .sp \fB\-r\fR, \fB\-\-release\fR .RS 4 Run optimized artifacts with the \fBrelease\fR profile. See also the \fB\-\-profile\fR option for choosing a specific profile by name. .RE .sp \fB\-\-profile\fR \fIname\fR .RS 4 Run with the given profile. See \fIthe reference\fR for more details on profiles. .RE .sp \fB\-\-timings=\fR\fIfmts\fR .RS 4 Output information how long each compilation takes, and track concurrency information over time. Accepts an optional comma\-separated list of output formats; \fB\-\-timings\fR without an argument will default to \fB\-\-timings=html\fR\&. Specifying an output format (rather than the default) is unstable and requires \fB\-Zunstable\-options\fR\&. Valid output formats: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhtml\fR (unstable, requires \fB\-Zunstable\-options\fR): Write a human\-readable file \fBcargo\-timing.html\fR to the \fBtarget/cargo\-timings\fR directory with a report of the compilation. Also write a report to the same directory with a timestamp in the filename if you want to look at older runs. HTML output is suitable for human consumption only, and does not provide machine\-readable timing data. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR (unstable, requires \fB\-Zunstable\-options\fR): Emit machine\-readable JSON information about timing information. .RE .RE .SS "Output Options" .sp \fB\-\-target\-dir\fR \fIdirectory\fR .RS 4 Directory for all generated artifacts and intermediate files. May also be specified with the \fBCARGO_TARGET_DIR\fR environment variable, or the \fBbuild.target\-dir\fR \fIconfig value\fR \&. Defaults to \fBtarget\fR in the root of the workspace. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .sp \fB\-\-message\-format\fR \fIfmt\fR .RS 4 The output format for diagnostic messages. Can be specified multiple times and consists of comma\-separated values. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhuman\fR (default): Display in a human\-readable text format. Conflicts with \fBshort\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBshort\fR: Emit shorter, human\-readable text messages. Conflicts with \fBhuman\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR: Emit JSON messages to stdout. See \fIthe reference\fR for more details. Conflicts with \fBhuman\fR and \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-short\fR: Ensure the \fBrendered\fR field of JSON messages contains the \[lq]short\[rq] rendering from rustc. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-rendered\-ansi\fR: Ensure the \fBrendered\fR field of JSON messages contains embedded ANSI color codes for respecting rustc\[cq]s default color scheme. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-render\-diagnostics\fR: Instruct Cargo to not include rustc diagnostics in JSON messages printed, but instead Cargo itself should render the JSON diagnostics coming from rustc. Cargo\[cq]s own JSON diagnostics and others coming from rustc are still emitted. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-ignore\-rust\-version\fR .RS 4 Ignore \fBrust\-version\fR specification in packages. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SS "Miscellaneous Options" .sp \fB\-j\fR \fIN\fR, \fB\-\-jobs\fR \fIN\fR .RS 4 Number of parallel jobs to run. May also be specified with the \fBbuild.jobs\fR \fIconfig value\fR \&. 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 \fBdefault\fR is provided, it sets the value back to defaults. Should not be 0. .RE .sp \fB\-\-keep\-going\fR .RS 4 Build as many crates in the dependency graph as possible, rather than aborting the build on the first one that fails to build. .sp For example if the current package depends on dependencies \fBfails\fR and \fBworks\fR, one of which fails to build, \fBcargo run \-j1\fR may or may not build the one that succeeds (depending on which one of the two builds Cargo picked to run first), whereas \fBcargo run \-j1 \-\-keep\-going\fR would definitely run both builds, even if the one run first fails. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Build the local package and run its main target (assuming only one binary): .sp .RS 4 .nf cargo run .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Run an example with extra arguments: .sp .RS 4 .nf cargo run \-\-example exname \-\- \-\-exoption exarg1 exarg2 .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-build\fR(1) cargo-0.86.0/src/etc/man/cargo-rustc.1000064400000000000000000000435451046102023000154550ustar 00000000000000'\" t .TH "CARGO\-RUSTC" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-rustc \[em] Compile the current package, and pass extra options to the compiler .SH "SYNOPSIS" \fBcargo rustc\fR [\fIoptions\fR] [\fB\-\-\fR \fIargs\fR] .SH "DESCRIPTION" The specified target for the current package (or package specified by \fB\-p\fR if provided) will be compiled along with all of its dependencies. The specified \fIargs\fR will all be passed to the final compiler invocation, not any of the dependencies. Note that the compiler will still unconditionally receive arguments such as \fB\-L\fR, \fB\-\-extern\fR, and \fB\-\-crate\-type\fR, and the specified \fIargs\fR will simply be added to the compiler invocation. .sp See for documentation on rustc flags. .sp This command requires that only one target is being compiled when additional arguments are provided. If more than one target is available for the current package the filters of \fB\-\-lib\fR, \fB\-\-bin\fR, etc, must be used to select which target is compiled. .sp To pass flags to all compiler processes spawned by Cargo, use the \fBRUSTFLAGS\fR \fIenvironment variable\fR or the \fBbuild.rustflags\fR \fIconfig value\fR \&. .SH "OPTIONS" .SS "Package Selection" By default, the package in the current working directory is selected. The \fB\-p\fR flag can be used to choose a different package in a workspace. .sp \fB\-p\fR \fIspec\fR, \fB\-\-package\fR \fIspec\fR .RS 4 The package to build. See \fBcargo\-pkgid\fR(1) for the SPEC format. .RE .SS "Target Selection" When no target selection options are given, \fBcargo rustc\fR will build all binary and library targets of the selected package. .sp Binary targets are automatically built if there is an integration test or benchmark being selected to build. This allows an integration test to execute the binary to exercise and test its behavior. The \fBCARGO_BIN_EXE_\fR \fIenvironment variable\fR is set when the integration test is built so that it can use the \fI\f(BIenv\fI macro\fR to locate the executable. .sp Passing target selection flags will build only the specified targets. .sp Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each glob pattern. .sp \fB\-\-lib\fR .RS 4 Build the package\[cq]s library. .RE .sp \fB\-\-bin\fR \fIname\fR\[u2026] .RS 4 Build the specified binary. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-bins\fR .RS 4 Build all binary targets. .RE .sp \fB\-\-example\fR \fIname\fR\[u2026] .RS 4 Build the specified example. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-examples\fR .RS 4 Build all example targets. .RE .sp \fB\-\-test\fR \fIname\fR\[u2026] .RS 4 Build the specified integration test. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-tests\fR .RS 4 Build all targets that have the \fBtest = true\fR manifest flag set. By default this includes the library and binaries built as unittests, and integration tests. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a unittest, and once as a dependency for binaries, integration tests, etc.). Targets may be enabled or disabled by setting the \fBtest\fR flag in the manifest settings for the target. .RE .sp \fB\-\-bench\fR \fIname\fR\[u2026] .RS 4 Build the specified benchmark. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-benches\fR .RS 4 Build all targets that have the \fBbench = true\fR manifest flag set. By default this includes the library and binaries built as benchmarks, and bench targets. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a benchmark, and once as a dependency for binaries, benchmarks, etc.). Targets may be enabled or disabled by setting the \fBbench\fR flag in the manifest settings for the target. .RE .sp \fB\-\-all\-targets\fR .RS 4 Build all targets. This is equivalent to specifying \fB\-\-lib \-\-bins \-\-tests \-\-benches \-\-examples\fR\&. .RE .SS "Feature Selection" The feature flags allow you to control which features are enabled. When no feature options are given, the \fBdefault\fR feature is activated for every selected package. .sp See \fIthe features documentation\fR for more details. .sp \fB\-F\fR \fIfeatures\fR, \fB\-\-features\fR \fIfeatures\fR .RS 4 Space or comma separated list of features to activate. Features of workspace members may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE .sp \fB\-\-all\-features\fR .RS 4 Activate all available features of all selected packages. .RE .sp \fB\-\-no\-default\-features\fR .RS 4 Do not activate the \fBdefault\fR feature of the selected packages. .RE .SS "Compilation Options" .sp \fB\-\-target\fR \fItriple\fR .RS 4 Build for the given architecture. The default is the host architecture. The general format of the triple is \fB\-\-\-\fR\&. Run \fBrustc \-\-print target\-list\fR for a list of supported targets. This flag may be specified multiple times. .sp This may also be specified with the \fBbuild.target\fR \fIconfig value\fR \&. .sp Note that specifying this flag makes Cargo run in a different mode where the target artifacts are placed in a separate directory. See the \fIbuild cache\fR documentation for more details. .RE .sp \fB\-r\fR, \fB\-\-release\fR .RS 4 Build optimized artifacts with the \fBrelease\fR profile. See also the \fB\-\-profile\fR option for choosing a specific profile by name. .RE .sp \fB\-\-profile\fR \fIname\fR .RS 4 Build with the given profile. .sp The \fBrustc\fR subcommand will treat the following named profiles with special behaviors: .sp .RS 4 \h'-04'\(bu\h'+02'\fBcheck\fR \[em] Builds in the same way as the \fBcargo\-check\fR(1) command with the \fBdev\fR profile. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBtest\fR \[em] Builds in the same way as the \fBcargo\-test\fR(1) command, enabling building in test mode which will enable tests and enable the \fBtest\fR cfg option. See \fIrustc tests\fR for more detail. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBbench\fR \[em] Builds in the same was as the \fBcargo\-bench\fR(1) command, similar to the \fBtest\fR profile. .RE .sp See \fIthe reference\fR for more details on profiles. .RE .sp \fB\-\-timings=\fR\fIfmts\fR .RS 4 Output information how long each compilation takes, and track concurrency information over time. Accepts an optional comma\-separated list of output formats; \fB\-\-timings\fR without an argument will default to \fB\-\-timings=html\fR\&. Specifying an output format (rather than the default) is unstable and requires \fB\-Zunstable\-options\fR\&. Valid output formats: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhtml\fR (unstable, requires \fB\-Zunstable\-options\fR): Write a human\-readable file \fBcargo\-timing.html\fR to the \fBtarget/cargo\-timings\fR directory with a report of the compilation. Also write a report to the same directory with a timestamp in the filename if you want to look at older runs. HTML output is suitable for human consumption only, and does not provide machine\-readable timing data. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR (unstable, requires \fB\-Zunstable\-options\fR): Emit machine\-readable JSON information about timing information. .RE .RE .sp \fB\-\-crate\-type\fR \fIcrate\-type\fR .RS 4 Build for the given crate type. This flag accepts a comma\-separated list of 1 or more crate types, of which the allowed values are the same as \fBcrate\-type\fR field in the manifest for configuring a Cargo target. See \fI\f(BIcrate\-type\fI field\fR for possible values. .sp If the manifest contains a list, and \fB\-\-crate\-type\fR is provided, the command\-line argument value will override what is in the manifest. .sp This flag only works when building a \fBlib\fR or \fBexample\fR library target. .RE .SS "Output Options" .sp \fB\-\-target\-dir\fR \fIdirectory\fR .RS 4 Directory for all generated artifacts and intermediate files. May also be specified with the \fBCARGO_TARGET_DIR\fR environment variable, or the \fBbuild.target\-dir\fR \fIconfig value\fR \&. Defaults to \fBtarget\fR in the root of the workspace. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .sp \fB\-\-message\-format\fR \fIfmt\fR .RS 4 The output format for diagnostic messages. Can be specified multiple times and consists of comma\-separated values. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhuman\fR (default): Display in a human\-readable text format. Conflicts with \fBshort\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBshort\fR: Emit shorter, human\-readable text messages. Conflicts with \fBhuman\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR: Emit JSON messages to stdout. See \fIthe reference\fR for more details. Conflicts with \fBhuman\fR and \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-short\fR: Ensure the \fBrendered\fR field of JSON messages contains the \[lq]short\[rq] rendering from rustc. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-rendered\-ansi\fR: Ensure the \fBrendered\fR field of JSON messages contains embedded ANSI color codes for respecting rustc\[cq]s default color scheme. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-render\-diagnostics\fR: Instruct Cargo to not include rustc diagnostics in JSON messages printed, but instead Cargo itself should render the JSON diagnostics coming from rustc. Cargo\[cq]s own JSON diagnostics and others coming from rustc are still emitted. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-ignore\-rust\-version\fR .RS 4 Ignore \fBrust\-version\fR specification in packages. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SS "Miscellaneous Options" .sp \fB\-j\fR \fIN\fR, \fB\-\-jobs\fR \fIN\fR .RS 4 Number of parallel jobs to run. May also be specified with the \fBbuild.jobs\fR \fIconfig value\fR \&. 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 \fBdefault\fR is provided, it sets the value back to defaults. Should not be 0. .RE .sp \fB\-\-keep\-going\fR .RS 4 Build as many crates in the dependency graph as possible, rather than aborting the build on the first one that fails to build. .sp For example if the current package depends on dependencies \fBfails\fR and \fBworks\fR, one of which fails to build, \fBcargo rustc \-j1\fR may or may not build the one that succeeds (depending on which one of the two builds Cargo picked to run first), whereas \fBcargo rustc \-j1 \-\-keep\-going\fR would definitely run both builds, even if the one run first fails. .RE .sp \fB\-\-future\-incompat\-report\fR .RS 4 Displays a future\-incompat report for any future\-incompatible warnings produced during execution of this command .sp See \fBcargo\-report\fR(1) .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Check if your package (not including dependencies) uses unsafe code: .sp .RS 4 .nf cargo rustc \-\-lib \-\- \-D unsafe\-code .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Try an experimental flag on the nightly compiler, such as this which prints the size of every type: .sp .RS 4 .nf cargo rustc \-\-lib \-\- \-Z print\-type\-sizes .fi .RE .RE .sp .RS 4 \h'-04' 3.\h'+01'Override \fBcrate\-type\fR field in Cargo.toml with command\-line option: .sp .RS 4 .nf cargo rustc \-\-lib \-\-crate\-type lib,cdylib .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-build\fR(1), \fBrustc\fR(1) cargo-0.86.0/src/etc/man/cargo-rustdoc.1000064400000000000000000000410661046102023000157740ustar 00000000000000'\" t .TH "CARGO\-RUSTDOC" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-rustdoc \[em] Build a package\[cq]s documentation, using specified custom flags .SH "SYNOPSIS" \fBcargo rustdoc\fR [\fIoptions\fR] [\fB\-\-\fR \fIargs\fR] .SH "DESCRIPTION" The specified target for the current package (or package specified by \fB\-p\fR if provided) will be documented with the specified \fIargs\fR being passed to the final rustdoc invocation. Dependencies will not be documented as part of this command. Note that rustdoc will still unconditionally receive arguments such as \fB\-L\fR, \fB\-\-extern\fR, and \fB\-\-crate\-type\fR, and the specified \fIargs\fR will simply be added to the rustdoc invocation. .sp See for documentation on rustdoc flags. .sp This command requires that only one target is being compiled when additional arguments are provided. If more than one target is available for the current package the filters of \fB\-\-lib\fR, \fB\-\-bin\fR, etc, must be used to select which target is compiled. .sp To pass flags to all rustdoc processes spawned by Cargo, use the \fBRUSTDOCFLAGS\fR \fIenvironment variable\fR or the \fBbuild.rustdocflags\fR \fIconfig value\fR \&. .SH "OPTIONS" .SS "Documentation Options" .sp \fB\-\-open\fR .RS 4 Open the docs in a browser after building them. This will use your default browser unless you define another one in the \fBBROWSER\fR environment variable or use the \fI\f(BIdoc.browser\fI\fR configuration option. .RE .SS "Package Selection" By default, the package in the current working directory is selected. The \fB\-p\fR flag can be used to choose a different package in a workspace. .sp \fB\-p\fR \fIspec\fR, \fB\-\-package\fR \fIspec\fR .RS 4 The package to document. See \fBcargo\-pkgid\fR(1) for the SPEC format. .RE .SS "Target Selection" When no target selection options are given, \fBcargo rustdoc\fR will document all binary and library targets of the selected package. The binary will be skipped if its name is the same as the lib target. Binaries are skipped if they have \fBrequired\-features\fR that are missing. .sp Passing target selection flags will document only the specified targets. .sp Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each glob pattern. .sp \fB\-\-lib\fR .RS 4 Document the package\[cq]s library. .RE .sp \fB\-\-bin\fR \fIname\fR\[u2026] .RS 4 Document the specified binary. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-bins\fR .RS 4 Document all binary targets. .RE .sp \fB\-\-example\fR \fIname\fR\[u2026] .RS 4 Document the specified example. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-examples\fR .RS 4 Document all example targets. .RE .sp \fB\-\-test\fR \fIname\fR\[u2026] .RS 4 Document the specified integration test. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-tests\fR .RS 4 Document all targets that have the \fBtest = true\fR manifest flag set. By default this includes the library and binaries built as unittests, and integration tests. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a unittest, and once as a dependency for binaries, integration tests, etc.). Targets may be enabled or disabled by setting the \fBtest\fR flag in the manifest settings for the target. .RE .sp \fB\-\-bench\fR \fIname\fR\[u2026] .RS 4 Document the specified benchmark. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-benches\fR .RS 4 Document all targets that have the \fBbench = true\fR manifest flag set. By default this includes the library and binaries built as benchmarks, and bench targets. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a benchmark, and once as a dependency for binaries, benchmarks, etc.). Targets may be enabled or disabled by setting the \fBbench\fR flag in the manifest settings for the target. .RE .sp \fB\-\-all\-targets\fR .RS 4 Document all targets. This is equivalent to specifying \fB\-\-lib \-\-bins \-\-tests \-\-benches \-\-examples\fR\&. .RE .SS "Feature Selection" The feature flags allow you to control which features are enabled. When no feature options are given, the \fBdefault\fR feature is activated for every selected package. .sp See \fIthe features documentation\fR for more details. .sp \fB\-F\fR \fIfeatures\fR, \fB\-\-features\fR \fIfeatures\fR .RS 4 Space or comma separated list of features to activate. Features of workspace members may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE .sp \fB\-\-all\-features\fR .RS 4 Activate all available features of all selected packages. .RE .sp \fB\-\-no\-default\-features\fR .RS 4 Do not activate the \fBdefault\fR feature of the selected packages. .RE .SS "Compilation Options" .sp \fB\-\-target\fR \fItriple\fR .RS 4 Document for the given architecture. The default is the host architecture. The general format of the triple is \fB\-\-\-\fR\&. Run \fBrustc \-\-print target\-list\fR for a list of supported targets. This flag may be specified multiple times. .sp This may also be specified with the \fBbuild.target\fR \fIconfig value\fR \&. .sp Note that specifying this flag makes Cargo run in a different mode where the target artifacts are placed in a separate directory. See the \fIbuild cache\fR documentation for more details. .RE .sp \fB\-r\fR, \fB\-\-release\fR .RS 4 Document optimized artifacts with the \fBrelease\fR profile. See also the \fB\-\-profile\fR option for choosing a specific profile by name. .RE .sp \fB\-\-profile\fR \fIname\fR .RS 4 Document with the given profile. See \fIthe reference\fR for more details on profiles. .RE .sp \fB\-\-timings=\fR\fIfmts\fR .RS 4 Output information how long each compilation takes, and track concurrency information over time. Accepts an optional comma\-separated list of output formats; \fB\-\-timings\fR without an argument will default to \fB\-\-timings=html\fR\&. Specifying an output format (rather than the default) is unstable and requires \fB\-Zunstable\-options\fR\&. Valid output formats: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhtml\fR (unstable, requires \fB\-Zunstable\-options\fR): Write a human\-readable file \fBcargo\-timing.html\fR to the \fBtarget/cargo\-timings\fR directory with a report of the compilation. Also write a report to the same directory with a timestamp in the filename if you want to look at older runs. HTML output is suitable for human consumption only, and does not provide machine\-readable timing data. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR (unstable, requires \fB\-Zunstable\-options\fR): Emit machine\-readable JSON information about timing information. .RE .RE .SS "Output Options" .sp \fB\-\-target\-dir\fR \fIdirectory\fR .RS 4 Directory for all generated artifacts and intermediate files. May also be specified with the \fBCARGO_TARGET_DIR\fR environment variable, or the \fBbuild.target\-dir\fR \fIconfig value\fR \&. Defaults to \fBtarget\fR in the root of the workspace. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .sp \fB\-\-message\-format\fR \fIfmt\fR .RS 4 The output format for diagnostic messages. Can be specified multiple times and consists of comma\-separated values. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhuman\fR (default): Display in a human\-readable text format. Conflicts with \fBshort\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBshort\fR: Emit shorter, human\-readable text messages. Conflicts with \fBhuman\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR: Emit JSON messages to stdout. See \fIthe reference\fR for more details. Conflicts with \fBhuman\fR and \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-short\fR: Ensure the \fBrendered\fR field of JSON messages contains the \[lq]short\[rq] rendering from rustc. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-rendered\-ansi\fR: Ensure the \fBrendered\fR field of JSON messages contains embedded ANSI color codes for respecting rustc\[cq]s default color scheme. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-render\-diagnostics\fR: Instruct Cargo to not include rustc diagnostics in JSON messages printed, but instead Cargo itself should render the JSON diagnostics coming from rustc. Cargo\[cq]s own JSON diagnostics and others coming from rustc are still emitted. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-ignore\-rust\-version\fR .RS 4 Ignore \fBrust\-version\fR specification in packages. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SS "Miscellaneous Options" .sp \fB\-j\fR \fIN\fR, \fB\-\-jobs\fR \fIN\fR .RS 4 Number of parallel jobs to run. May also be specified with the \fBbuild.jobs\fR \fIconfig value\fR \&. 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 \fBdefault\fR is provided, it sets the value back to defaults. Should not be 0. .RE .sp \fB\-\-keep\-going\fR .RS 4 Build as many crates in the dependency graph as possible, rather than aborting the build on the first one that fails to build. .sp For example if the current package depends on dependencies \fBfails\fR and \fBworks\fR, one of which fails to build, \fBcargo rustdoc \-j1\fR may or may not build the one that succeeds (depending on which one of the two builds Cargo picked to run first), whereas \fBcargo rustdoc \-j1 \-\-keep\-going\fR would definitely run both builds, even if the one run first fails. .RE .sp \fB\-\-output\-format\fR .RS 4 The output type for the documentation emitted. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhtml\fR (default): Emit the documentation in HTML format. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR: Emit the documentation in the \fIexperimental JSON format\fR \&. .RE .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Build documentation with custom CSS included from a given file: .sp .RS 4 .nf cargo rustdoc \-\-lib \-\- \-\-extend\-css extra.css .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-doc\fR(1), \fBrustdoc\fR(1) cargo-0.86.0/src/etc/man/cargo-search.1000064400000000000000000000101501046102023000155440ustar 00000000000000'\" t .TH "CARGO\-SEARCH" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-search \[em] Search packages in the registry. Default registry is crates.io .SH "SYNOPSIS" \fBcargo search\fR [\fIoptions\fR] [\fIquery\fR\[u2026]] .SH "DESCRIPTION" This performs a textual search for crates on \&. The matching crates will be displayed along with their description in TOML format suitable for copying into a \fBCargo.toml\fR manifest. .SH "OPTIONS" .SS "Search Options" .sp \fB\-\-limit\fR \fIlimit\fR .RS 4 Limit the number of results (default: 10, max: 100). .RE .sp \fB\-\-index\fR \fIindex\fR .RS 4 The URL of the registry index to use. .RE .sp \fB\-\-registry\fR \fIregistry\fR .RS 4 Name of the registry to use. Registry names are defined in \fICargo config files\fR \&. If not specified, the default registry is used, which is defined by the \fBregistry.default\fR config key which defaults to \fBcrates\-io\fR\&. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Search for a package from crates.io: .sp .RS 4 .nf cargo search serde .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-install\fR(1), \fBcargo\-publish\fR(1) cargo-0.86.0/src/etc/man/cargo-test.1000064400000000000000000000542771046102023000153000ustar 00000000000000'\" t .TH "CARGO\-TEST" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-test \[em] Execute unit and integration tests of a package .SH "SYNOPSIS" \fBcargo test\fR [\fIoptions\fR] [\fItestname\fR] [\fB\-\-\fR \fItest\-options\fR] .SH "DESCRIPTION" Compile and execute unit, integration, and documentation tests. .sp The test filtering argument \fBTESTNAME\fR and all the arguments following the two dashes (\fB\-\-\fR) are passed to the test binaries and thus to \fIlibtest\fR (rustc\[cq]s built in unit\-test and micro\-benchmarking framework). If you\[cq]re passing arguments to both Cargo and the binary, the ones after \fB\-\-\fR go to the binary, the ones before go to Cargo. For details about libtest\[cq]s arguments see the output of \fBcargo test \-\- \-\-help\fR and check out the rustc book\[cq]s chapter on how tests work at \&. .sp As an example, this will filter for tests with \fBfoo\fR in their name and run them on 3 threads in parallel: .sp .RS 4 .nf cargo test foo \-\- \-\-test\-threads 3 .fi .RE .sp Tests are built with the \fB\-\-test\fR option to \fBrustc\fR which creates a special executable by linking your code with libtest. The executable automatically runs all functions annotated with the \fB#[test]\fR attribute in multiple threads. \fB#[bench]\fR annotated functions will also be run with one iteration to verify that they are functional. .sp If the package contains multiple test targets, each target compiles to a special executable as aforementioned, and then is run serially. .sp The libtest harness may be disabled by setting \fBharness = false\fR in the target manifest settings, in which case your code will need to provide its own \fBmain\fR function to handle running tests. .SS "Documentation tests" Documentation tests are also run by default, which is handled by \fBrustdoc\fR\&. It extracts code samples from documentation comments of the library target, and then executes them. .sp Different from normal test targets, each code block compiles to a doctest executable on the fly with \fBrustc\fR\&. These executables run in parallel in separate processes. The compilation of a code block is in fact a part of test function controlled by libtest, so some options such as \fB\-\-jobs\fR might not take effect. Note that this execution model of doctests is not guaranteed and may change in the future; beware of depending on it. .sp See the \fIrustdoc book\fR for more information on writing doc tests. .SS "Working directory of tests" 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 \fB\-\-no\-run\fR .RS 4 Compile, but don\[cq]t run tests. .RE .sp \fB\-\-no\-fail\-fast\fR .RS 4 Run all tests regardless of failure. Without this flag, Cargo will exit after the first executable fails. The Rust test harness will run all tests within the executable to completion, this flag only applies to the executable as a whole. .RE .SS "Package Selection" By default, when no package selection options are given, the packages selected depend on the selected manifest file (based on the current working directory if \fB\-\-manifest\-path\fR is not given). If the manifest is the root of a workspace then the workspaces default members are selected, otherwise only the package defined by the manifest will be selected. .sp The default members of a workspace can be set explicitly with the \fBworkspace.default\-members\fR key in the root manifest. If this is not set, a virtual workspace will include all workspace members (equivalent to passing \fB\-\-workspace\fR), and a non\-virtual workspace will include only the root crate itself. .sp \fB\-p\fR \fIspec\fR\[u2026], \fB\-\-package\fR \fIspec\fR\[u2026] .RS 4 Test only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .sp \fB\-\-workspace\fR .RS 4 Test all members in the workspace. .RE .sp \fB\-\-all\fR .RS 4 Deprecated alias for \fB\-\-workspace\fR\&. .RE .sp \fB\-\-exclude\fR \fISPEC\fR\[u2026] .RS 4 Exclude the specified packages. Must be used in conjunction with the \fB\-\-workspace\fR flag. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .SS "Target Selection" When no target selection options are given, \fBcargo test\fR will build the following targets of the selected packages: .sp .RS 4 \h'-04'\(bu\h'+02'lib \[em] used to link with binaries, examples, integration tests, and doc tests .RE .sp .RS 4 \h'-04'\(bu\h'+02'bins (only if integration tests are built and required features are available) .RE .sp .RS 4 \h'-04'\(bu\h'+02'examples \[em] to ensure they compile .RE .sp .RS 4 \h'-04'\(bu\h'+02'lib as a unit test .RE .sp .RS 4 \h'-04'\(bu\h'+02'bins as unit tests .RE .sp .RS 4 \h'-04'\(bu\h'+02'integration tests .RE .sp .RS 4 \h'-04'\(bu\h'+02'doc tests for the lib target .RE .sp The default behavior can be changed by setting the \fBtest\fR flag for the target in the manifest settings. Setting examples to \fBtest = true\fR will build and run the example as a test, replacing the example\[cq]s \fBmain\fR function with the libtest harness. If you don\[cq]t want the \fBmain\fR function replaced, also include \fBharness = false\fR, in which case the example will be built and executed as\-is. .sp Setting targets to \fBtest = false\fR will stop them from being tested by default. Target selection options that take a target by name (such as \fB\-\-example foo\fR) ignore the \fBtest\fR flag and will always test the given target. .sp Doc tests for libraries may be disabled by setting \fBdoctest = false\fR for the library in the manifest. .sp See \fIConfiguring a target\fR for more information on per\-target settings. .sp Binary targets are automatically built if there is an integration test or benchmark being selected to test. This allows an integration test to execute the binary to exercise and test its behavior. The \fBCARGO_BIN_EXE_\fR \fIenvironment variable\fR is set when the integration test is built so that it can use the \fI\f(BIenv\fI macro\fR to locate the executable. .sp Passing target selection flags will test only the specified targets. .sp Note that \fB\-\-bin\fR, \fB\-\-example\fR, \fB\-\-test\fR and \fB\-\-bench\fR flags also support common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each glob pattern. .sp \fB\-\-lib\fR .RS 4 Test the package\[cq]s library. .RE .sp \fB\-\-bin\fR \fIname\fR\[u2026] .RS 4 Test the specified binary. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-bins\fR .RS 4 Test all binary targets. .RE .sp \fB\-\-example\fR \fIname\fR\[u2026] .RS 4 Test the specified example. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-examples\fR .RS 4 Test all example targets. .RE .sp \fB\-\-test\fR \fIname\fR\[u2026] .RS 4 Test the specified integration test. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-tests\fR .RS 4 Test all targets that have the \fBtest = true\fR manifest flag set. By default this includes the library and binaries built as unittests, and integration tests. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a unittest, and once as a dependency for binaries, integration tests, etc.). Targets may be enabled or disabled by setting the \fBtest\fR flag in the manifest settings for the target. .RE .sp \fB\-\-bench\fR \fIname\fR\[u2026] .RS 4 Test the specified benchmark. This flag may be specified multiple times and supports common Unix glob patterns. .RE .sp \fB\-\-benches\fR .RS 4 Test all targets that have the \fBbench = true\fR manifest flag set. By default this includes the library and binaries built as benchmarks, and bench targets. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a benchmark, and once as a dependency for binaries, benchmarks, etc.). Targets may be enabled or disabled by setting the \fBbench\fR flag in the manifest settings for the target. .RE .sp \fB\-\-all\-targets\fR .RS 4 Test all targets. This is equivalent to specifying \fB\-\-lib \-\-bins \-\-tests \-\-benches \-\-examples\fR\&. .RE .sp \fB\-\-doc\fR .RS 4 Test only the library\[cq]s documentation. This cannot be mixed with other target options. .RE .SS "Feature Selection" The feature flags allow you to control which features are enabled. When no feature options are given, the \fBdefault\fR feature is activated for every selected package. .sp See \fIthe features documentation\fR for more details. .sp \fB\-F\fR \fIfeatures\fR, \fB\-\-features\fR \fIfeatures\fR .RS 4 Space or comma separated list of features to activate. Features of workspace members may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE .sp \fB\-\-all\-features\fR .RS 4 Activate all available features of all selected packages. .RE .sp \fB\-\-no\-default\-features\fR .RS 4 Do not activate the \fBdefault\fR feature of the selected packages. .RE .SS "Compilation Options" .sp \fB\-\-target\fR \fItriple\fR .RS 4 Test for the given architecture. The default is the host architecture. The general format of the triple is \fB\-\-\-\fR\&. Run \fBrustc \-\-print target\-list\fR for a list of supported targets. This flag may be specified multiple times. .sp This may also be specified with the \fBbuild.target\fR \fIconfig value\fR \&. .sp Note that specifying this flag makes Cargo run in a different mode where the target artifacts are placed in a separate directory. See the \fIbuild cache\fR documentation for more details. .RE .sp \fB\-r\fR, \fB\-\-release\fR .RS 4 Test optimized artifacts with the \fBrelease\fR profile. See also the \fB\-\-profile\fR option for choosing a specific profile by name. .RE .sp \fB\-\-profile\fR \fIname\fR .RS 4 Test with the given profile. See \fIthe reference\fR for more details on profiles. .RE .sp \fB\-\-timings=\fR\fIfmts\fR .RS 4 Output information how long each compilation takes, and track concurrency information over time. Accepts an optional comma\-separated list of output formats; \fB\-\-timings\fR without an argument will default to \fB\-\-timings=html\fR\&. Specifying an output format (rather than the default) is unstable and requires \fB\-Zunstable\-options\fR\&. Valid output formats: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhtml\fR (unstable, requires \fB\-Zunstable\-options\fR): Write a human\-readable file \fBcargo\-timing.html\fR to the \fBtarget/cargo\-timings\fR directory with a report of the compilation. Also write a report to the same directory with a timestamp in the filename if you want to look at older runs. HTML output is suitable for human consumption only, and does not provide machine\-readable timing data. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR (unstable, requires \fB\-Zunstable\-options\fR): Emit machine\-readable JSON information about timing information. .RE .RE .SS "Output Options" .sp \fB\-\-target\-dir\fR \fIdirectory\fR .RS 4 Directory for all generated artifacts and intermediate files. May also be specified with the \fBCARGO_TARGET_DIR\fR environment variable, or the \fBbuild.target\-dir\fR \fIconfig value\fR \&. Defaults to \fBtarget\fR in the root of the workspace. .RE .SS "Display Options" By default the Rust test harness hides output from test execution to keep results readable. Test output can be recovered (e.g., for debugging) by passing \fB\-\-nocapture\fR to the test binaries: .sp .RS 4 .nf cargo test \-\- \-\-nocapture .fi .RE .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .sp \fB\-\-message\-format\fR \fIfmt\fR .RS 4 The output format for diagnostic messages. Can be specified multiple times and consists of comma\-separated values. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBhuman\fR (default): Display in a human\-readable text format. Conflicts with \fBshort\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBshort\fR: Emit shorter, human\-readable text messages. Conflicts with \fBhuman\fR and \fBjson\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\fR: Emit JSON messages to stdout. See \fIthe reference\fR for more details. Conflicts with \fBhuman\fR and \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-short\fR: Ensure the \fBrendered\fR field of JSON messages contains the \[lq]short\[rq] rendering from rustc. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-diagnostic\-rendered\-ansi\fR: Ensure the \fBrendered\fR field of JSON messages contains embedded ANSI color codes for respecting rustc\[cq]s default color scheme. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBjson\-render\-diagnostics\fR: Instruct Cargo to not include rustc diagnostics in JSON messages printed, but instead Cargo itself should render the JSON diagnostics coming from rustc. Cargo\[cq]s own JSON diagnostics and others coming from rustc are still emitted. Cannot be used with \fBhuman\fR or \fBshort\fR\&. .RE .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-ignore\-rust\-version\fR .RS 4 Ignore \fBrust\-version\fR specification in packages. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SS "Miscellaneous Options" The \fB\-\-jobs\fR argument affects the building of the test executable but does not affect how many threads are used when running the tests. The Rust test harness includes an option to control the number of threads used: .sp .RS 4 .nf cargo test \-j 2 \-\- \-\-test\-threads=2 .fi .RE .sp \fB\-j\fR \fIN\fR, \fB\-\-jobs\fR \fIN\fR .RS 4 Number of parallel jobs to run. May also be specified with the \fBbuild.jobs\fR \fIconfig value\fR \&. 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 \fBdefault\fR is provided, it sets the value back to defaults. Should not be 0. .RE .sp \fB\-\-future\-incompat\-report\fR .RS 4 Displays a future\-incompat report for any future\-incompatible warnings produced during execution of this command .sp See \fBcargo\-report\fR(1) .RE .sp While \fBcargo test\fR involves compilation, it does not provide a \fB\-\-keep\-going\fR flag. Use \fB\-\-no\-fail\-fast\fR to run as many tests as possible without stopping at the first failure. To \[lq]compile\[rq] as many tests as possible, use \fB\-\-tests\fR to build test binaries separately. For example: .sp .RS 4 .nf cargo build \-\-tests \-\-keep\-going cargo test \-\-tests \-\-no\-fail\-fast .fi .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Execute all the unit and integration tests of the current package: .sp .RS 4 .nf cargo test .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Run only tests whose names match against a filter string: .sp .RS 4 .nf cargo test name_filter .fi .RE .RE .sp .RS 4 \h'-04' 3.\h'+01'Run only a specific test within a specific integration test: .sp .RS 4 .nf cargo test \-\-test int_test_name \-\- modname::test_name .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-bench\fR(1), \fItypes of tests\fR , \fIhow to write tests\fR cargo-0.86.0/src/etc/man/cargo-tree.1000064400000000000000000000427001046102023000152440ustar 00000000000000'\" t .TH "CARGO\-TREE" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-tree \[em] Display a tree visualization of a dependency graph .SH "SYNOPSIS" \fBcargo tree\fR [\fIoptions\fR] .SH "DESCRIPTION" This command will display a tree of dependencies to the terminal. An example of a simple project that depends on the \[lq]rand\[rq] package: .sp .RS 4 .nf myproject v0.1.0 (/myproject) `\-\- rand v0.7.3 |\-\- getrandom v0.1.14 | |\-\- cfg\-if v0.1.10 | `\-\- libc v0.2.68 |\-\- libc v0.2.68 (*) |\-\- rand_chacha v0.2.2 | |\-\- ppv\-lite86 v0.2.6 | `\-\- rand_core v0.5.1 | `\-\- getrandom v0.1.14 (*) `\-\- rand_core v0.5.1 (*) [build\-dependencies] `\-\- cc v1.0.50 .fi .RE .sp Packages marked with \fB(*)\fR have been \[lq]de\-duplicated\[rq]\&. The dependencies for the package have already been shown elsewhere in the graph, and so are not repeated. Use the \fB\-\-no\-dedupe\fR option to repeat the duplicates. .sp The \fB\-e\fR flag can be used to select the dependency kinds to display. The \[lq]features\[rq] kind changes the output to display the features enabled by each dependency. For example, \fBcargo tree \-e features\fR: .sp .RS 4 .nf myproject v0.1.0 (/myproject) `\-\- log feature "serde" `\-\- log v0.4.8 |\-\- serde v1.0.106 `\-\- cfg\-if feature "default" `\-\- cfg\-if v0.1.10 .fi .RE .sp In this tree, \fBmyproject\fR depends on \fBlog\fR with the \fBserde\fR feature. \fBlog\fR in turn depends on \fBcfg\-if\fR with \[lq]default\[rq] features. When using \fB\-e features\fR it can be helpful to use \fB\-i\fR flag to show how the features flow into a package. See the examples below for more detail. .SS "Feature Unification" This command shows a graph much closer to a feature\-unified graph Cargo will build, rather than what you list in \fBCargo.toml\fR\&. For instance, if you specify the same dependency in both \fB[dependencies]\fR and \fB[dev\-dependencies]\fR but with different features on. This command may merge all features and show a \fB(*)\fR on one of the dependency to indicate the duplicate. .sp As a result, for a mostly equivalent overview of what \fBcargo build\fR does, \fBcargo tree \-e normal,build\fR is pretty close; for a mostly equivalent overview of what \fBcargo test\fR does, \fBcargo tree\fR is pretty close. However, it doesn\[cq]t guarantee the exact equivalence to what Cargo is going to build, since a compilation is complex and depends on lots of different factors. .sp To learn more about feature unification, check out this \fIdedicated section\fR \&. .SH "OPTIONS" .SS "Tree Options" .sp \fB\-i\fR \fIspec\fR, \fB\-\-invert\fR \fIspec\fR .RS 4 Show the reverse dependencies for the given package. This flag will invert the tree and display the packages that depend on the given package. .sp Note that in a workspace, by default it will only display the package\[cq]s reverse dependencies inside the tree of the workspace member in the current directory. The \fB\-\-workspace\fR flag can be used to extend it so that it will show the package\[cq]s reverse dependencies across the entire workspace. The \fB\-p\fR flag can be used to display the package\[cq]s reverse dependencies only with the subtree of the package given to \fB\-p\fR\&. .RE .sp \fB\-\-prune\fR \fIspec\fR .RS 4 Prune the given package from the display of the dependency tree. .RE .sp \fB\-\-depth\fR \fIdepth\fR .RS 4 Maximum display depth of the dependency tree. A depth of 1 displays the direct dependencies, for example. .sp If the given value is \fBworkspace\fR, only shows the dependencies that are member of the current workspace, instead. .RE .sp \fB\-\-no\-dedupe\fR .RS 4 Do not de\-duplicate repeated dependencies. Usually, when a package has already displayed its dependencies, further occurrences will not re\-display its dependencies, and will include a \fB(*)\fR to indicate it has already been shown. This flag will cause those duplicates to be repeated. .RE .sp \fB\-d\fR, \fB\-\-duplicates\fR .RS 4 Show only dependencies which come in multiple versions (implies \fB\-\-invert\fR). When used with the \fB\-p\fR flag, only shows duplicates within the subtree of the given package. .sp It can be beneficial for build times and executable sizes to avoid building that same package multiple times. This flag can help identify the offending packages. You can then investigate if the package that depends on the duplicate with the older version can be updated to the newer version so that only one instance is built. .RE .sp \fB\-e\fR \fIkinds\fR, \fB\-\-edges\fR \fIkinds\fR .RS 4 The dependency kinds to display. Takes a comma separated list of values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBall\fR \[em] Show all edge kinds. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnormal\fR \[em] Show normal dependencies. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBbuild\fR \[em] Show build dependencies. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBdev\fR \[em] Show development dependencies. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBfeatures\fR \[em] Show features enabled by each dependency. If this is the only kind given, then it will automatically include the other dependency kinds. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBno\-normal\fR \[em] Do not include normal dependencies. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBno\-build\fR \[em] Do not include build dependencies. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBno\-dev\fR \[em] Do not include development dependencies. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBno\-proc\-macro\fR \[em] Do not include procedural macro dependencies. .RE .sp The \fBnormal\fR, \fBbuild\fR, \fBdev\fR, and \fBall\fR dependency kinds cannot be mixed with \fBno\-normal\fR, \fBno\-build\fR, or \fBno\-dev\fR dependency kinds. .sp The default is \fBnormal,build,dev\fR\&. .RE .sp \fB\-\-target\fR \fItriple\fR .RS 4 Filter dependencies matching the given \fItarget triple\fR \&. The default is the host platform. Use the value \fBall\fR to include \fIall\fR targets. .RE .SS "Tree Formatting Options" .sp \fB\-\-charset\fR \fIcharset\fR .RS 4 Chooses the character set to use for the tree. Valid values are \[lq]utf8\[rq] or \[lq]ascii\[rq]\&. When unspecified, cargo will auto\-select a value. .RE .sp \fB\-f\fR \fIformat\fR, \fB\-\-format\fR \fIformat\fR .RS 4 Set the format string for each package. The default is \[lq]{p}\[rq]\&. .sp This is an arbitrary string which will be used to display each package. The following strings will be replaced with the corresponding value: .sp .RS 4 \h'-04'\(bu\h'+02'\fB{p}\fR \[em] The package name. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB{l}\fR \[em] The package license. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB{r}\fR \[em] The package repository URL. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB{f}\fR \[em] Comma\-separated list of package features that are enabled. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB{lib}\fR \[em] The name, as used in a \fBuse\fR statement, of the package\[cq]s library. .RE .RE .sp \fB\-\-prefix\fR \fIprefix\fR .RS 4 Sets how each line is displayed. The \fIprefix\fR value can be one of: .sp .RS 4 \h'-04'\(bu\h'+02'\fBindent\fR (default) \[em] Shows each line indented as a tree. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBdepth\fR \[em] Show as a list, with the numeric depth printed before each entry. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnone\fR \[em] Show as a flat list. .RE .RE .SS "Package Selection" By default, when no package selection options are given, the packages selected depend on the selected manifest file (based on the current working directory if \fB\-\-manifest\-path\fR is not given). If the manifest is the root of a workspace then the workspaces default members are selected, otherwise only the package defined by the manifest will be selected. .sp The default members of a workspace can be set explicitly with the \fBworkspace.default\-members\fR key in the root manifest. If this is not set, a virtual workspace will include all workspace members (equivalent to passing \fB\-\-workspace\fR), and a non\-virtual workspace will include only the root crate itself. .sp \fB\-p\fR \fIspec\fR\[u2026], \fB\-\-package\fR \fIspec\fR\[u2026] .RS 4 Display only the specified packages. See \fBcargo\-pkgid\fR(1) for the SPEC format. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .sp \fB\-\-workspace\fR .RS 4 Display all members in the workspace. .RE .sp \fB\-\-exclude\fR \fISPEC\fR\[u2026] .RS 4 Exclude the specified packages. Must be used in conjunction with the \fB\-\-workspace\fR flag. This flag may be specified multiple times and supports common Unix glob patterns like \fB*\fR, \fB?\fR and \fB[]\fR\&. However, to avoid your shell accidentally expanding glob patterns before Cargo handles them, you must use single quotes or double quotes around each pattern. .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Feature Selection" The feature flags allow you to control which features are enabled. When no feature options are given, the \fBdefault\fR feature is activated for every selected package. .sp See \fIthe features documentation\fR for more details. .sp \fB\-F\fR \fIfeatures\fR, \fB\-\-features\fR \fIfeatures\fR .RS 4 Space or comma separated list of features to activate. Features of workspace members may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE .sp \fB\-\-all\-features\fR .RS 4 Activate all available features of all selected packages. .RE .sp \fB\-\-no\-default\-features\fR .RS 4 Do not activate the \fBdefault\fR feature of the selected packages. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Display the tree for the package in the current directory: .sp .RS 4 .nf cargo tree .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Display all the packages that depend on the \fBsyn\fR package: .sp .RS 4 .nf cargo tree \-i syn .fi .RE .RE .sp .RS 4 \h'-04' 3.\h'+01'Show the features enabled on each package: .sp .RS 4 .nf cargo tree \-\-format "{p} {f}" .fi .RE .RE .sp .RS 4 \h'-04' 4.\h'+01'Show all packages that are built multiple times. This can happen if multiple semver\-incompatible versions appear in the tree (like 1.0.0 and 2.0.0). .sp .RS 4 .nf cargo tree \-d .fi .RE .RE .sp .RS 4 \h'-04' 5.\h'+01'Explain why features are enabled for the \fBsyn\fR package: .sp .RS 4 .nf cargo tree \-e features \-i syn .fi .RE .sp The \fB\-e features\fR flag is used to show features. The \fB\-i\fR flag is used to invert the graph so that it displays the packages that depend on \fBsyn\fR\&. An example of what this would display: .sp .RS 4 .nf syn v1.0.17 |\-\- syn feature "clone\-impls" | `\-\- syn feature "default" | `\-\- rustversion v1.0.2 | `\-\- rustversion feature "default" | `\-\- myproject v0.1.0 (/myproject) | `\-\- myproject feature "default" (command\-line) |\-\- syn feature "default" (*) |\-\- syn feature "derive" | `\-\- syn feature "default" (*) |\-\- syn feature "full" | `\-\- rustversion v1.0.2 (*) |\-\- syn feature "parsing" | `\-\- syn feature "default" (*) |\-\- syn feature "printing" | `\-\- syn feature "default" (*) |\-\- syn feature "proc\-macro" | `\-\- syn feature "default" (*) `\-\- syn feature "quote" |\-\- syn feature "printing" (*) `\-\- syn feature "proc\-macro" (*) .fi .RE .sp To read this graph, you can follow the chain for each feature from the root to see why it is included. For example, the \[lq]full\[rq] feature is added by the \fBrustversion\fR crate which is included from \fBmyproject\fR (with the default features), and \fBmyproject\fR is the package selected on the command\-line. All of the other \fBsyn\fR features are added by the \[lq]default\[rq] feature (\[lq]quote\[rq] is added by \[lq]printing\[rq] and \[lq]proc\-macro\[rq], both of which are default features). .sp If you\[cq]re having difficulty cross\-referencing the de\-duplicated \fB(*)\fR entries, try with the \fB\-\-no\-dedupe\fR flag to get the full output. .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-metadata\fR(1) cargo-0.86.0/src/etc/man/cargo-uninstall.1000064400000000000000000000105631046102023000163200ustar 00000000000000'\" t .TH "CARGO\-UNINSTALL" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-uninstall \[em] Remove a Rust binary .SH "SYNOPSIS" \fBcargo uninstall\fR [\fIoptions\fR] [\fIspec\fR\[u2026]] .SH "DESCRIPTION" This command removes a package installed with \fBcargo\-install\fR(1). The \fIspec\fR argument is a package ID specification of the package to remove (see \fBcargo\-pkgid\fR(1)). .sp By default all binaries are removed for a crate but the \fB\-\-bin\fR and \fB\-\-example\fR flags can be used to only remove particular binaries. .sp The installation root is determined, in order of precedence: .sp .RS 4 \h'-04'\(bu\h'+02'\fB\-\-root\fR option .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBCARGO_INSTALL_ROOT\fR environment variable .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBinstall.root\fR Cargo \fIconfig value\fR .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBCARGO_HOME\fR environment variable .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB$HOME/.cargo\fR .RE .SH "OPTIONS" .SS "Uninstall Options" .sp \fB\-p\fR, \fB\-\-package\fR \fIspec\fR\[u2026] .RS 4 Package to uninstall. .RE .sp \fB\-\-bin\fR \fIname\fR\[u2026] .RS 4 Only uninstall the binary \fIname\fR\&. .RE .sp \fB\-\-root\fR \fIdir\fR .RS 4 Directory to uninstall packages from. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Uninstall a previously installed package. .sp .RS 4 .nf cargo uninstall ripgrep .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-install\fR(1) cargo-0.86.0/src/etc/man/cargo-update.1000064400000000000000000000214741046102023000155740ustar 00000000000000'\" t .TH "CARGO\-UPDATE" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-update \[em] Update dependencies as recorded in the local lock file .SH "SYNOPSIS" \fBcargo update\fR [\fIoptions\fR] \fIspec\fR .SH "DESCRIPTION" This command will update dependencies in the \fBCargo.lock\fR file to the latest version. If the \fBCargo.lock\fR file does not exist, it will be created with the latest available versions. .SH "OPTIONS" .SS "Update Options" .sp \fIspec\fR\[u2026] .RS 4 Update only the specified packages. This flag may be specified multiple times. See \fBcargo\-pkgid\fR(1) for the SPEC format. .sp If packages are specified with \fIspec\fR, then a conservative update of the lockfile will be performed. This means that only the dependency specified by SPEC will be updated. Its transitive dependencies will be updated only if SPEC cannot be updated without updating dependencies. All other dependencies will remain locked at their currently recorded versions. .sp If \fIspec\fR is not specified, all dependencies are updated. .RE .sp \fB\-\-recursive\fR .RS 4 When used with \fIspec\fR, dependencies of \fIspec\fR are forced to update as well. Cannot be used with \fB\-\-precise\fR\&. .RE .sp \fB\-\-precise\fR \fIprecise\fR .RS 4 When used with \fIspec\fR, allows you to specify a specific version number to set the package to. If the package comes from a git repository, this can be a git revision (such as a SHA hash or tag). .sp While not recommended, you can specify a yanked version of a package. When possible, try other non\-yanked SemVer\-compatible versions or seek help from the maintainers of the package. .sp A compatible \fBpre\-release\fR version can also be specified even when the version requirement in \fBCargo.toml\fR doesn\[cq]t contain any pre\-release identifier (nightly only). .RE .sp \fB\-\-breaking\fR \fIdirectory\fR .RS 4 Update \fIspec\fR to latest SemVer\-breaking version. .sp Version requirements will be modified to allow this update. .sp This only applies to dependencies when .sp .RS 4 \h'-04'\(bu\h'+02'The package is a dependency of a workspace member .RE .sp .RS 4 \h'-04'\(bu\h'+02'The dependency is not renamed .RE .sp .RS 4 \h'-04'\(bu\h'+02'A SemVer\-incompatible version is available .RE .sp .RS 4 \h'-04'\(bu\h'+02'The \[lq]SemVer operator\[rq] is used (\fB^\fR which is the default) .RE .sp This option is unstable and available only on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable. See for more information. .RE .sp \fB\-w\fR, \fB\-\-workspace\fR .RS 4 Attempt to update only packages defined in the workspace. Other packages are updated only if they don\[cq]t already exist in the lockfile. This option is useful for updating \fBCargo.lock\fR after you\[cq]ve changed version numbers in \fBCargo.toml\fR\&. .RE .sp \fB\-\-dry\-run\fR .RS 4 Displays what would be updated, but doesn\[cq]t actually write the lockfile. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-ignore\-rust\-version\fR .RS 4 Ignore \fBrust\-version\fR specification in packages. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Update all dependencies in the lockfile: .sp .RS 4 .nf cargo update .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Update only specific dependencies: .sp .RS 4 .nf cargo update foo bar .fi .RE .RE .sp .RS 4 \h'-04' 3.\h'+01'Set a specific dependency to a specific version: .sp .RS 4 .nf cargo update foo \-\-precise 1.2.3 .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-generate\-lockfile\fR(1) cargo-0.86.0/src/etc/man/cargo-vendor.1000064400000000000000000000201751046102023000156040ustar 00000000000000'\" t .TH "CARGO\-VENDOR" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-vendor \[em] Vendor all dependencies locally .SH "SYNOPSIS" \fBcargo vendor\fR [\fIoptions\fR] [\fIpath\fR] .SH "DESCRIPTION" This cargo subcommand will vendor all crates.io and git dependencies for a project into the specified directory at \fB\fR\&. After this command completes the vendor directory specified by \fB\fR will contain all remote sources from dependencies specified. Additional manifests beyond the default one can be specified with the \fB\-s\fR option. .sp The configuration necessary to use the vendored sources would be printed to stdout after \fBcargo vendor\fR completes the vendoring process. You will need to add or redirect it to your Cargo configuration file, which is usually \fB\&.cargo/config.toml\fR locally for the current package. .sp Cargo treats vendored sources as read\-only as it does to registry and git sources. If you intend to modify a crate from a remote source, use \fB[patch]\fR or a \fBpath\fR dependency pointing to a local copy of that crate. Cargo will then correctly handle the crate on incremental rebuilds, as it knows that it is no longer a read\-only dependency. .SH "OPTIONS" .SS "Vendor Options" .sp \fB\-s\fR \fImanifest\fR, \fB\-\-sync\fR \fImanifest\fR .RS 4 Specify an extra \fBCargo.toml\fR manifest to workspaces which should also be vendored and synced to the output. May be specified multiple times. .RE .sp \fB\-\-no\-delete\fR .RS 4 Don\[cq]t delete the \[lq]vendor\[rq] directory when vendoring, but rather keep all existing contents of the vendor directory .RE .sp \fB\-\-respect\-source\-config\fR .RS 4 Instead of ignoring \fB[source]\fR configuration by default in \fB\&.cargo/config.toml\fR read it and use it when downloading crates from crates.io, for example .RE .sp \fB\-\-versioned\-dirs\fR .RS 4 Normally versions are only added to disambiguate multiple versions of the same package. This option causes all directories in the \[lq]vendor\[rq] directory to be versioned, which makes it easier to track the history of vendored packages over time, and can help with the performance of re\-vendoring when only a subset of the packages have changed. .RE .SS "Manifest Options" .sp \fB\-\-manifest\-path\fR \fIpath\fR .RS 4 Path to the \fBCargo.toml\fR file. By default, Cargo searches for the \fBCargo.toml\fR file in the current directory or any parent directory. .RE .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .sp \fB\-\-lockfile\-path\fR \fIPATH\fR .RS 4 Changes the path of the lockfile from the default (\fB/Cargo.lock\fR) to \fIPATH\fR\&. \fIPATH\fR must end with \fBCargo.lock\fR (e.g. \fB\-\-lockfile\-path /tmp/temporary\-lockfile/Cargo.lock\fR). Note that providing \fB\-\-lockfile\-path\fR will ignore existing lockfile at the default path, and instead will either use the lockfile from \fIPATH\fR, or write a new lockfile into the provided \fIPATH\fR if it doesn\[cq]t exist. This flag can be used to run most commands in read\-only directories, writing lockfile into the provided \fIPATH\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#14421\fR ). .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Vendor all dependencies into a local \[lq]vendor\[rq] folder .sp .RS 4 .nf cargo vendor .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Vendor all dependencies into a local \[lq]third\-party/vendor\[rq] folder .sp .RS 4 .nf cargo vendor third\-party/vendor .fi .RE .RE .sp .RS 4 \h'-04' 3.\h'+01'Vendor the current workspace as well as another to \[lq]vendor\[rq] .sp .RS 4 .nf cargo vendor \-s ../path/to/Cargo.toml .fi .RE .RE .sp .RS 4 \h'-04' 4.\h'+01'Vendor and redirect the necessary vendor configs to a config file. .sp .RS 4 .nf cargo vendor > path/to/my/cargo/config.toml .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1) cargo-0.86.0/src/etc/man/cargo-version.1000064400000000000000000000012301046102023000157630ustar 00000000000000'\" t .TH "CARGO\-VERSION" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-version \[em] Show version information .SH "SYNOPSIS" \fBcargo version\fR [\fIoptions\fR] .SH "DESCRIPTION" Displays the version of Cargo. .SH "OPTIONS" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Display additional version information. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Display the version: .sp .RS 4 .nf cargo version .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'The version is also available via flags: .sp .RS 4 .nf cargo \-\-version cargo \-V .fi .RE .RE .sp .RS 4 \h'-04' 3.\h'+01'Display extra version information: .sp .RS 4 .nf cargo \-Vv .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1) cargo-0.86.0/src/etc/man/cargo-yank.1000064400000000000000000000200421046102023000152420ustar 00000000000000'\" t .TH "CARGO\-YANK" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo\-yank \[em] Remove a pushed crate from the index .SH "SYNOPSIS" \fBcargo yank\fR [\fIoptions\fR] \fIcrate\fR@\fIversion\fR .br \fBcargo yank\fR [\fIoptions\fR] \fB\-\-version\fR \fIversion\fR [\fIcrate\fR] .SH "DESCRIPTION" The yank command removes a previously published crate\[cq]s version from the server\[cq]s index. This command does not delete any data, and the crate will still be available for download via the registry\[cq]s download link. .sp Cargo will not use a yanked version for any new project or checkout without a pre\-existing lockfile, and will generate an error if there are no longer any compatible versions for your crate. .sp This command requires you to be authenticated with either the \fB\-\-token\fR option or using \fBcargo\-login\fR(1). .sp If the crate name is not specified, it will use the package name from the current directory. .SS "How yank works" For example, the \fBfoo\fR crate published version \fB1.5.0\fR and another crate \fBbar\fR declared a dependency on version \fBfoo = "1.5"\fR\&. Now \fBfoo\fR releases a new, but not semver compatible, version \fB2.0.0\fR, and finds a critical issue with \fB1.5.0\fR\&. If \fB1.5.0\fR is yanked, no new project or checkout without an existing lockfile will be able to use crate \fBbar\fR as it relies on \fB1.5\fR\&. .sp In this case, the maintainers of \fBfoo\fR should first publish a semver compatible version such as \fB1.5.1\fR prior to yanking \fB1.5.0\fR so that \fBbar\fR and all projects that depend on \fBbar\fR will continue to work. .sp As another example, consider a crate \fBbar\fR with published versions \fB1.5.0\fR, \fB1.5.1\fR, \fB1.5.2\fR, \fB2.0.0\fR and \fB3.0.0\fR\&. The following table identifies the versions cargo could use in the absence of a lockfile for different SemVer requirements, following a given release being yanked: .TS allbox tab(:); lt lt lt lt. T{ Yanked Version / SemVer requirement T}:T{ \fBbar = "1.5.0"\fR T}:T{ \fBbar = "=1.5.0"\fR T}:T{ \fBbar = "2.0.0"\fR T} T{ \fB1.5.0\fR T}:T{ Use either \fB1.5.1\fR or \fB1.5.2\fR T}:T{ \fBReturn Error\fR T}:T{ Use \fB2.0.0\fR T} T{ \fB1.5.1\fR T}:T{ Use either \fB1.5.0\fR or \fB1.5.2\fR T}:T{ Use \fB1.5.0\fR T}:T{ Use \fB2.0.0\fR T} T{ \fB2.0.0\fR T}:T{ Use either \fB1.5.0\fR, \fB1.5.1\fR or \fB1.5.2\fR T}:T{ Use \fB1.5.0\fR T}:T{ \fBReturn Error\fR T} .TE .sp .SS "When to yank" Crates should only be yanked in exceptional circumstances, for example, an accidental publish, an unintentional SemVer breakages, or a significantly broken and unusable crate. In the case of security vulnerabilities, \fIRustSec\fR is typically a less disruptive mechanism to inform users and encourage them to upgrade, and avoids the possibility of significant downstream disruption irrespective of susceptibility to the vulnerability in question. .sp A common workflow is to yank a crate having already published a semver compatible version, to reduce the probability of preventing dependent crates from compiling. .sp When addressing copyright, licensing, or personal data issues with a published crate, simply yanking it may not suffice. In such cases, contact the maintainers of the registry you used. For crates.io, refer to their \fIpolicies\fR and contact them at \&. .sp If credentials have been leaked, the recommended course of action is to revoke them immediately. Once a crate has been published, it is impossible to determine if the leaked credentials have been copied. Yanking the crate only prevents new users from downloading it, but cannot stop those who have already downloaded it from keeping or even spreading the leaked credentials. .SH "OPTIONS" .SS "Yank Options" .sp \fB\-\-vers\fR \fIversion\fR, \fB\-\-version\fR \fIversion\fR .RS 4 The version to yank or un\-yank. .RE .sp \fB\-\-undo\fR .RS 4 Undo a yank, putting a version back into the index. .RE .sp \fB\-\-token\fR \fItoken\fR .RS 4 API token to use when authenticating. This overrides the token stored in the credentials file (which is created by \fBcargo\-login\fR(1)). .sp \fICargo config\fR environment variables can be used to override the tokens stored in the credentials file. The token for crates.io may be specified with the \fBCARGO_REGISTRY_TOKEN\fR environment variable. Tokens for other registries may be specified with environment variables of the form \fBCARGO_REGISTRIES_NAME_TOKEN\fR where \fBNAME\fR is the name of the registry in all capital letters. .RE .sp \fB\-\-index\fR \fIindex\fR .RS 4 The URL of the registry index to use. .RE .sp \fB\-\-registry\fR \fIregistry\fR .RS 4 Name of the registry to use. Registry names are defined in \fICargo config files\fR \&. If not specified, the default registry is used, which is defined by the \fBregistry.default\fR config key which defaults to \fBcrates\-io\fR\&. .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Yank a crate from the index: .sp .RS 4 .nf cargo yank foo@1.0.7 .fi .RE .RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-login\fR(1), \fBcargo\-publish\fR(1) cargo-0.86.0/src/etc/man/cargo.1000064400000000000000000000245621046102023000143150ustar 00000000000000'\" t .TH "CARGO" "1" .nh .ad l .ss \n[.ss] 0 .SH "NAME" cargo \[em] The Rust package manager .SH "SYNOPSIS" \fBcargo\fR [\fIoptions\fR] \fIcommand\fR [\fIargs\fR] .br \fBcargo\fR [\fIoptions\fR] \fB\-\-version\fR .br \fBcargo\fR [\fIoptions\fR] \fB\-\-list\fR .br \fBcargo\fR [\fIoptions\fR] \fB\-\-help\fR .br \fBcargo\fR [\fIoptions\fR] \fB\-\-explain\fR \fIcode\fR .SH "DESCRIPTION" This program is a package manager and build tool for the Rust language, available at \&. .SH "COMMANDS" .SS "Build Commands" \fBcargo\-bench\fR(1) .br \ \ \ \ Execute benchmarks of a package. .sp \fBcargo\-build\fR(1) .br \ \ \ \ Compile a package. .sp \fBcargo\-check\fR(1) .br \ \ \ \ Check a local package and all of its dependencies for errors. .sp \fBcargo\-clean\fR(1) .br \ \ \ \ Remove artifacts that Cargo has generated in the past. .sp \fBcargo\-doc\fR(1) .br \ \ \ \ Build a package\[cq]s documentation. .sp \fBcargo\-fetch\fR(1) .br \ \ \ \ Fetch dependencies of a package from the network. .sp \fBcargo\-fix\fR(1) .br \ \ \ \ Automatically fix lint warnings reported by rustc. .sp \fBcargo\-run\fR(1) .br \ \ \ \ Run a binary or example of the local package. .sp \fBcargo\-rustc\fR(1) .br \ \ \ \ Compile a package, and pass extra options to the compiler. .sp \fBcargo\-rustdoc\fR(1) .br \ \ \ \ Build a package\[cq]s documentation, using specified custom flags. .sp \fBcargo\-test\fR(1) .br \ \ \ \ Execute unit and integration tests of a package. .SS "Manifest Commands" \fBcargo\-add\fR(1) .br \ \ \ \ Add dependencies to a \fBCargo.toml\fR manifest file. .sp \fBcargo\-generate\-lockfile\fR(1) .br \ \ \ \ Generate \fBCargo.lock\fR for a project. .sp \fBcargo\-info\fR(1) .br \ \ \ \ Display information about a package in the registry. Default registry is crates.io. .sp \fBcargo\-locate\-project\fR(1) .br \ \ \ \ Print a JSON representation of a \fBCargo.toml\fR file\[cq]s location. .sp \fBcargo\-metadata\fR(1) .br \ \ \ \ Output the resolved dependencies of a package in machine\-readable format. .sp \fBcargo\-pkgid\fR(1) .br \ \ \ \ Print a fully qualified package specification. .sp \fBcargo\-remove\fR(1) .br \ \ \ \ Remove dependencies from a \fBCargo.toml\fR manifest file. .sp \fBcargo\-tree\fR(1) .br \ \ \ \ Display a tree visualization of a dependency graph. .sp \fBcargo\-update\fR(1) .br \ \ \ \ Update dependencies as recorded in the local lock file. .sp \fBcargo\-vendor\fR(1) .br \ \ \ \ Vendor all dependencies locally. .SS "Package Commands" \fBcargo\-init\fR(1) .br \ \ \ \ Create a new Cargo package in an existing directory. .sp \fBcargo\-install\fR(1) .br \ \ \ \ Build and install a Rust binary. .sp \fBcargo\-new\fR(1) .br \ \ \ \ Create a new Cargo package. .sp \fBcargo\-search\fR(1) .br \ \ \ \ Search packages in crates.io. .sp \fBcargo\-uninstall\fR(1) .br \ \ \ \ Remove a Rust binary. .SS "Publishing Commands" \fBcargo\-login\fR(1) .br \ \ \ \ Save an API token from the registry locally. .sp \fBcargo\-logout\fR(1) .br \ \ \ \ Remove an API token from the registry locally. .sp \fBcargo\-owner\fR(1) .br \ \ \ \ Manage the owners of a crate on the registry. .sp \fBcargo\-package\fR(1) .br \ \ \ \ Assemble the local package into a distributable tarball. .sp \fBcargo\-publish\fR(1) .br \ \ \ \ Upload a package to the registry. .sp \fBcargo\-yank\fR(1) .br \ \ \ \ Remove a pushed crate from the index. .SS "General Commands" \fBcargo\-help\fR(1) .br \ \ \ \ Display help information about Cargo. .sp \fBcargo\-version\fR(1) .br \ \ \ \ Show version information. .SH "OPTIONS" .SS "Special Options" .sp \fB\-V\fR, \fB\-\-version\fR .RS 4 Print version info and exit. If used with \fB\-\-verbose\fR, prints extra information. .RE .sp \fB\-\-list\fR .RS 4 List all installed Cargo subcommands. If used with \fB\-\-verbose\fR, prints extra information. .RE .sp \fB\-\-explain\fR \fIcode\fR .RS 4 Run \fBrustc \-\-explain CODE\fR which will print out a detailed explanation of an error message (for example, \fBE0004\fR). .RE .SS "Display Options" .sp \fB\-v\fR, \fB\-\-verbose\fR .RS 4 Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which includes extra output such as dependency warnings and build script output. May also be specified with the \fBterm.verbose\fR \fIconfig value\fR \&. .RE .sp \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Do not print cargo log messages. May also be specified with the \fBterm.quiet\fR \fIconfig value\fR \&. .RE .sp \fB\-\-color\fR \fIwhen\fR .RS 4 Control when colored output is used. Valid values: .sp .RS 4 \h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the terminal. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBalways\fR: Always display colors. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fBnever\fR: Never display colors. .RE .sp May also be specified with the \fBterm.color\fR \fIconfig value\fR \&. .RE .SS "Manifest Options" .sp \fB\-\-locked\fR .RS 4 Asserts that the exact same dependencies and versions are used as when the existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an error when either of the following scenarios arises: .sp .RS 4 \h'-04'\(bu\h'+02'The lock file is missing. .RE .sp .RS 4 \h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution. .RE .sp It may be used in environments where deterministic builds are desired, such as in CI pipelines. .RE .sp \fB\-\-offline\fR .RS 4 Prevents Cargo from accessing the network for any reason. Without this flag, Cargo will stop with an error if it needs to access the network and the network is not available. With this flag, Cargo will attempt to proceed without the network if possible. .sp Beware that this may result in different dependency resolution than online mode. Cargo will restrict itself to crates that are downloaded locally, even if there might be a newer version as indicated in the local copy of the index. See the \fBcargo\-fetch\fR(1) command to download dependencies before going offline. .sp May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&. .RE .sp \fB\-\-frozen\fR .RS 4 Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&. .RE .SS "Common Options" .sp \fB+\fR\fItoolchain\fR .RS 4 If Cargo has been installed with rustup, and the first argument to \fBcargo\fR begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such as \fB+stable\fR or \fB+nightly\fR). See the \fIrustup documentation\fR for more information about how toolchain overrides work. .RE .sp \fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR .RS 4 Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR, or provided as a path to an extra configuration file. This flag may be specified multiple times. See the \fIcommand\-line overrides section\fR for more information. .RE .sp \fB\-C\fR \fIPATH\fR .RS 4 Changes the current working directory before executing any specified operations. This affects things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&. .sp This option is only available on the \fInightly channel\fR and requires the \fB\-Z unstable\-options\fR flag to enable (see \fI#10098\fR ). .RE .sp \fB\-h\fR, \fB\-\-help\fR .RS 4 Prints help information. .RE .sp \fB\-Z\fR \fIflag\fR .RS 4 Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details. .RE .SH "ENVIRONMENT" See \fIthe reference\fR for details on environment variables that Cargo reads. .SH "EXIT STATUS" .sp .RS 4 \h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded. .RE .sp .RS 4 \h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete. .RE .SH "FILES" \fB~/.cargo/\fR .br \ \ \ \ Default location for Cargo\[cq]s \[lq]home\[rq] directory where it stores various files. The location can be changed with the \fBCARGO_HOME\fR environment variable. .sp \fB$CARGO_HOME/bin/\fR .br \ \ \ \ Binaries installed by \fBcargo\-install\fR(1) will be located here. If using \fIrustup\fR , executables distributed with Rust are also located here. .sp \fB$CARGO_HOME/config.toml\fR .br \ \ \ \ The global configuration file. See \fIthe reference\fR for more information about configuration files. .sp \fB\&.cargo/config.toml\fR .br \ \ \ \ Cargo automatically searches for a file named \fB\&.cargo/config.toml\fR in the current directory, and all parent directories. These configuration files will be merged with the global configuration file. .sp \fB$CARGO_HOME/credentials.toml\fR .br \ \ \ \ Private authentication information for logging in to a registry. .sp \fB$CARGO_HOME/registry/\fR .br \ \ \ \ This directory contains cached downloads of the registry index and any downloaded dependencies. .sp \fB$CARGO_HOME/git/\fR .br \ \ \ \ This directory contains cached downloads of git dependencies. .sp Please note that the internal structure of the \fB$CARGO_HOME\fR directory is not stable yet and may be subject to change. .SH "EXAMPLES" .sp .RS 4 \h'-04' 1.\h'+01'Build a local package and all of its dependencies: .sp .RS 4 .nf cargo build .fi .RE .RE .sp .RS 4 \h'-04' 2.\h'+01'Build a package with optimizations: .sp .RS 4 .nf cargo build \-\-release .fi .RE .RE .sp .RS 4 \h'-04' 3.\h'+01'Run tests for a cross\-compiled target: .sp .RS 4 .nf cargo test \-\-target i686\-unknown\-linux\-gnu .fi .RE .RE .sp .RS 4 \h'-04' 4.\h'+01'Create a new package that builds an executable: .sp .RS 4 .nf cargo new foobar .fi .RE .RE .sp .RS 4 \h'-04' 5.\h'+01'Create a package in the current directory: .sp .RS 4 .nf mkdir foo && cd foo cargo init . .fi .RE .RE .sp .RS 4 \h'-04' 6.\h'+01'Learn about a command\[cq]s options and usage: .sp .RS 4 .nf cargo help clean .fi .RE .RE .SH "BUGS" See for issues. .SH "SEE ALSO" \fBrustc\fR(1), \fBrustdoc\fR(1) cargo-0.86.0/tests/build-std/main.rs000064400000000000000000000307501046102023000153420ustar 00000000000000//! A test suite for `-Zbuild-std` which is much more expensive than the //! standard test suite. //! //! This test suite attempts to perform a full integration test where we //! actually compile the standard library from source (like the real one) and //! the various tests associated with that. //! //! YOU SHOULD IDEALLY NOT WRITE TESTS HERE. //! //! If possible, use `tests/testsuite/standard_lib.rs` instead. That uses a //! 'mock' sysroot which is much faster to compile. The tests here are //! extremely intensive and are only intended to run on CI and are theoretically //! not catching any regressions that `tests/testsuite/standard_lib.rs` isn't //! already catching. //! //! All tests here should use `#[cargo_test(build_std_real)]` to indicate that //! boilerplate should be generated to require the nightly toolchain and the //! `CARGO_RUN_BUILD_STD_TESTS` env var to be set to actually run these tests. //! Otherwise the tests are skipped. #![allow(clippy::disallowed_methods)] use cargo_test_support::prelude::*; use cargo_test_support::{basic_manifest, paths, project, rustc_host, str, Execs}; use std::env; use std::path::Path; fn enable_build_std(e: &mut Execs, arg: Option<&str>, isolated: bool) { if !isolated { e.env_remove("CARGO_HOME"); e.env_remove("HOME"); } // And finally actually enable `build-std` for now let arg = match arg { Some(s) => format!("-Zbuild-std={}", s), None => "-Zbuild-std".to_string(), }; e.arg(arg).arg("-Zpublic-dependency"); e.masquerade_as_nightly_cargo(&["build-std"]); } // Helper methods used in the tests below trait BuildStd: Sized { /// Set `-Zbuild-std` args and will download dependencies of the standard /// library in users's `CARGO_HOME` (`~/.cargo/`) instead of isolated /// environment `cargo-test-support` usually provides. /// /// The environment is not isolated is to avoid excessive network requests /// and downloads. A side effect is `[BLOCKING]` will show up in stderr, /// as a sign of package cahce lock contention when running other build-std /// tests concurrently. fn build_std(&mut self) -> &mut Self; /// Like [`BuildStd::build_std`] and is able to specify what crates to build. fn build_std_arg(&mut self, arg: &str) -> &mut Self; /// Like [`BuildStd::build_std`] but use an isolated `CARGO_HOME` environment /// to avoid package cache lock contention. /// /// Don't use this unless you really need to assert the full stderr /// and avoid any `[BLOCKING]` message. fn build_std_isolated(&mut self) -> &mut Self; fn target_host(&mut self) -> &mut Self; } impl BuildStd for Execs { fn build_std(&mut self) -> &mut Self { enable_build_std(self, None, false); self } fn build_std_arg(&mut self, arg: &str) -> &mut Self { enable_build_std(self, Some(arg), false); self } fn build_std_isolated(&mut self) -> &mut Self { enable_build_std(self, None, true); self } fn target_host(&mut self) -> &mut Self { self.arg("--target").arg(rustc_host()); self } } #[cargo_test(build_std_real)] fn basic() { let p = project() .file( "src/main.rs", " fn main() { foo::f(); } #[test] fn smoke_bin_unit() { foo::f(); } ", ) .file( "src/lib.rs", " extern crate alloc; extern crate proc_macro; /// ``` /// foo::f(); /// ``` pub fn f() { } #[test] fn smoke_lib_unit() { f(); } ", ) .file( "tests/smoke.rs", " #[test] fn smoke_integration() { foo::f(); } ", ) .build(); // HACK: use an isolated the isolated CARGO_HOME environment (`build_std_isolated`) // to avoid `[BLOCKING]` messages (from lock contention with other tests) // from getting in this test's asserts p.cargo("check").build_std_isolated().target_host().run(); p.cargo("build") .build_std_isolated() .target_host() // Importantly, this should not say [UPDATING] // There have been multiple bugs where every build triggers and update. .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("run") .build_std_isolated() .target_host() .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/[HOST_TARGET]/debug/foo` "#]]) .run(); p.cargo("test") .build_std_isolated() .target_host() .with_stderr_data(str![[r#" [COMPILING] rustc-std-workspace-std [..] ... [COMPILING] test v0.0.0 ([..]) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/[HOST_TARGET]/debug/deps/foo-[HASH]) [RUNNING] unittests src/main.rs (target/[HOST_TARGET]/debug/deps/foo-[HASH]) [RUNNING] tests/smoke.rs (target/[HOST_TARGET]/debug/deps/smoke-[HASH]) [DOCTEST] foo "#]]) .run(); // Check for hack that removes dylibs. let deps_dir = Path::new("target") .join(rustc_host()) .join("debug") .join("deps"); assert!(p.glob(deps_dir.join("*.rlib")).count() > 0); assert_eq!(p.glob(deps_dir.join("*.dylib")).count(), 0); } #[cargo_test(build_std_real)] fn host_proc_macro() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2021" [dependencies] macro_test = { path = "macro_test" } "#, ) .file( "src/main.rs", r#" extern crate macro_test; use macro_test::make_answer; make_answer!(); fn main() { println!("Hello, World: {}", answer()); } "#, ) .file( "macro_test/Cargo.toml", r#" [package] name = "macro_test" version = "0.1.0" edition = "2021" [lib] proc-macro = true "#, ) .file( "macro_test/src/lib.rs", r#" extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro] pub fn make_answer(_item: TokenStream) -> TokenStream { "fn answer() -> u32 { 42 }".parse().unwrap() } "#, ) .build(); p.cargo("build") .build_std_arg("std") .build_std_arg("proc_macro") .run(); } #[cargo_test(build_std_real)] fn cross_custom() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [target.custom-target.dependencies] dep = { path = "dep" } "#, ) .file( "src/lib.rs", "#![no_std] pub fn f() -> u32 { dep::answer() }", ) .file("dep/Cargo.toml", &basic_manifest("dep", "0.1.0")) .file("dep/src/lib.rs", "#![no_std] pub fn answer() -> u32 { 42 }") .file( "custom-target.json", r#" { "llvm-target": "x86_64-unknown-none-gnu", "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "arch": "x86_64", "target-endian": "little", "target-pointer-width": "64", "target-c-int-width": "32", "os": "none", "linker-flavor": "ld.lld" } "#, ) .build(); p.cargo("build --target custom-target.json -v") .build_std_arg("core") .run(); } #[cargo_test(build_std_real)] fn custom_test_framework() { let p = project() .file( "src/lib.rs", r#" #![no_std] #![cfg_attr(test, no_main)] #![feature(custom_test_frameworks)] #![test_runner(crate::test_runner)] pub fn test_runner(_tests: &[&dyn Fn()]) {} #[panic_handler] fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} } "#, ) .file( "target.json", r#" { "llvm-target": "x86_64-unknown-none-gnu", "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "arch": "x86_64", "target-endian": "little", "target-pointer-width": "64", "target-c-int-width": "32", "os": "none", "linker-flavor": "ld.lld", "linker": "rust-lld", "executables": true, "panic-strategy": "abort" } "#, ) .build(); // This is a bit of a hack to use the rust-lld that ships with most toolchains. let sysroot = paths::sysroot(); let sysroot = Path::new(&sysroot); let sysroot_bin = sysroot .join("lib") .join("rustlib") .join(rustc_host()) .join("bin"); let path = env::var_os("PATH").unwrap_or_default(); let mut paths = env::split_paths(&path).collect::>(); paths.insert(0, sysroot_bin); let new_path = env::join_paths(paths).unwrap(); p.cargo("test --target target.json --no-run -v") .env("PATH", new_path) .build_std_arg("core") .run(); } // Fixing rust-lang/rust#117839. // on macOS it never gets remapped. // Might be a separate issue, so only run on Linux. #[cargo_test(build_std_real)] #[cfg(target_os = "linux")] fn remap_path_scope() { let p = project() .file( "src/main.rs", " fn main() { panic!(\"remap to /rustc/\"); } ", ) .file( ".cargo/config.toml", " [profile.release] debug = \"line-tables-only\" ", ) .build(); p.cargo("run --release -Ztrim-paths") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .env("RUST_BACKTRACE", "1") .build_std() .target_host() .with_status(101) .with_stderr_data( str![[r#" [FINISHED] `release` profile [optimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/[HOST_TARGET]/release/foo` ... [..]thread '[..]' panicked at [..]src/main.rs:3:[..]: [..]remap to /rustc/[..] [..]at /rustc/[..]/library/std/src/[..] [..]at ./src/main.rs:3:[..] [..]at /rustc/[..]/library/core/src/[..] ... "#]] .unordered(), ) .run(); } #[cargo_test(build_std_real)] fn test_proc_macro() { // See rust-lang/cargo#14735 let p = project() .file( "Cargo.toml", r#" [package] name = "foo" edition = "2021" [lib] proc-macro = true "#, ) .file("src/lib.rs", "") .build(); p.cargo("test --lib") .env_remove(cargo_util::paths::dylib_path_envvar()) .build_std() .with_stderr_data(str![[r#" ... [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH]) "#]]) .run(); } #[cargo_test(build_std_real)] fn test_panic_abort() { // See rust-lang/cargo#14935 let p = project() .file( "Cargo.toml", r#" [package] name = "foo" edition = "2021" "#, ) .file("src/lib.rs", "#![no_std]") .build(); p.cargo("check") .build_std_arg("std,panic_abort") .env("RUSTFLAGS", "-C panic=abort") .arg("-Zbuild-std-features=panic_immediate_abort") .run(); } cargo-0.86.0/tests/testsuite/advanced_env.rs000064400000000000000000000016611046102023000171740ustar 00000000000000//! -Zadvanced-env tests use cargo_test_support::prelude::*; use cargo_test_support::{paths, project, registry::Package}; #[cargo_test] fn source_config_env() { // Try to define [source] with environment variables. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] somedep = "1.0" "#, ) .file("src/lib.rs", "") .build(); Package::new("somedep", "1.0.0") .local(true) .file("src/lib.rs", "") .publish(); let path = paths::root().join("registry"); p.cargo("check -Zadvanced-env") .masquerade_as_nightly_cargo(&["advanced-env"]) .env("CARGO_SOURCE_crates-io_REPLACE_WITH", "my-local-source") .env("CARGO_SOURCE_my-local-source_LOCAL_REGISTRY", path) .run(); } cargo-0.86.0/tests/testsuite/alt_registry.rs000064400000000000000000001464541046102023000173010ustar 00000000000000//! Tests for alternative registries. use std::fs; use cargo_test_support::compare::assert_e2e; use cargo_test_support::prelude::*; use cargo_test_support::publish::validate_alt_upload; use cargo_test_support::registry::{self, Package, RegistryBuilder}; use cargo_test_support::str; use cargo_test_support::{basic_manifest, paths, project}; #[cargo_test] fn depend_on_alt_registry() { registry::alt_init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2015" [dependencies.bar] version = "0.0.1" registry = "alternative" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").alternative(true).publish(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `alternative`) [CHECKING] bar v0.0.1 (registry `alternative`) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("clean").run(); // Don't download a second time p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] bar v0.0.1 (registry `alternative`) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn depend_on_alt_registry_depends_on_same_registry_no_index() { registry::alt_init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2015" [dependencies.bar] version = "0.0.1" registry = "alternative" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("baz", "0.0.1").alternative(true).publish(); Package::new("bar", "0.0.1") .registry_dep("baz", "0.0.1") .alternative(true) .publish(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] baz v0.0.1 (registry `alternative`) [DOWNLOADED] bar v0.0.1 (registry `alternative`) [CHECKING] baz v0.0.1 (registry `alternative`) [CHECKING] bar v0.0.1 (registry `alternative`) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn depend_on_alt_registry_depends_on_same_registry() { registry::alt_init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2015" [dependencies.bar] version = "0.0.1" registry = "alternative" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("baz", "0.0.1").alternative(true).publish(); Package::new("bar", "0.0.1") .registry_dep("baz", "0.0.1") .alternative(true) .publish(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] baz v0.0.1 (registry `alternative`) [DOWNLOADED] bar v0.0.1 (registry `alternative`) [CHECKING] baz v0.0.1 (registry `alternative`) [CHECKING] bar v0.0.1 (registry `alternative`) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn depend_on_alt_registry_depends_on_crates_io() { registry::alt_init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2015" [dependencies.bar] version = "0.0.1" registry = "alternative" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("baz", "0.0.1").publish(); Package::new("bar", "0.0.1") .dep("baz", "0.0.1") .alternative(true) .publish(); p.cargo("check") .with_stderr_data( str![[r#" [UPDATING] `alternative` index [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] baz v0.0.1 (registry `dummy-registry`) [DOWNLOADED] bar v0.0.1 (registry `alternative`) [CHECKING] baz v0.0.1 [CHECKING] bar v0.0.1 (registry `alternative`) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn registry_and_path_dep_works() { registry::alt_init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2015" [dependencies.bar] path = "bar" registry = "alternative" "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.0.1 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn registry_incompatible_with_git() { registry::alt_init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2015" [dependencies.bar] git = "" registry = "alternative" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: dependency (bar) specification is ambiguous. Only one of `git` or `registry` is allowed. "#]]) .run(); } #[cargo_test] fn cannot_publish_to_crates_io_with_registry_dependency() { let crates_io = registry::init(); let _alternative = RegistryBuilder::new().alternative().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2015" [dependencies.bar] version = "0.0.1" registry = "alternative" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").alternative(true).publish(); p.cargo("publish") .replace_crates_io(crates_io.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] crates cannot be published to crates.io with dependencies sourced from other registries. `bar` needs to be published to crates.io before publishing this crate. (crate `bar` is pulled from registry `alternative`) "#]]) .run(); p.cargo("publish") .replace_crates_io(crates_io.index_url()) .arg("--token") .arg(crates_io.token()) .arg("--index") .arg(crates_io.index_url().as_str()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] crates cannot be published to crates.io with dependencies sourced from other registries. `bar` needs to be published to crates.io before publishing this crate. (crate `bar` is pulled from registry `alternative`) "#]]) .run(); } #[cargo_test] fn publish_with_registry_dependency() { let _reg = RegistryBuilder::new() .http_api() .http_index() .alternative() .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2015" [dependencies.bar] version = "0.0.1" registry = "alternative" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").alternative(true).publish(); p.cargo("publish --registry alternative") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [UPDATING] `alternative` index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `alternative`) [COMPILING] bar v0.0.1 (registry `alternative`) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `alternative` [NOTE] waiting for `foo v0.0.1` to be available at registry `alternative`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `alternative` "#]]) .run(); validate_alt_upload( r#"{ "authors": [], "badges": {}, "categories": [], "deps": [ { "default_features": true, "features": [], "kind": "normal", "name": "bar", "optional": false, "target": null, "version_req": "^0.0.1" } ], "description": null, "documentation": null, "features": {}, "homepage": null, "keywords": [], "license": null, "license_file": null, "links": null, "name": "foo", "readme": null, "readme_file": null, "repository": null, "homepage": null, "documentation": null, "rust_version": null, "vers": "0.0.1" }"#, "foo-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], ); } #[cargo_test] fn alt_registry_and_crates_io_deps() { registry::alt_init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2015" [dependencies] crates_io_dep = "0.0.1" [dependencies.alt_reg_dep] version = "0.1.0" registry = "alternative" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("crates_io_dep", "0.0.1").publish(); Package::new("alt_reg_dep", "0.1.0") .alternative(true) .publish(); p.cargo("check") .with_stderr_data( str![[r#" [UPDATING] `alternative` index [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] crates_io_dep v0.0.1 (registry `dummy-registry`) [DOWNLOADED] alt_reg_dep v0.1.0 (registry `alternative`) [CHECKING] crates_io_dep v0.0.1 [CHECKING] alt_reg_dep v0.1.0 (registry `alternative`) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn block_publish_due_to_no_token() { registry::alt_init(); let p = project().file("src/lib.rs", "").build(); fs::remove_file(paths::home().join(".cargo/credentials.toml")).unwrap(); // Now perform the actual publish p.cargo("publish --registry alternative") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [ERROR] no token found for `alternative`, please run `cargo login --registry alternative` or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN "#]]) .run(); } #[cargo_test] fn cargo_registries_crates_io_protocol() { let _ = RegistryBuilder::new() .no_configure_token() .alternative() .build(); // Should not produce a warning due to the registries.crates-io.protocol = 'sparse' configuration let p = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", "[registries.crates-io] protocol = 'sparse'", ) .build(); p.cargo("publish --registry alternative") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [ERROR] no token found for `alternative`, please run `cargo login --registry alternative` or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN "#]]) .run(); } #[cargo_test] fn publish_to_alt_registry() { let _reg = RegistryBuilder::new() .http_api() .http_index() .alternative() .build(); let p = project().file("src/main.rs", "fn main() {}").build(); // Now perform the actual publish p.cargo("publish --registry alternative") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `alternative` [NOTE] waiting for `foo v0.0.1` to be available at registry `alternative`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `alternative` "#]]) .run(); validate_alt_upload( r#"{ "authors": [], "badges": {}, "categories": [], "deps": [], "description": null, "documentation": null, "features": {}, "homepage": null, "keywords": [], "license": null, "license_file": null, "links": null, "name": "foo", "readme": null, "readme_file": null, "repository": null, "homepage": null, "documentation": null, "rust_version": null, "vers": "0.0.1" }"#, "foo-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], ); } #[cargo_test] fn publish_with_crates_io_dep() { // crates.io registry. let _dummy_reg = registry::init(); // Alternative registry. let _alt_reg = RegistryBuilder::new() .http_api() .http_index() .alternative() .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = ["me"] edition = "2015" license = "MIT" description = "foo" [dependencies.bar] version = "0.0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").publish(); p.cargo("publish --registry alternative") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [UPDATING] `dummy-registry` index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [COMPILING] bar v0.0.1 [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `alternative` [NOTE] waiting for `foo v0.0.1` to be available at registry `alternative`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `alternative` "#]]) .run(); validate_alt_upload( r#"{ "authors": ["me"], "badges": {}, "categories": [], "deps": [ { "default_features": true, "features": [], "kind": "normal", "name": "bar", "optional": false, "registry": "https://github.com/rust-lang/crates.io-index", "target": null, "version_req": "^0.0.1" } ], "description": "foo", "documentation": null, "features": {}, "homepage": null, "keywords": [], "license": "MIT", "license_file": null, "links": null, "name": "foo", "readme": null, "readme_file": null, "repository": null, "homepage": null, "documentation": null, "rust_version": null, "vers": "0.0.1" }"#, "foo-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], ); } #[cargo_test] fn passwords_in_registries_index_url_forbidden() { registry::alt_init(); let config = paths::home().join(".cargo/config.toml"); fs::write( config, r#" [registries.alternative] index = "ssh://git:secret@foobar.com" "#, ) .unwrap(); let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("publish --registry alternative") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid index URL for registry `alternative` defined in [ROOT]/home/.cargo/config.toml Caused by: registry URLs may not contain passwords "#]]) .run(); } #[cargo_test] fn patch_alt_reg() { registry::alt_init(); Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = { version = "0.1.0", registry = "alternative" } [patch.alternative] bar = { path = "bar" } "#, ) .file( "src/lib.rs", " extern crate bar; pub fn f() { bar::bar(); } ", ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn bad_registry_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2015" [dependencies.bar] version = "0.0.1" registry = "bad name" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid character ` ` in registry name: `bad name`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters) --> Cargo.toml:8:17 | 8 | [dependencies.bar] | _________________^ 9 | | version = "0.0.1" 10 | | registry = "bad name" | |_____________________________________^ | "#]]) .run(); for cmd in &[ "init", "install foo", "login", "owner", "publish", "search", "yank --version 0.0.1", ] { p.cargo(cmd) .arg("--registry") .arg("bad name") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid character ` ` in registry name: `bad name`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters) "#]]) .run(); } } #[cargo_test] fn no_api() { let _registry = RegistryBuilder::new().alternative().no_api().build(); Package::new("bar", "0.0.1").alternative(true).publish(); // First check that a dependency works. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies.bar] version = "0.0.1" registry = "alternative" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `alternative`) [CHECKING] bar v0.0.1 (registry `alternative`) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("login --registry alternative TOKEN") .with_status(101) .with_stderr_data(str![[r#" [ERROR] registry `alternative` does not support API commands "#]]) .run(); p.cargo("publish --registry alternative") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [ERROR] registry `alternative` does not support API commands "#]]) .run(); p.cargo("search --registry alternative") .with_status(101) .with_stderr_data(str![[r#" [ERROR] registry `alternative` does not support API commands "#]]) .run(); p.cargo("owner --registry alternative --list") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [ERROR] registry `alternative` does not support API commands "#]]) .run(); p.cargo("yank --registry alternative --version=0.0.1 bar") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [ERROR] registry `alternative` does not support API commands "#]]) .run(); p.cargo("yank --registry alternative --version=0.0.1 bar") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [ERROR] registry `alternative` does not support API commands "#]]) .run(); } #[cargo_test] fn alt_reg_metadata() { // Check for "registry" entries in `cargo metadata` with alternative registries. registry::alt_init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] altdep = { version = "0.0.1", registry = "alternative" } iodep = { version = "0.0.1" } "#, ) .file("src/lib.rs", "") .build(); Package::new("bar", "0.0.1").publish(); Package::new("altdep", "0.0.1") .dep("bar", "0.0.1") .alternative(true) .publish(); Package::new("altdep2", "0.0.1").alternative(true).publish(); Package::new("iodep", "0.0.1") .registry_dep("altdep2", "0.0.1") .publish(); // The important thing to check here is the "registry" value in `deps`. // They should be: // foo -> altdep: alternative-registry // foo -> iodep: null (because it is in crates.io) // altdep -> bar: null (because it is in crates.io) // iodep -> altdep2: alternative-registry p.cargo("metadata --format-version=1 --no-deps") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [ { "features": [], "kind": null, "name": "altdep", "optional": false, "registry": "[ROOTURL]/alternative-registry", "rename": null, "req": "^0.0.1", "source": "registry+[ROOTURL]/alternative-registry", "target": null, "uses_default_features": true }, { "features": [], "kind": null, "name": "iodep", "optional": false, "registry": null, "rename": null, "req": "^0.0.1", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true } ], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } ], "version": "0.0.1" } ], "resolve": null, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.0.1" ], "workspace_members": [ "path+[ROOTURL]/foo#0.0.1" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); // --no-deps uses a different code path, make sure both work. p.cargo("metadata --format-version=1") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [ { "features": [], "kind": null, "name": "bar", "optional": false, "registry": null, "rename": null, "req": "^0.0.1", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true } ], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "registry+[ROOTURL]/alternative-registry#altdep@0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/altdep-0.0.1/Cargo.toml", "metadata": null, "name": "altdep", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": "registry+[ROOTURL]/alternative-registry", "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "altdep", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/altdep-0.0.1/src/lib.rs", "test": true } ], "version": "0.0.1" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "registry+[ROOTURL]/alternative-registry#altdep2@0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/altdep2-0.0.1/Cargo.toml", "metadata": null, "name": "altdep2", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": "registry+[ROOTURL]/alternative-registry", "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "altdep2", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/altdep2-0.0.1/src/lib.rs", "test": true } ], "version": "0.0.1" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "registry+https://github.com/rust-lang/crates.io-index#bar@0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/bar-0.0.1/Cargo.toml", "metadata": null, "name": "bar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": "registry+https://github.com/rust-lang/crates.io-index", "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "bar", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/bar-0.0.1/src/lib.rs", "test": true } ], "version": "0.0.1" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [ { "features": [], "kind": null, "name": "altdep", "optional": false, "registry": "[ROOTURL]/alternative-registry", "rename": null, "req": "^0.0.1", "source": "registry+[ROOTURL]/alternative-registry", "target": null, "uses_default_features": true }, { "features": [], "kind": null, "name": "iodep", "optional": false, "registry": null, "rename": null, "req": "^0.0.1", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true } ], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } ], "version": "0.0.1" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [ { "features": [], "kind": null, "name": "altdep2", "optional": false, "registry": "[ROOTURL]/alternative-registry", "rename": null, "req": "^0.0.1", "source": "registry+[ROOTURL]/alternative-registry", "target": null, "uses_default_features": true } ], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "registry+https://github.com/rust-lang/crates.io-index#iodep@0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/iodep-0.0.1/Cargo.toml", "metadata": null, "name": "iodep", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": "registry+https://github.com/rust-lang/crates.io-index", "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "iodep", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/iodep-0.0.1/src/lib.rs", "test": true } ], "version": "0.0.1" } ], "resolve": { "nodes": [ { "dependencies": [ "registry+https://github.com/rust-lang/crates.io-index#bar@0.0.1" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": null } ], "name": "bar", "pkg": "registry+https://github.com/rust-lang/crates.io-index#bar@0.0.1" } ], "features": [], "id": "registry+[ROOTURL]/alternative-registry#altdep@0.0.1" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+[ROOTURL]/alternative-registry#altdep2@0.0.1" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#bar@0.0.1" }, { "dependencies": [ "registry+[ROOTURL]/alternative-registry#altdep@0.0.1", "registry+https://github.com/rust-lang/crates.io-index#iodep@0.0.1" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": null } ], "name": "altdep", "pkg": "registry+[ROOTURL]/alternative-registry#altdep@0.0.1" }, { "dep_kinds": [ { "kind": null, "target": null } ], "name": "iodep", "pkg": "registry+https://github.com/rust-lang/crates.io-index#iodep@0.0.1" } ], "features": [], "id": "path+[ROOTURL]/foo#0.0.1" }, { "dependencies": [ "registry+[ROOTURL]/alternative-registry#altdep2@0.0.1" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": null } ], "name": "altdep2", "pkg": "registry+[ROOTURL]/alternative-registry#altdep2@0.0.1" } ], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#iodep@0.0.1" } ], "root": "path+[ROOTURL]/foo#0.0.1" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.0.1" ], "workspace_members": [ "path+[ROOTURL]/foo#0.0.1" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn unknown_registry() { // A known registry refers to an unknown registry. // foo -> bar(crates.io) -> baz(alt) registry::alt_init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2015" [dependencies.bar] version = "0.0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("baz", "0.0.1").alternative(true).publish(); Package::new("bar", "0.0.1") .registry_dep("baz", "0.0.1") .publish(); // Remove "alternative" from config. let cfg_path = paths::home().join(".cargo/config.toml"); let mut config = fs::read_to_string(&cfg_path).unwrap(); let start = config.find("[registries.alternative]").unwrap(); config.insert(start, '#'); let start_index = &config[start..].find("index =").unwrap(); config.insert(start + start_index, '#'); fs::write(&cfg_path, config).unwrap(); p.cargo("check").run(); // Important parts: // foo -> bar registry = null // bar -> baz registry = alternate p.cargo("metadata --format-version=1") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [ { "features": [], "kind": null, "name": "baz", "optional": false, "registry": "[ROOTURL]/alternative-registry", "rename": null, "req": "^0.0.1", "source": "registry+[ROOTURL]/alternative-registry", "target": null, "uses_default_features": true } ], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "registry+https://github.com/rust-lang/crates.io-index#bar@0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/bar-0.0.1/Cargo.toml", "metadata": null, "name": "bar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": "registry+https://github.com/rust-lang/crates.io-index", "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "bar", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/bar-0.0.1/src/lib.rs", "test": true } ], "version": "0.0.1" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "registry+[ROOTURL]/alternative-registry#baz@0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/baz-0.0.1/Cargo.toml", "metadata": null, "name": "baz", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": "registry+[ROOTURL]/alternative-registry", "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "baz", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/baz-0.0.1/src/lib.rs", "test": true } ], "version": "0.0.1" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [ { "features": [], "kind": null, "name": "bar", "optional": false, "registry": null, "rename": null, "req": "^0.0.1", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true } ], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "foo", "src_path": "[ROOT]/foo/src/main.rs", "test": true } ], "version": "0.0.1" } ], "resolve": { "nodes": [ { "dependencies": [ "registry+[ROOTURL]/alternative-registry#baz@0.0.1" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": null } ], "name": "baz", "pkg": "registry+[ROOTURL]/alternative-registry#baz@0.0.1" } ], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#bar@0.0.1" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+[ROOTURL]/alternative-registry#baz@0.0.1" }, { "dependencies": [ "registry+https://github.com/rust-lang/crates.io-index#bar@0.0.1" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": null } ], "name": "bar", "pkg": "registry+https://github.com/rust-lang/crates.io-index#bar@0.0.1" } ], "features": [], "id": "path+[ROOTURL]/foo#0.0.1" } ], "root": "path+[ROOTURL]/foo#0.0.1" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.0.1" ], "workspace_members": [ "path+[ROOTURL]/foo#0.0.1" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn registries_index_relative_url() { registry::alt_init(); let config = paths::root().join(".cargo/config.toml"); fs::create_dir_all(config.parent().unwrap()).unwrap(); fs::write( &config, r#" [registries.relative] index = "file:alternative-registry" "#, ) .unwrap(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2015" [dependencies.bar] version = "0.0.1" registry = "relative" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").alternative(true).publish(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `relative` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `relative`) [CHECKING] bar v0.0.1 (registry `relative`) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn registries_index_relative_path_not_allowed() { registry::alt_init(); let config = paths::root().join(".cargo/config.toml"); fs::create_dir_all(config.parent().unwrap()).unwrap(); fs::write( &config, r#" [registries.relative] index = "alternative-registry" "#, ) .unwrap(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2015" [dependencies.bar] version = "0.0.1" registry = "relative" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").alternative(true).publish(); p.cargo("check") .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: invalid index URL for registry `relative` defined in [ROOT]/.cargo/config.toml Caused by: invalid url `alternative-registry`: relative URL without a base "#]]) .with_status(101) .run(); } #[cargo_test] fn both_index_and_registry() { let p = project().file("src/lib.rs", "").build(); for cmd in &["publish", "owner", "search", "yank --version 1.0.0"] { p.cargo(cmd) .arg("--registry=foo") .arg("--index=foo") .with_status(1) .with_stderr_data(str![[r#" [ERROR] the argument '--registry ' cannot be used with '--index ' Usage: [..] For more information, try '--help'. "#]]) .run(); } } #[cargo_test] fn both_index_and_default() { let p = project().file("src/lib.rs", "").build(); for cmd in &[ "publish", "owner", "search", "yank --version 1.0.0", "install foo", ] { p.cargo(cmd) .env("CARGO_REGISTRY_DEFAULT", "undefined") .arg(format!("--index=index_url")) .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid url `index_url`: relative URL without a base "#]]) .run(); } } #[cargo_test] fn sparse_lockfile() { let _registry = registry::RegistryBuilder::new() .http_index() .alternative() .build(); Package::new("foo", "0.1.0").alternative(true).publish(); let p = project() .file( "Cargo.toml", r#" [project] name = "a" version = "0.5.0" authors = [] edition = "2015" [dependencies] foo = { registry = 'alternative', version = '0.1.0'} "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); assert_e2e().eq( &p.read_lockfile(), str![[r##" # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "a" version = "0.5.0" dependencies = [ "foo", ] [[package]] name = "foo" version = "0.1.0" source = "sparse+http://127.0.0.1:[..]/index/" checksum = "458c1addb23fde7dfbca0410afdbcc0086f96197281ec304d9e0e10def3cb899" "##]], ); } #[cargo_test] fn publish_with_transitive_dep() { let _alt1 = RegistryBuilder::new() .http_api() .http_index() .alternative_named("Alt-1") .build(); let _alt2 = RegistryBuilder::new() .http_api() .http_index() .alternative_named("Alt-2") .build(); let p1 = project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" "#, ) .file("src/lib.rs", "") .build(); p1.cargo("publish --registry Alt-1").run(); let p2 = project() .file( "Cargo.toml", r#" [package] name = "b" version = "0.6.0" publish = ["Alt-2"] edition = "2015" [dependencies] a = { version = "0.5.0", registry = "Alt-1" } "#, ) .file("src/lib.rs", "") .build(); p2.cargo("publish").run(); } #[cargo_test] fn warn_for_unused_fields() { let _ = RegistryBuilder::new() .no_configure_token() .alternative() .build(); let p = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", "[registry] unexpected-field = 'foo' [registries.alternative] unexpected-field = 'foo' ", ) .build(); p.cargo("publish --registry alternative") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [WARNING] unused config key `registries.alternative.unexpected-field` in `[ROOT]/foo/.cargo/config.toml` [ERROR] no token found for `alternative`, please run `cargo login --registry alternative` or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN "#]]) .run(); let crates_io = registry::RegistryBuilder::new() .no_configure_token() .build(); p.cargo("publish --registry crates-io") .replace_crates_io(crates_io.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] unused config key `registry.unexpected-field` in `[ROOT]/foo/.cargo/config.toml` [ERROR] no token found, please run `cargo login` or use environment variable CARGO_REGISTRY_TOKEN "#]]) .run(); } #[cargo_test] fn config_empty_registry_name() { let _ = RegistryBuilder::new() .no_configure_token() .alternative() .build(); let p = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", "[registry.''] ", ) .build(); p.cargo("publish") .arg("--registry") .arg("") .with_status(101) .with_stderr_data(str![[r#" [ERROR] registry name cannot be empty "#]]) .run(); } #[cargo_test] fn empty_registry_flag() { let p = project().file("src/lib.rs", "").build(); p.cargo("publish") .arg("--registry") .arg("") .with_status(101) .with_stderr_data(str![[r#" [ERROR] registry name cannot be empty "#]]) .run(); } #[cargo_test] fn empty_dependency_registry() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = { version = "0.1.0", registry = "" } "#, ) .file( "src/lib.rs", " extern crate bar; pub fn f() { bar::bar(); } ", ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] registry name cannot be empty --> Cargo.toml:8:23 | 8 | bar = { version = "0.1.0", registry = "" } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | "#]]) .run(); } cargo-0.86.0/tests/testsuite/artifact_dep.rs000064400000000000000000003050411046102023000172030ustar 00000000000000//! Tests specific to artifact dependencies, designated using //! the new `dep = { artifact = "bin", … }` syntax in manifests. use cargo_test_support::compare::assert_e2e; use cargo_test_support::prelude::*; use cargo_test_support::registry::{Package, RegistryBuilder}; use cargo_test_support::str; use cargo_test_support::{ basic_bin_manifest, basic_manifest, cross_compile, project, publish, registry, rustc_host, Project, }; #[cargo_test] fn check_with_invalid_artifact_dependency() { // invalid name let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [dependencies] bar = { path = "bar/", artifact = "unknown" } "#, ) .file("src/lib.rs", "extern crate bar;") // this would fail but we don't get there, artifacts are no libs .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: 'unknown' is not a valid artifact specifier "#]]) .with_status(101) .run(); fn run_cargo_with_and_without_bindeps_feature( p: &Project, cmd: &str, assert: &dyn Fn(&mut cargo_test_support::Execs), ) { assert( p.cargo(&format!("{} -Z bindeps", cmd)) .masquerade_as_nightly_cargo(&["bindeps"]), ); assert(&mut p.cargo(cmd)); } // lib specified without artifact let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] bar = { path = "bar/", lib = true } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); run_cargo_with_and_without_bindeps_feature(&p, "check", &|cargo| { cargo .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: 'lib' specifier cannot be used without an 'artifact = …' value (bar) "#]]) .with_status(101) .run(); }); // target specified without artifact let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] bar = { path = "bar/", target = "target" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); run_cargo_with_and_without_bindeps_feature(&p, "check", &|cargo| { cargo .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: 'target' specifier cannot be used without an 'artifact = …' value (bar) "#]]) .with_status(101) .run(); }) } #[cargo_test] fn check_with_invalid_target_triple() { // invalid name let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [dependencies] bar = { path = "bar/", artifact = "bin", target = "unknown-target-triple" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: process didn't exit successfully: `rustc - --crate-name ___ --print=file-names --target unknown-target-triple [..]` ([EXIT_STATUS]: 1) --- stderr ... "#]]) .with_status(101) .run(); } #[cargo_test] fn build_without_nightly_aborts_with_error() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [dependencies] bar = { path = "bar/", artifact = "bin" } "#, ) .file("src/lib.rs", "extern crate bar;") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `artifact = …` requires `-Z bindeps` (bar) "#]]) .run(); } #[cargo_test] fn disallow_artifact_and_no_artifact_dep_to_same_package_within_the_same_dep_category() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [dependencies] bar = { path = "bar/", artifact = "bin" } bar_stable = { path = "bar/", package = "bar" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_status(101) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [WARNING] foo v0.0.0 ([ROOT]/foo) ignoring invalid dependency `bar_stable` which is missing a lib target [ERROR] the crate `foo v0.0.0 ([ROOT]/foo)` depends on crate `bar v0.5.0 ([ROOT]/foo/bar)` multiple times with different names "#]]) .run(); } #[cargo_test] fn features_are_unified_among_lib_and_bin_dep_of_same_target() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] resolver = "2" [dependencies.d1] path = "d1" features = ["d1f1"] artifact = "bin" lib = true [dependencies.d2] path = "d2" features = ["d2f2"] "#, ) .file( "src/main.rs", r#" fn main() { d1::f1(); d1::f2(); d2::f1(); d2::f2(); } "#, ) .file( "d1/Cargo.toml", r#" [package] name = "d1" version = "0.0.1" edition = "2015" authors = [] [features] d1f1 = ["d2"] [dependencies.d2] path = "../d2" features = ["d2f1"] optional = true "#, ) .file( "d1/src/main.rs", r#"fn main() { #[cfg(feature = "d1f1")] d2::f1(); // Using f2 is only possible as features are unififed across the same target. // Our own manifest would only enable f1, and f2 comes in because a parent crate // enables the feature in its manifest. #[cfg(feature = "d1f1")] d2::f2(); }"#, ) .file( "d1/src/lib.rs", r#" #[cfg(feature = "d2")] extern crate d2; /// Importing f2 here shouldn't be possible as unless features are unified. #[cfg(feature = "d1f1")] pub use d2::{f1, f2}; "#, ) .file( "d2/Cargo.toml", r#" [package] name = "d2" version = "0.0.1" edition = "2015" authors = [] [features] d2f1 = [] d2f2 = [] "#, ) .file( "d2/src/lib.rs", r#" #[cfg(feature = "d2f1")] pub fn f1() {} #[cfg(feature = "d2f2")] pub fn f2() {} "#, ) .build(); p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] d2 v0.0.1 ([ROOT]/foo/d2) [COMPILING] d1 v0.0.1 ([ROOT]/foo/d1) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn features_are_not_unified_among_lib_and_bin_dep_of_different_target() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let p = project() .file( "Cargo.toml", &r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] resolver = "2" [dependencies.d1] path = "d1" features = ["d1f1"] artifact = "bin" lib = true target = "$TARGET" [dependencies.d2] path = "d2" features = ["d2f2"] "# .replace("$TARGET", target), ) .file( "src/main.rs", r#" fn main() { // the lib = true part always builds for our current target, unifying dependencies d1::d2::f1(); d1::d2::f2(); d2::f1(); d2::f2(); } "#, ) .file( "d1/Cargo.toml", r#" [package] name = "d1" version = "0.0.1" edition = "2015" authors = [] [features] d1f1 = ["d2"] [dependencies.d2] path = "../d2" features = ["d2f1"] optional = true "#, ) .file("d1/src/main.rs", r#"fn main() { // f1 we set ourselves d2::f1(); // As 'main' is only compiled as part of the artifact dependency and since that is not unified // if the target differs, trying to access f2 is a compile time error as the feature isn't enabled in our dependency tree. d2::f2(); }"#) .file( "d1/src/lib.rs", r#" #[cfg(feature = "d2")] pub extern crate d2; "#, ) .file( "d2/Cargo.toml", r#" [package] name = "d2" version = "0.0.1" edition = "2015" authors = [] [features] d2f1 = [] d2f2 = [] "#, ) .file( "d2/src/lib.rs", r#" #[cfg(feature = "d2f1")] pub fn f1() {} #[cfg(feature = "d2f2")] pub fn f2() {} "#, ) .build(); p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_status(101) .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] d2 v0.0.1 ([ROOT]/foo/d2) [COMPILING] d1 v0.0.1 ([ROOT]/foo/d1) error[E0425]: cannot find function `f2` in crate `d2` ... For more information about this error, try `rustc --explain E0425`. [ERROR] could not compile `d1` (bin "d1") due to 1 previous error ... "#]]) .run(); } #[cargo_test] fn feature_resolution_works_for_cfg_target_specification() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let p = project() .file( "Cargo.toml", &r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] resolver = "2" [dependencies.d1] path = "d1" artifact = "bin" target = "$TARGET" "# .replace("$TARGET", target), ) .file( "src/main.rs", r#" fn main() { let _b = include_bytes!(env!("CARGO_BIN_FILE_D1")); } "#, ) .file( "d1/Cargo.toml", &r#" [package] name = "d1" version = "0.0.1" edition = "2015" authors = [] [target.'$TARGET'.dependencies] d2 = { path = "../d2" } "# .replace("$TARGET", target), ) .file( "d1/src/main.rs", r#"fn main() { d1::f(); }"#, ) .file("d1/build.rs", r#"fn main() { }"#) .file( "d1/src/lib.rs", &r#"pub fn f() { #[cfg(target = "$TARGET")] d2::f(); } "# .replace("$TARGET", target), ) .file( "d2/Cargo.toml", r#" [package] name = "d2" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("d2/build.rs", r#"fn main() { }"#) .file("d2/src/lib.rs", "pub fn f() {}") .build(); p.cargo("test -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .run(); } #[cargo_test] fn build_script_with_bin_artifacts() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [build-dependencies] bar = { path = "bar/", artifact = ["bin", "staticlib", "cdylib"] } "#, ) .file("src/lib.rs", "") .file("build.rs", r#" fn main() { let baz: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR_baz").expect("CARGO_BIN_FILE_BAR_baz").into(); println!("{}", baz.display()); assert!(&baz.is_file()); let lib: std::path::PathBuf = std::env::var("CARGO_STATICLIB_FILE_BAR_bar").expect("CARGO_STATICLIB_FILE_BAR_bar").into(); println!("{}", lib.display()); assert!(&lib.is_file()); let lib: std::path::PathBuf = std::env::var("CARGO_CDYLIB_FILE_BAR_bar").expect("CARGO_CDYLIB_FILE_BAR_bar").into(); println!("{}", lib.display()); assert!(&lib.is_file()); let dir: std::path::PathBuf = std::env::var("CARGO_BIN_DIR_BAR").expect("CARGO_BIN_DIR_BAR").into(); println!("{}", dir.display()); assert!(dir.is_dir()); let bar: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR").expect("CARGO_BIN_FILE_BAR").into(); println!("{}", bar.display()); assert!(&bar.is_file()); let bar2: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR_bar").expect("CARGO_BIN_FILE_BAR_bar").into(); println!("{}", bar2.display()); assert_eq!(bar, bar2); } "#) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [lib] crate-type = ["staticlib", "cdylib"] "#, ) // compilation target is native for build scripts unless overridden .file("bar/src/bin/bar.rs", &format!(r#"fn main() {{ assert_eq!(std::env::var("TARGET").unwrap(), "{}"); }}"#, cross_compile::native())) .file("bar/src/bin/baz.rs", "fn main() {}") .file("bar/src/lib.rs", "") .build(); p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data( str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] foo v0.0.0 ([ROOT]/foo) [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); let build_script_output = build_script_output_string(&p, "foo"); // we need the binary directory for this artifact along with all binary paths if cfg!(target_env = "msvc") { assert_e2e().eq( &build_script_output, str![[r#" [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin/baz[EXE] [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/staticlib/bar-[HASH].lib [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/cdylib/bar.dll [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin/bar[EXE] [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin/bar[EXE] "#]], ); } else { assert_e2e().eq( &build_script_output, str![[r#" [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin/baz-[HASH][EXE] [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/staticlib/libbar-[HASH].a [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/cdylib/[..]bar.[..] [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin/bar-[HASH][EXE] [ROOT]/foo/target/debug/deps/artifact/bar-[HASH]/bin/bar-[HASH][EXE] "#]], ); } assert!( !p.bin("bar").is_file(), "artifacts are located in their own directory, exclusively, and won't be lifted up" ); assert!(!p.bin("baz").is_file(),); assert_artifact_executable_output(&p, "debug", "bar", "bar"); } #[cargo_test] fn build_script_with_bin_artifact_and_lib_false() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [build-dependencies] bar = { path = "bar/", artifact = "bin" } "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { bar::doit() } "#, ) .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", "fn main() { bar::doit(); }") .file( "bar/src/lib.rs", r#" pub fn doit() { panic!("sentinel"); } "#, ) .build(); p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_status(101) .with_stderr_does_not_contain("[..]sentinel[..]") .run(); } #[cargo_test] fn lib_with_bin_artifact_and_lib_false() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [dependencies] bar = { path = "bar/", artifact = "bin" } "#, ) .file( "src/lib.rs", r#" pub fn foo() { bar::doit() }"#, ) .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", "fn main() { bar::doit(); }") .file( "bar/src/lib.rs", r#" pub fn doit() { panic!("sentinel"); } "#, ) .build(); p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_status(101) .with_stderr_does_not_contain("[..]sentinel[..]") .run(); } #[cargo_test] fn build_script_with_selected_dashed_bin_artifact_and_lib_true() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [build-dependencies] bar-baz = { path = "bar/", artifact = "bin:baz-suffix", lib = true } "#, ) .file("src/lib.rs", "") .file("build.rs", r#" fn main() { bar_baz::print_env() } "#) .file( "bar/Cargo.toml", r#" [package] name = "bar-baz" version = "0.5.0" edition = "2015" authors = [] [[bin]] name = "bar" [[bin]] name = "baz-suffix" "#, ) .file("bar/src/main.rs", "fn main() {}") .file("bar/src/lib.rs", r#" pub fn print_env() { let dir: std::path::PathBuf = std::env::var("CARGO_BIN_DIR_BAR_BAZ").expect("CARGO_BIN_DIR_BAR_BAZ").into(); let bin: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR_BAZ_baz-suffix").expect("CARGO_BIN_FILE_BAR_BAZ_baz-suffix").into(); println!("{}", dir.display()); println!("{}", bin.display()); assert!(dir.is_dir()); assert!(&bin.is_file()); assert!(std::env::var("CARGO_BIN_FILE_BAR_BAZ").is_err(), "CARGO_BIN_FILE_BAR_BAZ isn't set due to name mismatch"); assert!(std::env::var("CARGO_BIN_FILE_BAR_BAZ_bar").is_err(), "CARGO_BIN_FILE_BAR_BAZ_bar isn't set as binary isn't selected"); } "#) .build(); p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar-baz v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let build_script_output = build_script_output_string(&p, "foo"); // we need the binary directory for this artifact and the binary itself if cfg!(target_env = "msvc") { assert_e2e().eq( &build_script_output, str![[r#" [ROOT]/foo/target/debug/deps/artifact/bar-baz-[HASH]/bin [ROOT]/foo/target/debug/deps/artifact/bar-baz-[HASH]/bin/baz_suffix[EXE] "#]], ); } else { assert_e2e().eq( &build_script_output, str![[r#" [ROOT]/foo/target/debug/deps/artifact/bar-baz-[HASH]/bin [ROOT]/foo/target/debug/deps/artifact/bar-baz-[HASH]/bin/baz_suffix-[HASH][EXE] "#]], ); } assert!( !p.bin("bar").is_file(), "artifacts are located in their own directory, exclusively, and won't be lifted up" ); assert_artifact_executable_output(&p, "debug", "bar", "baz_suffix"); } #[cargo_test] fn lib_with_selected_dashed_bin_artifact_and_lib_true() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [dependencies] bar-baz = { path = "bar/", artifact = ["bin:baz-suffix", "staticlib", "cdylib"], lib = true } "#, ) .file( "src/lib.rs", r#" pub fn foo() { bar_baz::exists(); env!("CARGO_BIN_DIR_BAR_BAZ"); let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_BAZ_baz-suffix")); let _b = include_bytes!(env!("CARGO_STATICLIB_FILE_BAR_BAZ")); let _b = include_bytes!(env!("CARGO_STATICLIB_FILE_BAR_BAZ_bar-baz")); let _b = include_bytes!(env!("CARGO_STATICLIB_FILE_BAR_BAZ_bar_baz")); let _b = include_bytes!(env!("CARGO_CDYLIB_FILE_BAR_BAZ")); let _b = include_bytes!(env!("CARGO_CDYLIB_FILE_BAR_BAZ_bar-baz")); let _b = include_bytes!(env!("CARGO_CDYLIB_FILE_BAR_BAZ_bar_baz")); } "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar-baz" version = "0.5.0" edition = "2015" authors = [] [lib] crate-type = ["rlib", "staticlib", "cdylib"] [[bin]] name = "bar" [[bin]] name = "baz-suffix" "#, ) .file("bar/src/main.rs", "fn main() {}") .file("bar/src/lib.rs", "pub fn exists() {}") .build(); p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar-baz v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!( !p.bin("bar").is_file(), "artifacts are located in their own directory, exclusively, and won't be lifted up" ); assert_artifact_executable_output(&p, "debug", "bar", "baz_suffix"); } #[cargo_test] fn allow_artifact_and_no_artifact_dep_to_same_package_within_different_dep_categories() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [dependencies] bar = { path = "bar/", artifact = "bin" } [dev-dependencies] bar = { path = "bar/", package = "bar" } "#, ) .file( "src/lib.rs", r#" #[cfg(test)] extern crate bar; pub fn foo() { env!("CARGO_BIN_DIR_BAR"); let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); }"#, ) .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", "fn main() {}") .file("bar/src/lib.rs", "") .build(); p.cargo("test -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "#]]) .run(); } #[cargo_test] fn normal_build_deps_are_picked_up_in_presence_of_an_artifact_build_dep_to_the_same_package() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [dependencies] bar = { path = "bar", artifact = "bin:bar" } [build-dependencies] bar = { path = "bar" } "#, ) .file("build.rs", "fn main() { bar::f(); }") .file( "src/lib.rs", r#" pub fn foo() { env!("CARGO_BIN_DIR_BAR"); let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); }"#, ) .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", "fn main() {}") .file("bar/src/lib.rs", "pub fn f() {}") .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .run(); } #[cargo_test] fn disallow_using_example_binaries_as_artifacts() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [dependencies] bar = { path = "bar/", artifact = "bin:one-example" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", "fn main() {}") .file("bar/examples/one-example.rs", "fn main() {}") .build(); p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_status(101) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [ERROR] dependency `bar` in package `foo` requires a `bin:one-example` artifact to be present. "#]]) .run(); } /// From RFC 3028 /// /// > You may also specify separate dependencies with different artifact values, as well as /// dependencies on the same crate without artifact specified; for instance, you may have a /// build dependency on the binary of a crate and a normal dependency on the Rust library of the same crate. #[cargo_test] fn allow_artifact_and_non_artifact_dependency_to_same_crate() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [build-dependencies] bar = { path = "bar/", artifact = "bin" } [dependencies] bar = { path = "bar/" } "#, ) .file("src/lib.rs", r#" pub fn foo() { bar::doit(); assert!(option_env!("CARGO_BIN_FILE_BAR").is_none()); }"#) .file( "build.rs", r#" fn main() { assert!(option_env!("CARGO_BIN_FILE_BAR").is_none(), "no environment variables at build time"); std::process::Command::new(std::env::var("CARGO_BIN_FILE_BAR").expect("BAR present")).status().unwrap(); }"#, ) .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", "fn main() {}") .file("bar/src/lib.rs", "pub fn doit() {}") .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_script_deps_adopt_specified_target_unconditionally() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [build-dependencies.bar] path = "bar/" artifact = "bin" target = "{}" "#, target ), ) .file("src/lib.rs", "") .file("build.rs", r#" fn main() { let bar: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR").expect("CARGO_BIN_FILE_BAR").into(); assert!(&bar.is_file()); }"#) .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", "fn main() {}") .file("bar/src/lib.rs", "pub fn doit() {}") .build(); p.cargo("check -v -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_does_not_contain( "[RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]--target [ALT_TARGET] [..]", ) .with_stderr_contains("[RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]") .with_stderr_contains( "[RUNNING] `rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--target [ALT_TARGET] [..]", ) .with_stderr_contains( "[RUNNING] `rustc --crate-name bar --edition=2015 bar/src/main.rs [..]--target [ALT_TARGET] [..]", ) .with_stderr_does_not_contain( "[RUNNING] `rustc --crate-name foo [..]--target [ALT_TARGET] [..]", ) .with_stderr_contains("[RUNNING] `rustc --crate-name foo [..]") .run(); } /// inverse RFC-3176 #[cargo_test] fn build_script_deps_adopt_do_not_allow_multiple_targets_under_different_name_and_same_version() { if cross_compile::disabled() { return; } let alternate = cross_compile::alternate(); let native = cross_compile::native(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [build-dependencies.bar] path = "bar/" artifact = "bin" target = "{}" [build-dependencies.bar-native] package = "bar" path = "bar/" artifact = "bin" target = "{}" "#, alternate, native ), ) .file("src/lib.rs", "") .file("build.rs", r#" fn main() { let bar: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR").expect("CARGO_BIN_FILE_BAR").into(); assert!(&bar.is_file()); let bar_native: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR_NATIVE_bar").expect("CARGO_BIN_FILE_BAR_NATIVE_bar").into(); assert!(&bar_native.is_file()); assert_ne!(bar_native, bar, "should build different binaries due to different targets"); }"#) .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check -v -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_status(101) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [ERROR] the crate `foo v0.0.0 ([ROOT]/foo)` depends on crate `bar v0.5.0 ([ROOT]/foo/bar)` multiple times with different names "#]]) .run(); } #[cargo_test] fn non_build_script_deps_adopt_specified_target_unconditionally() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [dependencies.bar] path = "bar/" artifact = "bin" target = "{}" "#, target ), ) .file( "src/lib.rs", r#"pub fn foo() { let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); }"#, ) .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", "fn main() {}") .file("bar/src/lib.rs", "pub fn doit() {}") .build(); p.cargo("check -v -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_contains( "[RUNNING] `rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--target [ALT_TARGET] [..]", ) .with_stderr_contains( "[RUNNING] `rustc --crate-name bar --edition=2015 bar/src/main.rs [..]--target [ALT_TARGET] [..]", ) .with_stderr_does_not_contain( "[RUNNING] `rustc --crate-name foo [..]--target [ALT_TARGET] [..]", ) .with_stderr_contains("[RUNNING] `rustc --crate-name foo [..]") .run(); } #[cargo_test] fn no_cross_doctests_works_with_artifacts() { if cross_compile::disabled() { return; } let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] resolver = "2" [dependencies] bar = { path = "bar/", artifact = "bin", lib = true } "#, ) .file( "src/lib.rs", r#" //! ``` //! env!("CARGO_BIN_DIR_BAR"); //! let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); //! ``` pub fn foo() { env!("CARGO_BIN_DIR_BAR"); let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); } "#, ) .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/lib.rs", r#"pub extern "C" fn c() {}"#) .file("bar/src/main.rs", "fn main() {}") .build(); let target = rustc_host(); p.cargo("test -Z bindeps --target") .arg(&target) .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/[HOST_TARGET]/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "#]]) .run(); println!("c"); let target = cross_compile::alternate(); // This will build the library, but does not build or run doc tests. // This should probably be a warning or error. p.cargo("test -Z bindeps -v --doc --target") .arg(&target) .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--target [ALT_TARGET] [..] [RUNNING] `rustc --crate-name bar --edition=2015 bar/src/main.rs [..]--target [ALT_TARGET] [..] [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [NOTE] skipping doctests for foo v0.0.1 ([ROOT]/foo) (lib), cross-compilation doctests are not yet supported See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#doctest-xcompile for more information. "#]]) .run(); if !cross_compile::can_run_on_host() { return; } // This tests the library, but does not run the doc tests. p.cargo("test -Z bindeps -v --target") .arg(&target) .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [FRESH] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]--test[..] [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/[ALT_TARGET]/debug/deps/foo-[HASH][EXE]` [NOTE] skipping doctests for foo v0.0.1 ([ROOT]/foo) (lib), cross-compilation doctests are not yet supported See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#doctest-xcompile for more information. "#]]) .run(); } #[cargo_test] fn build_script_deps_adopts_target_platform_if_target_equals_target() { if cross_compile::disabled() { return; } let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [build-dependencies] bar = { path = "bar/", artifact = "bin", target = "target" } "#, ) .file("src/lib.rs", "") .file("build.rs", r#" fn main() { let bar: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR").expect("CARGO_BIN_FILE_BAR").into(); assert!(&bar.is_file()); }"#) .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", "fn main() {}") .file("bar/src/lib.rs", "pub fn doit() {}") .build(); let alternate_target = cross_compile::alternate(); p.cargo("check -v -Z bindeps --target") .arg(alternate_target) .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_does_not_contain( "[RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]--target [ALT_TARGET] [..]", ) .with_stderr_contains("[RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]") .with_stderr_contains( "[RUNNING] `rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--target [ALT_TARGET] [..]", ) .with_stderr_contains( "[RUNNING] `rustc --crate-name bar --edition=2015 bar/src/main.rs [..]--target [ALT_TARGET] [..]", ) .with_stderr_contains( "[RUNNING] `rustc --crate-name foo [..]--target [ALT_TARGET] [..]", ) .run(); } #[cargo_test] // TODO(ST): rename bar (dependency) to something else and un-ignore this with RFC-3176 #[cfg_attr(target_env = "msvc", ignore = "msvc not working")] fn profile_override_basic() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [build-dependencies] bar = { path = "bar", artifact = "bin" } [dependencies] bar = { path = "bar", artifact = "bin" } [profile.dev.build-override] opt-level = 1 [profile.dev] opt-level = 3 "#, ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", "fn main() {}") .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("build -v -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data( str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build [..] -C opt-level=1 [..]` [RUNNING] `rustc --crate-name bar --edition=2015 bar/src/main.rs [..] -C opt-level=3 [..]` [RUNNING] `rustc --crate-name bar --edition=2015 bar/src/main.rs [..] -C opt-level=1 [..]` [RUNNING] `rustc --crate-name bar --edition=2015 bar/src/lib.rs [..] -C opt-level=1 [..]` [RUNNING] `rustc --crate-name bar --edition=2015 bar/src/lib.rs [..] -C opt-level=3 [..]` [RUNNING] `rustc --crate-name foo [..] -C opt-level=3 [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [FINISHED] `dev` profile [optimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn dependencies_of_dependencies_work_in_artifacts() { Package::new("baz", "1.0.0") .file("src/lib.rs", "pub fn baz() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [build-dependencies] bar = { path = "bar/", artifact = "bin" } "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { std::process::Command::new(std::env::var("CARGO_BIN_FILE_BAR").expect("BAR present")).status().unwrap(); } "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [dependencies] baz = "1.0.0" "#, ) .file("bar/src/lib.rs", r#"pub fn bar() {baz::baz()}"#) .file("bar/src/main.rs", r#"fn main() {bar::bar()}"#) .build(); p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .run(); // cargo tree sees artifacts as the dependency kind they are in and doesn't do anything special with it. p.cargo("tree -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stdout_data(str![[r#" foo v0.0.0 ([ROOT]/foo) [build-dependencies] └── bar v0.5.0 ([ROOT]/foo/bar) └── baz v1.0.0 "#]]) .run(); } #[cargo_test] fn artifact_dep_target_specified() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let p = project() .file( "Cargo.toml", &r#" [package] name = "foo" version = "0.0.0" authors = [] resolver = "2" edition = "2015" [dependencies] bindep = { path = "bindep", artifact = "bin", target = "$TARGET" } "# .replace("$TARGET", target), ) .file("src/lib.rs", "") .file("bindep/Cargo.toml", &basic_manifest("bindep", "0.0.0")) .file("bindep/src/main.rs", "fn main() {}") .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bindep v0.0.0 ([ROOT]/foo/bindep) [CHECKING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_status(0) .run(); p.cargo("tree -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stdout_data(str![[r#" foo v0.0.0 ([ROOT]/foo) └── bindep v0.0.0 ([ROOT]/foo/bindep) "#]]) .with_status(0) .run(); } /// From issue #10593 /// The case where: /// * artifact dep is { target = } /// * dependency of that artifact dependency specifies the same target /// * the target is not activated. #[cargo_test] fn dep_of_artifact_dep_same_target_specified() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" resolver = "2" [dependencies] bar = {{ path = "bar", artifact = "bin", target = "{target}" }} "#, ), ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", &format!( r#" [package] name = "bar" version = "0.1.0" [target.{target}.dependencies] baz = {{ path = "../baz" }} "#, ), ) .file("bar/src/main.rs", "fn main() {}") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.0" "#, ) .file("baz/src/lib.rs", "") .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] baz v0.1.0 ([ROOT]/foo/baz) [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_status(0) .run(); p.cargo("tree -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stdout_data( r#"... foo v0.1.0 ([ROOT]/foo) └── bar v0.1.0 ([ROOT]/foo/bar) └── baz v0.1.0 ([ROOT]/foo/baz) "#, ) .with_status(0) .run(); } #[cargo_test] fn targets_are_picked_up_from_non_workspace_artifact_deps() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); Package::new("artifact", "1.0.0") .file("src/main.rs", r#"fn main() {}"#) .file("src/lib.rs", r#"pub fn lib() {}"#) .publish(); let mut dep = registry::Dependency::new("artifact", "1.0.0"); Package::new("uses-artifact", "1.0.0") .schema_version(3) .file( "src/lib.rs", r#"pub fn uses_artifact() { let _b = include_bytes!(env!("CARGO_BIN_FILE_ARTIFACT")); }"#, ) .add_dep(dep.artifact("bin", Some(target.to_string()))) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] uses-artifact = { version = "1.0.0" } "#, ) .file( "src/lib.rs", r#"pub fn foo() { uses_artifact::uses_artifact(); }"#, ) .build(); p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .run(); } #[cargo_test] fn index_version_filtering() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); Package::new("artifact", "1.0.0") .file("src/main.rs", r#"fn main() {}"#) .file("src/lib.rs", r#"pub fn lib() {}"#) .publish(); let mut dep = registry::Dependency::new("artifact", "1.0.0"); Package::new("bar", "1.0.0").publish(); Package::new("bar", "1.0.1") .schema_version(3) .add_dep(dep.artifact("bin", Some(target.to_string()))) .publish(); // Verify that without `-Zbindeps` that it does not use 1.0.1. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar v1.0.0 "#]]) .run(); // And with -Zbindeps it can use 1.0.1. p.cargo("update -Zbindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [ADDING] artifact v1.0.0 [UPDATING] bar v1.0.0 -> v1.0.1 "#]]) .run(); // And without -Zbindeps, now that 1.0.1 is in Cargo.lock, it should fail. p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `bar = "^1.0"` (locked to 1.0.1) version 1.0.1 requires a Cargo version that supports index version 3 location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.1.0 ([ROOT]/foo)` "#]]) .run(); } #[cargo_test] fn proc_macro_in_artifact_dep() { // Forcing FeatureResolver to check a proc-macro for a dependency behind a // target dependency. if cross_compile::disabled() { return; } Package::new("pm", "1.0.0") .file("src/lib.rs", "") .file( "Cargo.toml", r#" [package] name = "pm" version = "1.0.0" edition = "2015" [lib] proc-macro = true "#, ) .publish(); let alternate = cross_compile::alternate(); Package::new("bin-uses-pm", "1.0.0") .target_dep("pm", "1.0", alternate) .file("src/main.rs", "fn main() {}") .publish(); // Simulate a network error downloading the proc-macro. std::fs::remove_file(cargo_test_support::paths::root().join("dl/pm/1.0.0/download")).unwrap(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2021" [dependencies] bin-uses-pm = {{ version = "1.0", artifact = "bin", target = "{alternate}"}} "# ), ) .file("src/lib.rs", "") .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data( r#"... [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [ERROR] failed to download from `[ROOTURL]/dl/pm/1.0.0/download` Caused by: [37] Could[..]t read a file:// file (Couldn't open file [ROOT]/dl/pm/1.0.0/download) "#, ) .with_status(101) .run(); } #[cargo_test] fn allow_dep_renames_with_multiple_versions() { Package::new("bar", "1.0.0") .file("src/main.rs", r#"fn main() {println!("1.0.0")}"#) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [build-dependencies] bar = { path = "bar/", artifact = "bin" } bar_stable = { package = "bar", version = "1.0.0", artifact = "bin" } "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { std::process::Command::new(std::env::var("CARGO_BIN_FILE_BAR").expect("BAR present")).status().unwrap(); std::process::Command::new(std::env::var("CARGO_BIN_FILE_BAR_STABLE_bar").expect("BAR STABLE present")).status().unwrap(); } "#, ) .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", r#"fn main() {println!("0.5.0")}"#) .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [COMPILING] bar v1.0.0 [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); let build_script_output = build_script_output_string(&p, "foo"); assert_e2e().eq( &build_script_output, str![[r#" 0.5.0 1.0.0 "#]], ); } #[cargo_test] fn allow_artifact_and_non_artifact_dependency_to_same_crate_if_these_are_not_the_same_dep_kind() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [build-dependencies] bar = { path = "bar/", artifact = "bin", lib = false } [dependencies] bar = { path = "bar/" } "#, ) .file("src/lib.rs", r#" pub fn foo() { bar::doit(); assert!(option_env!("CARGO_BIN_FILE_BAR").is_none()); }"#) .file( "build.rs", r#"fn main() { println!("{}", std::env::var("CARGO_BIN_FILE_BAR").expect("CARGO_BIN_FILE_BAR")); println!("{}", std::env::var("CARGO_BIN_FILE_BAR_bar").expect("CARGO_BIN_FILE_BAR_bar")); }"#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn doit() {}") .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn prevent_no_lib_warning_with_artifact_dependencies() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [dependencies] bar = { path = "bar/", artifact = "bin" } "#, ) .file( "src/lib.rs", r#"pub fn foo() { let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); }"#, ) .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [CHECKING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn show_no_lib_warning_with_artifact_dependencies_that_have_no_lib_but_lib_true() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [build-dependencies] bar = { path = "bar/", artifact = "bin" } [dependencies] bar = { path = "bar/", artifact = "bin", lib = true } "#, ) .file("src/lib.rs", "") .file("src/build.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [WARNING] foo v0.0.0 ([ROOT]/foo) ignoring invalid dependency `bar` which is missing a lib target [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [CHECKING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn resolver_2_build_dep_without_lib() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" authors = [] edition = "2021" [build-dependencies] bar = { path = "bar/", artifact = "bin" } "#, ) .file("src/lib.rs", "") .file("build.rs", r#" fn main() { let bar: std::path::PathBuf = std::env::var("CARGO_BIN_FILE_BAR").expect("CARGO_BIN_FILE_BAR").into(); assert!(&bar.is_file()); }"#) .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .run(); } #[cargo_test] fn check_missing_crate_type_in_package_fails() { for crate_type in &["cdylib", "staticlib", "bin"] { let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] bar = {{ path = "bar/", artifact = "{}" }} "#, crate_type ), ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) //no bin, just rlib .file("bar/src/lib.rs", "") .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_status(101) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [ERROR] dependency `bar` in package `foo` requires a [..] artifact to be present. "#]]) .run(); } } #[cargo_test] fn check_target_equals_target_in_non_build_dependency_errors() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [dependencies] bar = { path = "bar/", artifact = "bin", target = "target" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `target = "target"` in normal- or dev-dependencies has no effect (bar) "#]]) .run(); } #[cargo_test] fn env_vars_and_build_products_for_various_build_targets() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] resolver = "2" [lib] doctest = true [build-dependencies] bar = { path = "bar/", artifact = ["cdylib", "staticlib"] } [dependencies] bar = { path = "bar/", artifact = "bin", lib = true } [dev-dependencies] bar = { path = "bar/", artifact = "bin:baz" } "#, ) .file("build.rs", r#" fn main() { let file: std::path::PathBuf = std::env::var("CARGO_CDYLIB_FILE_BAR").expect("CARGO_CDYLIB_FILE_BAR").into(); assert!(&file.is_file()); let file: std::path::PathBuf = std::env::var("CARGO_STATICLIB_FILE_BAR").expect("CARGO_STATICLIB_FILE_BAR").into(); assert!(&file.is_file()); assert!(std::env::var("CARGO_BIN_FILE_BAR").is_err()); assert!(std::env::var("CARGO_BIN_FILE_BAR_baz").is_err()); } "#) .file( "src/lib.rs", r#" //! ``` //! bar::c(); //! env!("CARGO_BIN_DIR_BAR"); //! let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); //! let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_bar")); //! let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_baz")); //! assert!(option_env!("CARGO_STATICLIB_FILE_BAR").is_none()); //! assert!(option_env!("CARGO_CDYLIB_FILE_BAR").is_none()); //! ``` pub fn foo() { bar::c(); env!("CARGO_BIN_DIR_BAR"); let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_bar")); let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_baz")); assert!(option_env!("CARGO_STATICLIB_FILE_BAR").is_none()); assert!(option_env!("CARGO_CDYLIB_FILE_BAR").is_none()); } #[cfg(test)] #[test] fn env_unit() { env!("CARGO_BIN_DIR_BAR"); let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_bar")); let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_baz")); assert!(option_env!("CARGO_STATICLIB_FILE_BAR").is_none()); assert!(option_env!("CARGO_CDYLIB_FILE_BAR").is_none()); } "#, ) .file( "tests/main.rs", r#" #[test] fn env_integration() { env!("CARGO_BIN_DIR_BAR"); let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_bar")); let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR_baz")); }"#, ) .file("build.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [lib] crate-type = ["staticlib", "cdylib", "rlib"] [[bin]] name = "bar" [[bin]] name = "baz" "#, ) .file("bar/src/lib.rs", r#"pub extern "C" fn c() {}"#) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("test -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [RUNNING] tests/main.rs (target/debug/deps/main-[HASH][EXE]) [DOCTEST] foo "#]]) .run(); } #[cargo_test] fn publish_artifact_dep() { let registry = RegistryBuilder::new().http_api().http_index().build(); Package::new("bar", "1.0.0").publish(); Package::new("baz", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" resolver = "2" [dependencies] bar = { version = "1.0", artifact = "bin", lib = true } [build-dependencies] baz = { version = "1.0", artifact = ["bin:a", "cdylib", "staticlib"], target = "target" } "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish -Z bindeps --no-verify") .replace_crates_io(registry.index_url()) .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [UPDATING] crates.io index [PACKAGING] foo v0.1.0 ([ROOT]/foo) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.1.0 ([ROOT]/foo) [UPLOADED] foo v0.1.0 to registry `crates-io` [NOTE] waiting for `foo v0.1.0` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.1.0 at registry `crates-io` "#]]) .run(); publish::validate_upload_with_contents( r#" { "authors": [], "badges": {}, "categories": [], "deps": [{ "artifact": ["bin"], "default_features": true, "features": [], "kind": "normal", "lib": true, "name": "bar", "optional": false, "target": null, "version_req": "^1.0" }, { "artifact": [ "bin:a", "cdylib", "staticlib" ], "bindep_target": "target", "default_features": true, "features": [], "kind": "build", "name": "baz", "optional": false, "target": null, "version_req": "^1.0" } ], "description": "foo", "documentation": "foo", "features": {}, "homepage": "foo", "keywords": [], "license": "MIT", "license_file": null, "links": null, "name": "foo", "readme": null, "readme_file": null, "repository": "foo", "rust_version": null, "vers": "0.1.0" } "#, "foo-0.1.0.crate", &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "Cargo.lock"], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.1.0" authors = [] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" homepage = "foo" documentation = "foo" readme = false license = "MIT" repository = "foo" resolver = "2" [lib] name = "foo" path = "src/lib.rs" [dependencies.bar] version = "1.0" artifact = ["bin"] lib = true [build-dependencies.baz] version = "1.0" artifact = [ "bin:a", "cdylib", "staticlib", ] target = "target" "##]], )], ); } #[cargo_test] fn doc_lib_true() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] resolver = "2" [dependencies.bar] path = "bar" artifact = "bin" lib = true "#, ) .file("src/lib.rs", "extern crate bar; pub fn foo() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("doc -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [DOCUMENTING] bar v0.0.1 ([ROOT]/foo/bar) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); assert!(p.root().join("target/doc").is_dir()); assert!(p.root().join("target/doc/foo/index.html").is_file()); assert!(p.root().join("target/doc/bar/index.html").is_file()); // Verify that it emits rmeta for the bin and lib dependency. assert_eq!(p.glob("target/debug/artifact/*.rlib").count(), 0); assert_eq!(p.glob("target/debug/deps/libbar-*.rmeta").count(), 2); p.cargo("doc -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); assert!(p.root().join("target/doc").is_dir()); assert!(p.root().join("target/doc/foo/index.html").is_file()); assert!(p.root().join("target/doc/bar/index.html").is_file()); } #[cargo_test] fn rustdoc_works_on_libs_with_artifacts_and_lib_false() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] resolver = "2" [dependencies.bar] path = "bar" artifact = ["bin", "staticlib", "cdylib"] "#, ) .file( "src/lib.rs", r#" pub fn foo() { env!("CARGO_BIN_DIR_BAR"); let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); let _b = include_bytes!(env!("CARGO_CDYLIB_FILE_BAR")); let _b = include_bytes!(env!("CARGO_CDYLIB_FILE_BAR_bar")); let _b = include_bytes!(env!("CARGO_STATICLIB_FILE_BAR")); let _b = include_bytes!(env!("CARGO_STATICLIB_FILE_BAR_bar")); }"#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [lib] crate-type = ["staticlib", "cdylib"] "#, ) .file("bar/src/lib.rs", "pub fn bar() {}") .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("doc -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); assert!(p.root().join("target/doc").is_dir()); assert!(p.root().join("target/doc/foo/index.html").is_file()); assert!( !p.root().join("target/doc/bar/index.html").is_file(), "bar is not a lib dependency and thus remains undocumented" ); } fn assert_artifact_executable_output( p: &Project, target_name: &str, dep_name: &str, bin_name: &str, ) { if cfg!(target_env = "msvc") { assert_eq!( p.glob(format!( "target/{}/deps/artifact/{}-*/bin/{}{}", target_name, dep_name, bin_name, std::env::consts::EXE_SUFFIX )) .count(), 1, "artifacts are placed into their own output directory to not possibly clash" ); } else { assert_eq!( p.glob(format!( "target/{}/deps/artifact/{}-*/bin/{}-*{}", target_name, dep_name, bin_name, std::env::consts::EXE_SUFFIX )) .filter_map(Result::ok) .filter(|f| f.extension().map_or(true, |ext| ext != "o" && ext != "d")) .count(), 1, "artifacts are placed into their own output directory to not possibly clash" ); } } fn build_script_output_string(p: &Project, package_name: &str) -> String { let paths = p .glob(format!("target/debug/build/{}-*/output", package_name)) .collect::, _>>() .unwrap(); assert_eq!(paths.len(), 1); std::fs::read_to_string(&paths[0]).unwrap() } #[cargo_test] fn build_script_features_for_shared_dependency() { // When a build script is built and run, its features should match. Here: // // foo // -> artifact on d1 with target // -> common with features f1 // // d1 // -> common with features f2 // // common has features f1 and f2, with a build script. // // When common is built as a dependency of d1, it should have features // `f2` (for the library and the build script). // // When common is built as a dependency of foo, it should have features // `f1` (for the library and the build script). if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let p = project() .file( "Cargo.toml", &r#" [package] name = "foo" version = "0.0.1" edition = "2015" resolver = "2" [dependencies] d1 = { path = "d1", artifact = "bin", target = "$TARGET" } common = { path = "common", features = ["f1"] } "# .replace("$TARGET", target), ) .file( "src/main.rs", r#" fn main() { let _b = include_bytes!(env!("CARGO_BIN_FILE_D1")); common::f1(); } "#, ) .file( "d1/Cargo.toml", r#" [package] name = "d1" version = "0.0.1" edition = "2015" [dependencies] common = { path = "../common", features = ["f2"] } "#, ) .file( "d1/src/main.rs", r#"fn main() { common::f2(); }"#, ) .file( "common/Cargo.toml", r#" [package] name = "common" version = "0.0.1" edition = "2015" [features] f1 = [] f2 = [] "#, ) .file( "common/src/lib.rs", r#" #[cfg(feature = "f1")] pub fn f1() {} #[cfg(feature = "f2")] pub fn f2() {} "#, ) .file( "common/build.rs", &r#" use std::env::var_os; fn main() { assert_eq!(var_os("CARGO_FEATURE_F1").is_some(), cfg!(feature="f1")); assert_eq!(var_os("CARGO_FEATURE_F2").is_some(), cfg!(feature="f2")); if std::env::var("TARGET").unwrap() == "$TARGET" { assert!(var_os("CARGO_FEATURE_F1").is_none()); assert!(var_os("CARGO_FEATURE_F2").is_some()); } else { assert!(var_os("CARGO_FEATURE_F1").is_some()); assert!(var_os("CARGO_FEATURE_F2").is_none()); } } "# .replace("$TARGET", target), ) .build(); p.cargo("build -Z bindeps -v") .masquerade_as_nightly_cargo(&["bindeps"]) .run(); } #[cargo_test] fn calc_bin_artifact_fingerprint() { // See rust-lang/cargo#10527 let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" resolver = "2" [dependencies] bar = { path = "bar/", artifact = "bin" } "#, ) .file( "src/main.rs", r#" fn main() { let _b = include_bytes!(env!("CARGO_BIN_FILE_BAR")); } "#, ) .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/main.rs", r#"fn main() { println!("foo") }"#) .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file("bar/src/main.rs", r#"fn main() { println!("bar") }"#); // Change in artifact bin dep `bar` propagates to `foo`, triggering recompile. p.cargo("check -v -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [DIRTY] bar v0.5.0 ([ROOT]/foo/bar): the file `bar/src/main.rs` has changed ([..]) [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar [..]` [DIRTY] foo v0.1.0 ([ROOT]/foo): the dependency bar was rebuilt [CHECKING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // All units are fresh. No recompile. p.cargo("check -v -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [FRESH] bar v0.5.0 ([ROOT]/foo/bar) [FRESH] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn with_target_and_optional() { // See rust-lang/cargo#10526 if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let p = project() .file( "Cargo.toml", &r#" [package] name = "foo" version = "0.0.1" edition = "2021" [dependencies] d1 = { path = "d1", artifact = "bin", optional = true, target = "$TARGET" } "# .replace("$TARGET", target), ) .file( "src/main.rs", r#" fn main() { let _b = include_bytes!(env!("CARGO_BIN_FILE_D1")); } "#, ) .file( "d1/Cargo.toml", r#" [package] name = "d1" version = "0.0.1" edition = "2021" "#, ) .file("d1/src/main.rs", "fn main() {}") .build(); p.cargo("check -Z bindeps -F d1 -v") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] d1 v0.0.1 ([ROOT]/foo/d1) [RUNNING] `rustc --crate-name d1 [..]--crate-type bin[..] [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]--cfg[..]d1[..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn with_assumed_host_target_and_optional_build_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2021" [build-dependencies] d1 = { path = "d1", artifact = "bin", optional = true, target = "target" } "#, ) .file("src/main.rs", "fn main() {}") .file( "build.rs", r#" fn main() { std::env::var("CARGO_BIN_FILE_D1").unwrap(); } "#, ) .file( "d1/Cargo.toml", r#" [package] name = "d1" version = "0.0.1" edition = "2021" "#, ) .file("d1/src/main.rs", "fn main() {}") .build(); p.cargo("check -Z bindeps -F d1 -v") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data( str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] foo v0.0.1 ([ROOT]/foo) [COMPILING] d1 v0.0.1 ([ROOT]/foo/d1) [RUNNING] `rustc --crate-name build_script_build --edition=2021 [..]--crate-type bin[..] [RUNNING] `rustc --crate-name d1 --edition=2021 [..]--crate-type bin[..] [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo --edition=2021 [..]--cfg[..]d1[..] [FINISHED] `dev` profile [..] "#]] .unordered(), ) .run(); } #[cargo_test] fn decouple_same_target_transitive_dep_from_artifact_dep() { // See https://github.com/rust-lang/cargo/issues/11463 let target = rustc_host(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2021" [dependencies] a = {{ path = "a" }} bar = {{ path = "bar", artifact = "bin", target = "{target}" }} "# ), ) .file( "src/main.rs", r#" fn main() {} "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [dependencies] a = { path = "../a", features = ["feature"] } "#, ) .file( "bar/src/main.rs", r#" fn main() {} "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2021" [dependencies] b = { path = "../b" } c = { path = "../c" } [features] feature = ["c/feature"] "#, ) .file( "a/src/lib.rs", r#" use b::Trait as _; pub fn use_b_trait(x: &impl c::Trait) { x.b(); } "#, ) .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2015" [dependencies] c = { path = "../c" } "#, ) .file( "b/src/lib.rs", r#" pub trait Trait { fn b(&self) {} } impl Trait for T {} "#, ) .file( "c/Cargo.toml", r#" [package] name = "c" version = "0.1.0" edition = "2015" [features] feature = [] "#, ) .file( "c/src/lib.rs", r#" pub trait Trait {} "#, ) .build(); p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 4 packages to latest compatible versions [COMPILING] c v0.1.0 ([ROOT]/foo/c) [COMPILING] b v0.1.0 ([ROOT]/foo/b) [COMPILING] a v0.1.0 ([ROOT]/foo/a) [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn decouple_same_target_transitive_dep_from_artifact_dep_lib() { // See https://github.com/rust-lang/cargo/issues/10837 let target = rustc_host(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2021" [dependencies] a = {{ path = "a" }} b = {{ path = "b", features = ["feature"] }} bar = {{ path = "bar", artifact = "bin", lib = true, target = "{target}" }} "# ), ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2021" [dependencies] a = { path = "../a", features = ["b"] } b = { path = "../b" } "#, ) .file("bar/src/lib.rs", "") .file( "bar/src/main.rs", r#" use b::Trait; fn main() { a::A.b() } "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" [dependencies] b = { path = "../b", optional = true } "#, ) .file( "a/src/lib.rs", r#" pub struct A; #[cfg(feature = "b")] impl b::Trait for A {} "#, ) .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2015" [features] feature = [] "#, ) .file( "b/src/lib.rs", r#" pub trait Trait { fn b(&self) {} } "#, ) .build(); p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 3 packages to latest compatible versions [COMPILING] b v0.1.0 ([ROOT]/foo/b) [COMPILING] a v0.1.0 ([ROOT]/foo/a) [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn decouple_same_target_transitive_dep_from_artifact_dep_and_proc_macro() { let target = rustc_host(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2021" [dependencies] c = {{ path = "c" }} bar = {{ path = "bar", artifact = "bin", target = "{target}" }} "# ), ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [dependencies] b = { path = "../b" } "#, ) .file("bar/src/main.rs", "fn main() {}") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2021" [dependencies] a = { path = "../a" } [lib] proc-macro = true "#, ) .file("b/src/lib.rs", "") .file( "c/Cargo.toml", r#" [package] name = "c" version = "0.1.0" edition = "2021" [dependencies] d = { path = "../d", features = ["feature"] } a = { path = "../a" } [lib] proc-macro = true "#, ) .file( "c/src/lib.rs", r#" use a::Trait; fn _c() { d::D.a() } "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" [dependencies] d = { path = "../d" } "#, ) .file( "a/src/lib.rs", r#" pub trait Trait { fn a(&self) {} } impl Trait for d::D {} "#, ) .file( "d/Cargo.toml", r#" [package] name = "d" version = "0.1.0" edition = "2015" [features] feature = [] "#, ) .file("d/src/lib.rs", "pub struct D;") .build(); p.cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data( str![[r#" [LOCKING] 5 packages to latest compatible versions [COMPILING] d v0.1.0 ([ROOT]/foo/d) [COMPILING] a v0.1.0 ([ROOT]/foo/a) [COMPILING] b v0.1.0 ([ROOT]/foo/b) [COMPILING] c v0.1.0 ([ROOT]/foo/c) [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..] "#]] .unordered(), ) .run(); } #[cargo_test] fn same_target_artifact_dep_sharing() { let target = rustc_host(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] a = {{ path = "a" }} bar = {{ path = "bar", artifact = "bin", target = "{target}" }} "# ), ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [dependencies] a = { path = "../a" } "#, ) .file( "bar/src/main.rs", r#" fn main() {} "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" "#, ) .file("a/src/lib.rs", "") .build(); p.cargo(&format!("build -Z bindeps --target {target}")) .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] a v0.1.0 ([ROOT]/foo/a) [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn check_transitive_artifact_dependency_with_different_target() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" [dependencies] bar = { path = "bar/" } "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.0" edition = "2015" [dependencies] baz = { path = "baz/", artifact = "bin", target = "custom-target" } "#, ) .file("bar/src/lib.rs", "") .file( "bar/baz/Cargo.toml", r#" [package] name = "baz" version = "0.0.0" edition = "2015" [dependencies] "#, ) .file("bar/baz/src/main.rs", "fn main() {}") .build(); p.cargo("check -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [ERROR] failed to determine target information for target `custom-target`. Artifact dependency `baz` in package `bar v0.0.0 ([ROOT]/foo/bar)` requires building for `custom-target` Caused by: failed to run `rustc` to learn about target-specific information Caused by: process didn't exit successfully: `rustc [..] ([EXIT_STATUS]: 1) --- stderr ... "#]]) .with_status(101) .run(); } #[cargo_test] fn build_only_specified_artifact_library() { // Create a project with: // - A crate `bar` with both `staticlib` and `cdylib` as crate-types. // - A crate `foo` which depends on either the `staticlib` or `cdylib` artifact of bar, // whose build-script simply checks which library artifacts are present. let create_project = |artifact_lib| { project() .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "1.0.0" [lib] crate-type = ["staticlib", "cdylib"] "#, ) .file("bar/src/lib.rs", "") .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "1.0.0" [build-dependencies] bar = {{ path = "bar", artifact = "{artifact_lib}" }} "#), ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cdylib present: {}", std::env::var_os("CARGO_CDYLIB_FILE_BAR").is_some()); println!("staticlib present: {}", std::env::var_os("CARGO_STATICLIB_FILE_BAR").is_some()); } "#, ) .build() }; let cdylib = create_project("cdylib"); cdylib .cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .run(); assert_e2e().eq( &build_script_output_string(&cdylib, "foo"), str![[r#" cdylib present: true staticlib present: false "#]], ); let staticlib = create_project("staticlib"); staticlib .cargo("build -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .run(); assert_e2e().eq( &build_script_output_string(&staticlib, "foo"), str![[r#" cdylib present: false staticlib present: true "#]], ); } cargo-0.86.0/tests/testsuite/artifact_dir.rs000064400000000000000000000242261046102023000172140ustar 00000000000000//! Tests for --artifact-dir flag. use std::env; use std::fs; use std::path::Path; use cargo_test_support::prelude::*; use cargo_test_support::sleep_ms; use cargo_test_support::str; use cargo_test_support::{basic_manifest, project}; #[cargo_test] fn binary_with_debug() { let p = project() .file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#) .build(); p.cargo("build -Z unstable-options --artifact-dir out") .masquerade_as_nightly_cargo(&["artifact-dir"]) .enable_mac_dsym() .run(); check_dir_contents( &p.root().join("out"), &["foo"], &["foo", "foo.dSYM"], &["foo.exe", "foo.pdb"], &["foo.exe"], ); } #[cargo_test] fn static_library_with_debug() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [lib] crate-type = ["staticlib"] "#, ) .file( "src/lib.rs", r#" #[no_mangle] pub extern "C" fn foo() { println!("Hello, World!") } "#, ) .build(); p.cargo("build -Z unstable-options --artifact-dir out") .masquerade_as_nightly_cargo(&["artifact-dir"]) .run(); check_dir_contents( &p.root().join("out"), &["libfoo.a"], &["libfoo.a"], &["foo.lib"], &["libfoo.a"], ); } #[cargo_test] fn dynamic_library_with_debug() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [lib] crate-type = ["cdylib"] "#, ) .file( "src/lib.rs", r#" #[no_mangle] pub extern "C" fn foo() { println!("Hello, World!") } "#, ) .build(); p.cargo("build -Z unstable-options --artifact-dir out") .masquerade_as_nightly_cargo(&["artifact-dir"]) .enable_mac_dsym() .run(); check_dir_contents( &p.root().join("out"), &["libfoo.so"], &["libfoo.dylib", "libfoo.dylib.dSYM"], &["foo.dll", "foo.dll.exp", "foo.dll.lib", "foo.pdb"], &["foo.dll", "libfoo.dll.a"], ); } #[cargo_test] fn rlib_with_debug() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [lib] crate-type = ["rlib"] "#, ) .file( "src/lib.rs", r#" pub fn foo() { println!("Hello, World!") } "#, ) .build(); p.cargo("build -Z unstable-options --artifact-dir out") .masquerade_as_nightly_cargo(&["artifact-dir"]) .run(); check_dir_contents( &p.root().join("out"), &["libfoo.rlib"], &["libfoo.rlib"], &["libfoo.rlib"], &["libfoo.rlib"], ); } #[cargo_test] fn include_only_the_binary_from_the_current_package() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [workspace] [dependencies] utils = { path = "./utils" } "#, ) .file("src/lib.rs", "extern crate utils;") .file( "src/main.rs", r#" extern crate foo; extern crate utils; fn main() { println!("Hello, World!") } "#, ) .file("utils/Cargo.toml", &basic_manifest("utils", "0.0.1")) .file("utils/src/lib.rs", "") .build(); p.cargo("build -Z unstable-options --bin foo --artifact-dir out") .masquerade_as_nightly_cargo(&["artifact-dir"]) .enable_mac_dsym() .run(); check_dir_contents( &p.root().join("out"), &["foo"], &["foo", "foo.dSYM"], &["foo.exe", "foo.pdb"], &["foo.exe"], ); } #[cargo_test] fn artifact_dir_is_a_file() { let p = project() .file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#) .file("out", "") .build(); p.cargo("build -Z unstable-options --artifact-dir out") .masquerade_as_nightly_cargo(&["artifact-dir"]) .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [ERROR] failed to create directory `[ROOT]/foo/out` Caused by: ... "#]]) .run(); } #[cargo_test] fn replaces_artifacts() { let p = project() .file("src/main.rs", r#"fn main() { println!("foo") }"#) .build(); p.cargo("build -Z unstable-options --artifact-dir out") .masquerade_as_nightly_cargo(&["artifact-dir"]) .run(); p.process( &p.root() .join(&format!("out/foo{}", env::consts::EXE_SUFFIX)), ) .with_stdout_data(str![[r#" foo "#]]) .run(); sleep_ms(1000); p.change_file("src/main.rs", r#"fn main() { println!("bar") }"#); p.cargo("build -Z unstable-options --artifact-dir out") .masquerade_as_nightly_cargo(&["artifact-dir"]) .run(); p.process( &p.root() .join(&format!("out/foo{}", env::consts::EXE_SUFFIX)), ) .with_stdout_data(str![[r#" bar "#]]) .run(); } #[cargo_test] fn avoid_build_scripts() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/src/main.rs", "fn main() {}") .file("a/build.rs", r#"fn main() { println!("hello-build-a"); }"#) .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/main.rs", "fn main() {}") .file("b/build.rs", r#"fn main() { println!("hello-build-b"); }"#) .build(); p.cargo("build -Z unstable-options --artifact-dir out -vv") .masquerade_as_nightly_cargo(&["artifact-dir"]) .enable_mac_dsym() .with_stdout_data( str![[r#" [a 0.0.1] hello-build-a [b 0.0.1] hello-build-b "#]] .unordered(), ) .run(); check_dir_contents( &p.root().join("out"), &["a", "b"], &["a", "a.dSYM", "b", "b.dSYM"], &["a.exe", "a.pdb", "b.exe", "b.pdb"], &["a.exe", "b.exe"], ); } #[cargo_test] fn cargo_build_artifact_dir() { let p = project() .file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#) .file( ".cargo/config.toml", r#" [build] artifact-dir = "out" "#, ) .build(); p.cargo("build -Z unstable-options") .masquerade_as_nightly_cargo(&["artifact-dir"]) .enable_mac_dsym() .run(); check_dir_contents( &p.root().join("out"), &["foo"], &["foo", "foo.dSYM"], &["foo.exe", "foo.pdb"], &["foo.exe"], ); } #[cargo_test] fn unsupported_short_artifact_dir_flag() { let p = project() .file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#) .build(); p.cargo("build -Z unstable-options -O") .masquerade_as_nightly_cargo(&["artifact-dir"]) .with_stderr_data(str![[r#" [ERROR] unexpected argument '-O' found tip: a similar argument exists: '--artifact-dir' Usage: cargo[EXE] build [OPTIONS] For more information, try '--help'. "#]]) .with_status(1) .run(); } #[cargo_test] fn deprecated_out_dir() { let p = project() .file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#) .build(); p.cargo("build -Z unstable-options --out-dir out") .masquerade_as_nightly_cargo(&["out-dir"]) .enable_mac_dsym() .with_stderr_data(str![[r#" [WARNING] the --out-dir flag has been changed to --artifact-dir [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); check_dir_contents( &p.root().join("out"), &["foo"], &["foo", "foo.dSYM"], &["foo.exe", "foo.pdb"], &["foo.exe"], ); } #[cargo_test] fn cargo_build_deprecated_out_dir() { let p = project() .file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#) .file( ".cargo/config.toml", r#" [build] out-dir = "out" "#, ) .build(); p.cargo("build -Z unstable-options") .masquerade_as_nightly_cargo(&["out-dir"]) .enable_mac_dsym() .with_stderr_data(str![[r#" [WARNING] the out-dir config option has been changed to artifact-dir [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); check_dir_contents( &p.root().join("out"), &["foo"], &["foo", "foo.dSYM"], &["foo.exe", "foo.pdb"], &["foo.exe"], ); } fn check_dir_contents( artifact_dir: &Path, expected_linux: &[&str], expected_mac: &[&str], expected_win_msvc: &[&str], expected_win_gnu: &[&str], ) { let expected = if cfg!(target_os = "windows") { if cfg!(target_env = "msvc") { expected_win_msvc } else { expected_win_gnu } } else if cfg!(target_os = "macos") { expected_mac } else { expected_linux }; let actual = list_dir(artifact_dir); let mut expected = expected.iter().map(|s| s.to_string()).collect::>(); expected.sort_unstable(); assert_eq!(actual, expected); } fn list_dir(dir: &Path) -> Vec { let mut res = Vec::new(); for entry in fs::read_dir(dir).unwrap() { let entry = entry.unwrap(); res.push(entry.file_name().into_string().unwrap()); } res.sort_unstable(); res } cargo-0.86.0/tests/testsuite/bad_config.rs000064400000000000000000002266251046102023000166430ustar 00000000000000//! Tests for some invalid .cargo/config files. use cargo_test_support::git::cargo_uses_gitoxide; use cargo_test_support::prelude::*; use cargo_test_support::registry::{self, Package}; use cargo_test_support::str; use cargo_test_support::{basic_manifest, project, rustc_host}; #[cargo_test] fn bad1() { let p = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [target] nonexistent-target = "foo" "#, ) .build(); p.cargo("check -v --target=nonexistent-target") .with_status(101) .with_stderr_data(str![[r#" [ERROR] expected table for configuration key `target.nonexistent-target`, but found string in [ROOT]/foo/.cargo/config.toml "#]]) .run(); } #[cargo_test] fn bad2() { let p = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [http] proxy = 3.0 "#, ) .build(); p.cargo("publish -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] could not load Cargo configuration Caused by: failed to load TOML configuration from `[ROOT]/foo/.cargo/config.toml` Caused by: failed to parse key `http` Caused by: failed to parse key `proxy` Caused by: found TOML configuration value of unknown type `float` "#]]) .run(); } #[cargo_test] fn bad3() { let registry = registry::init(); let p = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [http] proxy = true "#, ) .build(); Package::new("foo", "1.0.0").publish(); p.cargo("publish -v") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to update registry `crates-io` Caused by: error in [ROOT]/foo/.cargo/config.toml: `http.proxy` expected a string, but found a boolean "#]]) .run(); } #[cargo_test] fn bad4() { let p = project() .file( ".cargo/config.toml", r#" [cargo-new] vcs = false "#, ) .build(); p.cargo("new -v foo") .with_status(101) .with_stderr_data(str![[r#" [CREATING] binary (application) `foo` package [ERROR] Failed to create package `foo` at `[ROOT]/foo/foo` Caused by: error in [ROOT]/foo/.cargo/config.toml: `cargo-new.vcs` expected a string, but found a boolean "#]]) .run(); } #[cargo_test] fn bad6() { let registry = registry::init(); let p = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [http] user-agent = true "#, ) .build(); Package::new("foo", "1.0.0").publish(); p.cargo("publish -v") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to update registry `crates-io` Caused by: error in [ROOT]/foo/.cargo/config.toml: `http.user-agent` expected a string, but found a boolean "#]]) .run(); } #[cargo_test] fn invalid_global_config() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] foo = "0.1.0" "#, ) .file(".cargo/config.toml", "4") .file("src/lib.rs", "") .build(); p.cargo("check -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] could not load Cargo configuration Caused by: could not parse TOML configuration in `[ROOT]/foo/.cargo/config.toml` Caused by: TOML parse error at line 1, column 2 | 1 | 4 | ^ expected `.`, `=` "#]]) .run(); } #[cargo_test] fn bad_cargo_lock() { let p = project() .file("Cargo.lock", "[[package]]\nfoo = 92") .file("src/lib.rs", "") .build(); p.cargo("check -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse lock file at: [ROOT]/foo/Cargo.lock Caused by: TOML parse error at line 1, column 1 | 1 | [[package]] | ^^^^^^^^^^^ missing field `name` "#]]) .run(); } #[cargo_test] fn duplicate_packages_in_cargo_lock() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .file( "Cargo.lock", r#" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" "#, ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse lock file at: [ROOT]/foo/Cargo.lock Caused by: package `bar` is specified twice in the lockfile "#]]) .run(); } #[cargo_test] fn bad_source_in_cargo_lock() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .file( "Cargo.lock", r#" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bar" version = "0.1.0" source = "You shall not parse" "#, ) .build(); p.cargo("check --verbose") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse lock file at: [ROOT]/foo/Cargo.lock Caused by: TOML parse error at line 12, column 26 | 12 | source = "You shall not parse" | ^^^^^^^^^^^^^^^^^^^^^ invalid source `You shall not parse` "#]]) .run(); } #[cargo_test] fn bad_dependency_in_lockfile() { let p = project() .file("src/lib.rs", "") .file( "Cargo.lock", r#" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] "#, ) .build(); p.cargo("check").run(); } #[cargo_test] fn bad_git_dependency() { let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] foo = {{ git = "{url}" }} "#, url = if cargo_uses_gitoxide() { "git://host.xz" } else { "file:.." } ), ) .file("src/lib.rs", "") .build(); if cargo_uses_gitoxide() { p.cargo("check -v") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] git repository `git://host.xz` [ERROR] failed to get `foo` as a dependency of package `foo v0.0.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `foo` Caused by: Unable to update git://host.xz Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/_empty-[HASH] Caused by: URL "git://host.xz" does not specify a path to a repository "#]]) .run(); } else { p.cargo("check -v") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] git repository `file:///` [ERROR] failed to get `foo` as a dependency of package `foo v0.0.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `foo` Caused by: Unable to update file:/// Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/_empty-[HASH] Caused by: 'file:///' is not a valid local file URI; class=Config (7) "#]]) .run(); }; } #[cargo_test] fn bad_crate_type() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [lib] crate-type = ["bad_type", "rlib"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about crate-type bad_type information Caused by: process didn't exit successfully: `rustc - --crate-name ___ --print=file-names --crate-type bad_type` ([EXIT_STATUS]: 1) --- stderr [ERROR] unknown crate type: `bad_type`[..] "#]]) .run(); } #[cargo_test] fn malformed_override() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [target.x86_64-apple-darwin.freetype] native = { foo: "bar" } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid inline table expected `}` --> Cargo.toml:9:27 | 9 | native = { | ^ | "#]]) .run(); } #[cargo_test] fn duplicate_binary_names() { let p = project() .file( "Cargo.toml", r#" [package] name = "qqq" version = "0.1.0" edition = "2015" authors = ["A "] [[bin]] name = "e" path = "a.rs" [[bin]] name = "e" path = "b.rs" "#, ) .file("a.rs", r#"fn main() -> () {}"#) .file("b.rs", r#"fn main() -> () {}"#) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: found duplicate binary name e, but all binary targets must have a unique name "#]]) .run(); } #[cargo_test] fn duplicate_example_names() { let p = project() .file( "Cargo.toml", r#" [package] name = "qqq" version = "0.1.0" edition = "2015" authors = ["A "] [[example]] name = "ex" path = "examples/ex.rs" [[example]] name = "ex" path = "examples/ex2.rs" "#, ) .file("examples/ex.rs", r#"fn main () -> () {}"#) .file("examples/ex2.rs", r#"fn main () -> () {}"#) .build(); p.cargo("check --example ex") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: found duplicate example name ex, but all example targets must have a unique name "#]]) .run(); } #[cargo_test] fn duplicate_bench_names() { let p = project() .file( "Cargo.toml", r#" [package] name = "qqq" version = "0.1.0" edition = "2015" authors = ["A "] [[bench]] name = "ex" path = "benches/ex.rs" [[bench]] name = "ex" path = "benches/ex2.rs" "#, ) .file("benches/ex.rs", r#"fn main () {}"#) .file("benches/ex2.rs", r#"fn main () {}"#) .build(); p.cargo("bench") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: found duplicate bench name ex, but all bench targets must have a unique name "#]]) .run(); } #[cargo_test] fn duplicate_deps() { let p = project() .file("shim-bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("shim-bar/src/lib.rs", "pub fn a() {}") .file("linux-bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("linux-bar/src/lib.rs", "pub fn a() {}") .file( "Cargo.toml", r#" [package] name = "qqq" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = { path = "shim-bar" } [target.x86_64-unknown-linux-gnu.dependencies] bar = { path = "linux-bar" } "#, ) .file("src/main.rs", r#"fn main () {}"#) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: Dependency 'bar' has different source paths depending on the build target. Each dependency must have a single canonical source path irrespective of build target. "#]]) .run(); } #[cargo_test] fn duplicate_deps_diff_sources() { let p = project() .file("shim-bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("shim-bar/src/lib.rs", "pub fn a() {}") .file("linux-bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("linux-bar/src/lib.rs", "pub fn a() {}") .file( "Cargo.toml", r#" [package] name = "qqq" version = "0.0.1" edition = "2015" authors = [] [target.i686-unknown-linux-gnu.dependencies] bar = { path = "shim-bar" } [target.x86_64-unknown-linux-gnu.dependencies] bar = { path = "linux-bar" } "#, ) .file("src/main.rs", r#"fn main () {}"#) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: Dependency 'bar' has different source paths depending on the build target. Each dependency must have a single canonical source path irrespective of build target. "#]]) .run(); } #[cargo_test] fn unused_keys() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [target.foo] bar = "3" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] unused manifest key: target.foo.bar [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] bulid = "foo" "#, ) .file("src/lib.rs", "pub fn foo() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] unused manifest key: package.bulid [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let p = project() .at("bar") .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [lib] build = "foo" "#, ) .file("src/lib.rs", "pub fn foo() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] unused manifest key: lib.build [CHECKING] foo v0.5.0 ([ROOT]/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn unused_keys_in_virtual_manifest() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] bulid = "foo" "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("check --workspace") .with_stderr_data(str![[r#" [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: workspace.bulid [CHECKING] bar v0.0.1 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn empty_dependencies() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] bar = {} "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").publish(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: dependency (bar) specified without providing a local path, Git repository, version, or workspace dependency to use "#]]) .run(); } #[cargo_test] fn dev_dependencies2() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dev_dependencies] a = {path = "a"} "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] `dev_dependencies` is deprecated in favor of `dev-dependencies` and will not work in the 2024 edition (in the `foo` package) [LOCKING] 1 package to latest compatible version [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn dev_dependencies2_2024() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2024" [dev_dependencies] a = {path = "a"} "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `dev_dependencies` is unsupported as of the 2024 edition; instead use `dev-dependencies` (in the `foo` package) "#]]) .run(); } #[cargo_test] fn dev_dependencies2_conflict() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dev-dependencies] a = {path = "a"} [dev_dependencies] a = {path = "a"} "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] `dev_dependencies` is redundant with `dev-dependencies`, preferring `dev-dependencies` in the `foo` package [LOCKING] 1 package to latest compatible version [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn build_dependencies2() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [build_dependencies] a = {path = "a"} "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] `build_dependencies` is deprecated in favor of `build-dependencies` and will not work in the 2024 edition (in the `foo` package) [LOCKING] 1 package to latest compatible version [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn build_dependencies2_2024() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2024" [build_dependencies] a = {path = "a"} "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `build_dependencies` is unsupported as of the 2024 edition; instead use `build-dependencies` (in the `foo` package) "#]]) .run(); } #[cargo_test] fn build_dependencies2_conflict() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [build-dependencies] a = {path = "a"} [build_dependencies] a = {path = "a"} "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] `build_dependencies` is redundant with `build-dependencies`, preferring `build-dependencies` in the `foo` package [LOCKING] 1 package to latest compatible version [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn lib_crate_type2() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [lib] name = "foo" crate_type = ["staticlib", "dylib"] "#, ) .file("src/lib.rs", "pub fn foo() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] `crate_type` is deprecated in favor of `crate-type` and will not work in the 2024 edition (in the `foo` library target) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn lib_crate_type2_2024() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2024" authors = ["wycats@example.com"] [lib] name = "foo" crate_type = ["staticlib", "dylib"] "#, ) .file("src/lib.rs", "pub fn foo() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `crate_type` is unsupported as of the 2024 edition; instead use `crate-type` (in the `foo` library target) "#]]) .run(); } #[cargo_test] fn lib_crate_type2_conflict() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [lib] name = "foo" crate-type = ["rlib", "dylib"] crate_type = ["staticlib", "dylib"] "#, ) .file("src/lib.rs", "pub fn foo() {}") .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] `crate_type` is redundant with `crate-type`, preferring `crate-type` in the `foo` library target [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn bin_crate_type2() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [[bin]] name = "foo" path = "src/main.rs" crate_type = [] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] `crate_type` is deprecated in favor of `crate-type` and will not work in the 2024 edition (in the `foo` binary target) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn bin_crate_type2_2024() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2024" authors = ["wycats@example.com"] [[bin]] name = "foo" path = "src/main.rs" crate_type = [] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `crate_type` is unsupported as of the 2024 edition; instead use `crate-type` (in the `foo` binary target) "#]]) .run(); } #[cargo_test] fn bin_crate_type2_conflict() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [[bin]] name = "foo" path = "src/main.rs" crate_type = [] crate-type = [] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] `crate_type` is redundant with `crate-type`, preferring `crate-type` in the `foo` binary target [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn examples_crate_type2() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [[example]] name = "ex" path = "examples/ex.rs" crate_type = ["proc_macro"] [[example]] name = "goodbye" path = "examples/ex-goodbye.rs" crate_type = ["rlib", "staticlib"] "#, ) .file("src/lib.rs", "") .file( "examples/ex.rs", r#" fn main() { println!("ex"); } "#, ) .file( "examples/ex-goodbye.rs", r#" fn main() { println!("goodbye"); } "#, ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] `crate_type` is deprecated in favor of `crate-type` and will not work in the 2024 edition (in the `ex` example target) [WARNING] `crate_type` is deprecated in favor of `crate-type` and will not work in the 2024 edition (in the `goodbye` example target) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn examples_crate_type2_2024() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2024" authors = ["wycats@example.com"] [[example]] name = "ex" path = "examples/ex.rs" crate_type = ["proc_macro"] [[example]] name = "goodbye" path = "examples/ex-goodbye.rs" crate_type = ["rlib", "staticlib"] "#, ) .file("src/lib.rs", "") .file( "examples/ex.rs", r#" fn main() { println!("ex"); } "#, ) .file( "examples/ex-goodbye.rs", r#" fn main() { println!("goodbye"); } "#, ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `crate_type` is unsupported as of the 2024 edition; instead use `crate-type` (in the `ex` example target) "#]]) .run(); } #[cargo_test] fn examples_crate_type2_conflict() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [[example]] name = "ex" path = "examples/ex.rs" crate-type = ["rlib", "dylib"] crate_type = ["proc_macro"] [[example]] name = "goodbye" path = "examples/ex-goodbye.rs" crate-type = ["rlib", "dylib"] crate_type = ["rlib", "staticlib"] "#, ) .file("src/lib.rs", "") .file( "examples/ex.rs", r#" fn main() { println!("ex"); } "#, ) .file( "examples/ex-goodbye.rs", r#" fn main() { println!("goodbye"); } "#, ) .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] `crate_type` is redundant with `crate-type`, preferring `crate-type` in the `ex` example target [WARNING] `crate_type` is redundant with `crate-type`, preferring `crate-type` in the `goodbye` example target [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn cargo_platform_build_dependencies2() { let host = rustc_host(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] build = "build.rs" [target.{host}.build_dependencies] build = {{ path = "build" }} "#, host = host ), ) .file("src/main.rs", "fn main() { }") .file( "build.rs", "extern crate build; fn main() { build::build(); }", ) .file("build/Cargo.toml", &basic_manifest("build", "0.5.0")) .file("build/src/lib.rs", "pub fn build() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] `build_dependencies` is deprecated in favor of `build-dependencies` and will not work in the 2024 edition (in the `[HOST_TARGET]` platform target) [LOCKING] 1 package to latest compatible version [COMPILING] build v0.5.0 ([ROOT]/foo/build) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] ) .run(); } #[cargo_test] fn cargo_platform_build_dependencies2_2024() { let host = rustc_host(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2024" authors = ["wycats@example.com"] build = "build.rs" [target.{host}.build_dependencies] build = {{ path = "build" }} "#, host = host ), ) .file("src/main.rs", "fn main() { }") .file( "build.rs", "extern crate build; fn main() { build::build(); }", ) .file("build/Cargo.toml", &basic_manifest("build", "0.5.0")) .file("build/src/lib.rs", "pub fn build() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `build_dependencies` is unsupported as of the 2024 edition; instead use `build-dependencies` (in the `[HOST_TARGET]` platform target) "#]]) .run(); } #[cargo_test] fn cargo_platform_build_dependencies2_conflict() { let host = rustc_host(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] build = "build.rs" [target.{host}.build-dependencies] build = {{ path = "build" }} [target.{host}.build_dependencies] build = {{ path = "build" }} "#, host = host ), ) .file("src/main.rs", "fn main() { }") .file( "build.rs", "extern crate build; fn main() { build::build(); }", ) .file("build/Cargo.toml", &basic_manifest("build", "0.5.0")) .file("build/src/lib.rs", "pub fn build() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] `build_dependencies` is redundant with `build-dependencies`, preferring `build-dependencies` in the `[HOST_TARGET]` platform target [LOCKING] 1 package to latest compatible version [COMPILING] build v0.5.0 ([ROOT]/foo/build) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cargo_platform_dev_dependencies2() { let host = rustc_host(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [target.{host}.dev_dependencies] dev = {{ path = "dev" }} "#, host = host ), ) .file("src/main.rs", "fn main() { }") .file( "tests/foo.rs", "extern crate dev; #[test] fn foo() { dev::dev() }", ) .file("dev/Cargo.toml", &basic_manifest("dev", "0.5.0")) .file("dev/src/lib.rs", "pub fn dev() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] `dev_dependencies` is deprecated in favor of `dev-dependencies` and will not work in the 2024 edition (in the `[HOST_TARGET]` platform target) [LOCKING] 1 package to latest compatible version [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cargo_platform_dev_dependencies2_2024() { let host = rustc_host(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2024" authors = ["wycats@example.com"] [target.{host}.dev_dependencies] dev = {{ path = "dev" }} "#, host = host ), ) .file("src/main.rs", "fn main() { }") .file( "tests/foo.rs", "extern crate dev; #[test] fn foo() { dev::dev() }", ) .file("dev/Cargo.toml", &basic_manifest("dev", "0.5.0")) .file("dev/src/lib.rs", "pub fn dev() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `dev_dependencies` is unsupported as of the 2024 edition; instead use `dev-dependencies` (in the `[HOST_TARGET]` platform target) "#]]) .run(); } #[cargo_test] fn cargo_platform_dev_dependencies2_conflict() { let host = rustc_host(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [target.{host}.dev-dependencies] dev = {{ path = "dev" }} [target.{host}.dev_dependencies] dev = {{ path = "dev" }} "#, host = host ), ) .file("src/main.rs", "fn main() { }") .file( "tests/foo.rs", "extern crate dev; #[test] fn foo() { dev::dev() }", ) .file("dev/Cargo.toml", &basic_manifest("dev", "0.5.0")) .file("dev/src/lib.rs", "pub fn dev() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] `dev_dependencies` is redundant with `dev-dependencies`, preferring `dev-dependencies` in the `[HOST_TARGET]` platform target [LOCKING] 1 package to latest compatible version [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn default_features2() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] a = { path = "a", features = ["f1"], default_features = false } "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" authors = [] [features] default = ["f1"] f1 = [] "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] `default_features` is deprecated in favor of `default-features` and will not work in the 2024 edition (in the `a` dependency) [LOCKING] 1 package to latest compatible version [CHECKING] a v0.1.0 ([ROOT]/foo/a) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn default_features2_2024() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2024" authors = [] [dependencies] a = { path = "a", features = ["f1"], default_features = false } "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" authors = [] [features] default = ["f1"] f1 = [] "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `default_features` is unsupported as of the 2024 edition; instead use `default-features` (in the `a` dependency) "#]]) .run(); } #[cargo_test] fn default_features2_conflict() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] a = { path = "a", features = ["f1"], default-features = false, default_features = false } "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" authors = [] [features] default = ["f1"] f1 = [] "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] `default_features` is redundant with `default-features`, preferring `default-features` in the `a` dependency [LOCKING] 1 package to latest compatible version [CHECKING] a v0.1.0 ([ROOT]/foo/a) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn workspace_default_features2() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["workspace_only", "dep_workspace_only", "package_only", "dep_package_only"] [workspace.dependencies] dep_workspace_only = { path = "dep_workspace_only", default_features = true } dep_package_only = { path = "dep_package_only" } "#, ) .file( "workspace_only/Cargo.toml", r#" [package] name = "workspace_only" version = "0.1.0" edition = "2015" authors = [] [dependencies] dep_workspace_only.workspace = true "#, ) .file("workspace_only/src/lib.rs", "") .file( "dep_workspace_only/Cargo.toml", r#" [package] name = "dep_workspace_only" version = "0.1.0" edition = "2015" authors = [] "#, ) .file("dep_workspace_only/src/lib.rs", "") .file( "package_only/Cargo.toml", r#" [package] name = "package_only" version = "0.1.0" edition = "2015" authors = [] [dependencies] dep_package_only = { workspace = true, default_features = true } "#, ) .file("package_only/src/lib.rs", "") .file( "dep_package_only/Cargo.toml", r#" [package] name = "dep_package_only" version = "0.1.0" edition = "2015" authors = [] "#, ) .file("dep_package_only/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data( str![[r#" [WARNING] [ROOT]/foo/workspace_only/Cargo.toml: `default_features` is deprecated in favor of `default-features` and will not work in the 2024 edition (in the `dep_workspace_only` dependency) [CHECKING] dep_package_only v0.1.0 ([ROOT]/foo/dep_package_only) [CHECKING] dep_workspace_only v0.1.0 ([ROOT]/foo/dep_workspace_only) [CHECKING] package_only v0.1.0 ([ROOT]/foo/package_only) [CHECKING] workspace_only v0.1.0 ([ROOT]/foo/workspace_only) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn workspace_default_features2_2024() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["workspace_only", "dep_workspace_only", "package_only", "dep_package_only"] [workspace.dependencies] dep_workspace_only = { path = "dep_workspace_only", default_features = true } dep_package_only = { path = "dep_package_only" } "#, ) .file( "workspace_only/Cargo.toml", r#" [package] name = "workspace_only" version = "0.1.0" edition = "2024" authors = [] [dependencies] dep_workspace_only.workspace = true "#, ) .file("workspace_only/src/lib.rs", "") .file( "dep_workspace_only/Cargo.toml", r#" [package] name = "dep_workspace_only" version = "0.1.0" edition = "2024" authors = [] "#, ) .file("dep_workspace_only/src/lib.rs", "") .file( "package_only/Cargo.toml", r#" [package] name = "package_only" version = "0.1.0" edition = "2024" authors = [] [dependencies] dep_package_only = { workspace = true, default_features = true } "#, ) .file("package_only/src/lib.rs", "") .file( "dep_package_only/Cargo.toml", r#" [package] name = "dep_package_only" version = "0.1.0" edition = "2024" authors = [] "#, ) .file("dep_package_only/src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to load manifest for workspace member `[ROOT]/foo/workspace_only` referenced by workspace at `[ROOT]/foo/Cargo.toml` Caused by: failed to parse manifest at `[ROOT]/foo/workspace_only/Cargo.toml` Caused by: `default_features` is unsupported as of the 2024 edition; instead use `default-features` (in the `dep_workspace_only` dependency) "#]]) .run(); } #[cargo_test] fn lib_proc_macro2() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] proc_macro = true "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") .with_stderr_data(str![[r#" [WARNING] `proc_macro` is deprecated in favor of `proc-macro` and will not work in the 2024 edition (in the `foo` library target) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn lib_proc_macro2_2024() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2024" [lib] proc_macro = true "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `proc_macro` is unsupported as of the 2024 edition; instead use `proc-macro` (in the `foo` library target) "#]]) .run(); } #[cargo_test] fn lib_proc_macro2_conflict() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] proc-macro = false proc_macro = true "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check").with_stderr_data(str![[r#" [WARNING] `proc_macro` is redundant with `proc-macro`, preferring `proc-macro` in the `foo` library target [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn bin_proc_macro2() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [[bin]] name = "foo" path = "src/main.rs" proc_macro = false "#, ) .file("src/main.rs", "fn main() {}") .build(); foo.cargo("check") .with_stderr_data(str![[r#" [WARNING] `proc_macro` is deprecated in favor of `proc-macro` and will not work in the 2024 edition (in the `foo` binary target) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn bin_proc_macro2_2024() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2024" authors = ["wycats@example.com"] [[bin]] name = "foo" path = "src/main.rs" proc_macro = false "#, ) .file("src/main.rs", "fn main() {}") .build(); foo.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `proc_macro` is unsupported as of the 2024 edition; instead use `proc-macro` (in the `foo` binary target) "#]]) .run(); } #[cargo_test] fn bin_proc_macro2_conflict() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [[bin]] name = "foo" path = "src/main.rs" proc-macro = false proc_macro = false "#, ) .file("src/main.rs", "fn main() {}") .build(); foo.cargo("check").with_stderr_data(str![[r#" [WARNING] `proc_macro` is redundant with `proc-macro`, preferring `proc-macro` in the `foo` binary target [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn invalid_toml_historically_allowed_fails() { let p = project() .file(".cargo/config.toml", "[bar] baz = 2") .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] could not load Cargo configuration Caused by: could not parse TOML configuration in `[ROOT]/foo/.cargo/config.toml` Caused by: TOML parse error at line 1, column 7 | 1 | [bar] baz = 2 | ^ invalid table header expected newline, `#` "#]]) .run(); } #[cargo_test] fn ambiguous_git_reference() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies.bar] git = "http://127.0.0.1" branch = "master" tag = "some-tag" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: dependency (bar) specification is ambiguous. Only one of `branch`, `tag` or `rev` is allowed. "#]]) .run(); } #[cargo_test] fn fragment_in_git_url() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies.bar] git = "http://127.0.0.1#foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -v") .with_status(101) // the following is needed as gitoxide has a different error message // ... // [..]127.0.0.1[..] .with_stderr_data(str![[r#" [WARNING] URL fragment `#foo` in git URL is ignored for dependency (bar). If you were trying to specify a specific git revision, use `rev = "foo"` in the dependency declaration. [UPDATING] git repository `http://127.0.0.1/#foo` ... [ERROR] failed to get `bar` as a dependency of package `foo v0.0.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update http://127.0.0.1/#foo Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/_empty-[HASH] ... "#]]) .run(); } #[cargo_test] fn bad_source_config1() { let p = project() .file("src/lib.rs", "") .file(".cargo/config.toml", "[source.foo]") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no source location specified for `source.foo`, need `registry`, `local-registry`, `directory`, or `git` defined "#]]) .run(); } #[cargo_test] fn bad_source_config2() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [source.crates-io] registry = 'http://example.com' replace-with = 'bar' "#, ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to get `bar` as a dependency of package `foo v0.0.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update registry `crates-io` Caused by: could not find a configured source with the name `bar` when attempting to lookup `crates-io` (configuration in `[ROOT]/foo/.cargo/config.toml`) "#]]) .run(); } #[cargo_test] fn bad_source_config3() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [source.crates-io] registry = 'https://example.com' replace-with = 'crates-io' "#, ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to get `bar` as a dependency of package `foo v0.0.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update registry `crates-io` Caused by: detected a cycle of `replace-with` sources, the source `crates-io` is eventually replaced with itself (configuration in `[ROOT]/foo/.cargo/config.toml`) "#]]) .run(); } #[cargo_test] fn bad_source_config4() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [source.crates-io] replace-with = 'bar' [source.bar] registry = 'https://example.com' replace-with = 'crates-io' "#, ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to get `bar` as a dependency of package `foo v0.0.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update registry `crates-io` Caused by: detected a cycle of `replace-with` sources, the source `crates-io` is eventually replaced with itself (configuration in `[ROOT]/foo/.cargo/config.toml`) "#]]) .run(); } #[cargo_test] fn bad_source_config5() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [source.crates-io] registry = 'https://example.com' replace-with = 'bar' [source.bar] registry = 'not a url' "#, ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] configuration key `source.bar.registry` specified an invalid URL (in [ROOT]/foo/.cargo/config.toml) Caused by: invalid url `not a url`: relative URL without a base "#]]) .run(); } #[cargo_test] fn both_git_and_path_specified() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies.bar] git = "http://127.0.0.1" path = "bar" "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: dependency (bar) specification is ambiguous. Only one of `git` or `path` is allowed. "#]]) .run(); } #[cargo_test] fn bad_source_config6() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [source.crates-io] registry = 'https://example.com' replace-with = ['not', 'a', 'string'] "#, ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] error in [ROOT]/foo/.cargo/config.toml: could not load config key `source.crates-io.replace-with` Caused by: error in [ROOT]/foo/.cargo/config.toml: `source.crates-io.replace-with` expected a string, but found a array "#]]) .run(); } #[cargo_test] fn ignored_git_revision() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies.bar] path = "bar" branch = "spam" "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: key `branch` is ignored for dependency (bar). "#]]) .run(); // #11540, check that [target] dependencies fail the same way. foo.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" [target.some-target.dependencies] bar = { path = "bar", branch = "spam" } "#, ); foo.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: key `branch` is ignored for dependency (bar). "#]]) .run(); } #[cargo_test] fn bad_source_config7() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [source.foo] registry = 'https://example.com' local-registry = 'file:///another/file' "#, ) .build(); Package::new("bar", "0.1.0").publish(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] more than one source location specified for `source.foo` "#]]) .run(); } #[cargo_test] fn bad_source_config8() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [source.foo] branch = "somebranch" "#, ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] source definition `source.foo` specifies `branch`, but that requires a `git` key to be specified (in [ROOT]/foo/.cargo/config.toml) "#]]) .run(); } #[cargo_test] fn bad_dependency() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] bar = 3 "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid type: integer `3`, expected a version string like "0.9.8" or a detailed dependency like { version = "0.9.8" } --> Cargo.toml:9:23 | 9 | bar = 3 | ^ | "#]]) .run(); } #[cargo_test] fn bad_debuginfo() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [profile.dev] debug = 'a' "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid value: string "a", expected a boolean, 0, 1, 2, "none", "limited", "full", "line-tables-only", or "line-directives-only" --> Cargo.toml:9:25 | 9 | debug = 'a' | ^^^ | "#]]) .run(); } #[cargo_test] fn bad_debuginfo2() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [profile.dev] debug = 3.6 "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid type: floating point `3.6`, expected a boolean, 0, 1, 2, "none", "limited", "full", "line-tables-only", or "line-directives-only" --> Cargo.toml:9:25 | 9 | debug = 3.6 | ^^^ | "#]]) .run(); } #[cargo_test] fn bad_opt_level() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] build = 3 "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid type: integer `3`, expected a boolean or string --> Cargo.toml:7:25 | 7 | build = 3 | ^ | "#]]) .run(); } #[cargo_test] fn warn_semver_metadata() { Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" [dependencies] bar = "1.0.0+1234" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] version requirement `1.0.0+1234` for dependency `bar` includes semver metadata which will be ignored, removing the metadata is recommended to avoid confusion [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [CHECKING] bar v1.0.0 [CHECKING] foo v1.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn bad_http_ssl_version() { // Invalid type in SslVersionConfig. let p = project() .file( ".cargo/config.toml", r#" [http] ssl-version = ["tlsv1.2", "tlsv1.3"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] error in [ROOT]/foo/.cargo/config.toml: could not load config key `http.ssl-version` Caused by: invalid type: sequence, expected a string or map "#]]) .run(); } #[cargo_test] fn bad_http_ssl_version_range() { // Invalid type in SslVersionConfigRange. let p = project() .file( ".cargo/config.toml", r#" [http] ssl-version.min = false "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] error in [ROOT]/foo/.cargo/config.toml: could not load config key `http.ssl-version` Caused by: error in [ROOT]/foo/.cargo/config.toml: `http.ssl-version.min` expected a string, but found a boolean "#]]) .run(); } #[cargo_test] fn bad_build_jobs() { // Invalid type in JobsConfig. let p = project() .file( ".cargo/config.toml", r#" [build] jobs = { default = true } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] error in [ROOT]/foo/.cargo/config.toml: could not load config key `build.jobs` Caused by: invalid type: map, expected an integer or string "#]]) .run(); } #[cargo_test] fn bad_build_target() { // Invalid type in BuildTargetConfig. let p = project() .file( ".cargo/config.toml", r#" [build] target.'cfg(unix)' = "x86_64" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] error in [ROOT]/foo/.cargo/config.toml: could not load config key `build.target` Caused by: error in [ROOT]/foo/.cargo/config.toml: could not load config key `build.target` Caused by: invalid type: map, expected a string or array "#]]) .run(); } #[cargo_test] fn bad_target_cfg() { // Invalid type in a StringList. // // The error message is a bit unfortunate here. The type here ends up // being essentially Value>, and each layer of "Value" // adds some context to the error message. Also, untagged enums provide // strange error messages. Hopefully most users will be able to untangle // the message. let p = project() .file( ".cargo/config.toml", r#" [target.'cfg(not(target_os = "none"))'] runner = false "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] error in [ROOT]/foo/.cargo/config.toml: could not load config key `target.'cfg(not(target_os = "none"))'.runner` Caused by: error in [ROOT]/foo/.cargo/config.toml: could not load config key `target.'cfg(not(target_os = "none"))'.runner` Caused by: invalid configuration for key `target.'cfg(not(target_os = "none"))'.runner` expected a string or array of strings, but found a boolean for `target.'cfg(not(target_os = "none"))'.runner` in [ROOT]/foo/.cargo/config.toml "#]]) .run(); } #[cargo_test] fn bad_target_links_overrides() { // Invalid parsing of links overrides. // // This error message is terrible. Nothing in the deserialization path is // using config::Value<>, so nothing is able to report the location. I // think this illustrates how the way things break down with how it // currently is designed with serde. let p = project() .file( ".cargo/config.toml", &format!( r#" [target.{}.somelib] rustc-flags = 'foo' "#, rustc_host() ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r" [ERROR] Only `-l` and `-L` flags are allowed in target config `target.[..].rustc-flags` (in [..]foo/.cargo/config.toml): `foo` "]]) .run(); p.change_file( ".cargo/config.toml", &format!( "[target.{}.somelib] warning = \"foo\" ", rustc_host(), ), ); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `warning` is not supported in build script overrides "#]]) .run(); } #[cargo_test] fn redefined_sources() { // Cannot define a source multiple times. let p = project() .file( ".cargo/config.toml", r#" [source.foo] registry = "https://github.com/rust-lang/crates.io-index" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] source `foo` defines source registry `crates-io`, but that source is already defined by `crates-io` [NOTE] Sources are not allowed to be defined multiple times. "#]]) .run(); p.change_file( ".cargo/config.toml", r#" [source.one] directory = "index" [source.two] directory = "index" "#, ); // Name is `[..]` because we can't guarantee the order. p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] source `[..]` defines source dir [ROOT]/foo/index, but that source is already defined by `[..]` [NOTE] Sources are not allowed to be defined multiple times. "#]]) .run(); } #[cargo_test] fn bad_trim_paths() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" [profile.dev] trim-paths = "split-debuginfo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -Ztrim-paths") .masquerade_as_nightly_cargo(&["trim-paths"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] expected a boolean, "none", "diagnostics", "macro", "object", "all", or an array with these options --> Cargo.toml:8:30 | 8 | trim-paths = "split-debuginfo" | ^^^^^^^^^^^^^^^^^ | "#]]) .run(); } cargo-0.86.0/tests/testsuite/bad_manifest_path.rs000064400000000000000000000223111046102023000202020ustar 00000000000000//! Tests for invalid --manifest-path arguments. use cargo_test_support::prelude::*; use cargo_test_support::{basic_bin_manifest, main_file, project, str}; #[track_caller] fn assert_not_a_cargo_toml(command: &str, manifest_path_argument: &str) { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo(command) .arg("--manifest-path") .arg(manifest_path_argument) .cwd(p.root().parent().unwrap()) .with_status(101) .with_stderr_data("[ERROR] the manifest-path must be a path to a Cargo.toml file\n") .run(); } #[track_caller] fn assert_cargo_toml_doesnt_exist(command: &str, manifest_path_argument: &str) { let p = project().build(); let expected_path = manifest_path_argument .split('/') .collect::>() .join("[..]"); p.cargo(command) .arg("--manifest-path") .arg(manifest_path_argument) .cwd(p.root().parent().unwrap()) .with_status(101) .with_stderr_data(format!( "[ERROR] manifest path `{}` does not exist\n", expected_path )) .run(); } #[cargo_test] fn bench_dir_containing_cargo_toml() { assert_not_a_cargo_toml("bench", "foo"); } #[cargo_test] fn bench_dir_plus_file() { assert_not_a_cargo_toml("bench", "foo/bar"); } #[cargo_test] fn bench_dir_plus_path() { assert_not_a_cargo_toml("bench", "foo/bar/baz"); } #[cargo_test] fn bench_dir_to_nonexistent_cargo_toml() { assert_cargo_toml_doesnt_exist("bench", "foo/bar/baz/Cargo.toml"); } #[cargo_test] fn build_dir_containing_cargo_toml() { assert_not_a_cargo_toml("check", "foo"); } #[cargo_test] fn build_dir_plus_file() { assert_not_a_cargo_toml("bench", "foo/bar"); } #[cargo_test] fn build_dir_plus_path() { assert_not_a_cargo_toml("bench", "foo/bar/baz"); } #[cargo_test] fn build_dir_to_nonexistent_cargo_toml() { assert_cargo_toml_doesnt_exist("check", "foo/bar/baz/Cargo.toml"); } #[cargo_test] fn clean_dir_containing_cargo_toml() { assert_not_a_cargo_toml("clean", "foo"); } #[cargo_test] fn clean_dir_plus_file() { assert_not_a_cargo_toml("clean", "foo/bar"); } #[cargo_test] fn clean_dir_plus_path() { assert_not_a_cargo_toml("clean", "foo/bar/baz"); } #[cargo_test] fn clean_dir_to_nonexistent_cargo_toml() { assert_cargo_toml_doesnt_exist("clean", "foo/bar/baz/Cargo.toml"); } #[cargo_test] fn doc_dir_containing_cargo_toml() { assert_not_a_cargo_toml("doc", "foo"); } #[cargo_test] fn doc_dir_plus_file() { assert_not_a_cargo_toml("doc", "foo/bar"); } #[cargo_test] fn doc_dir_plus_path() { assert_not_a_cargo_toml("doc", "foo/bar/baz"); } #[cargo_test] fn doc_dir_to_nonexistent_cargo_toml() { assert_cargo_toml_doesnt_exist("doc", "foo/bar/baz/Cargo.toml"); } #[cargo_test] fn fetch_dir_containing_cargo_toml() { assert_not_a_cargo_toml("fetch", "foo"); } #[cargo_test] fn fetch_dir_plus_file() { assert_not_a_cargo_toml("fetch", "foo/bar"); } #[cargo_test] fn fetch_dir_plus_path() { assert_not_a_cargo_toml("fetch", "foo/bar/baz"); } #[cargo_test] fn fetch_dir_to_nonexistent_cargo_toml() { assert_cargo_toml_doesnt_exist("fetch", "foo/bar/baz/Cargo.toml"); } #[cargo_test] fn generate_lockfile_dir_containing_cargo_toml() { assert_not_a_cargo_toml("generate-lockfile", "foo"); } #[cargo_test] fn generate_lockfile_dir_plus_file() { assert_not_a_cargo_toml("generate-lockfile", "foo/bar"); } #[cargo_test] fn generate_lockfile_dir_plus_path() { assert_not_a_cargo_toml("generate-lockfile", "foo/bar/baz"); } #[cargo_test] fn generate_lockfile_dir_to_nonexistent_cargo_toml() { assert_cargo_toml_doesnt_exist("generate-lockfile", "foo/bar/baz/Cargo.toml"); } #[cargo_test] fn package_dir_containing_cargo_toml() { assert_not_a_cargo_toml("package", "foo"); } #[cargo_test] fn package_dir_plus_file() { assert_not_a_cargo_toml("package", "foo/bar"); } #[cargo_test] fn package_dir_plus_path() { assert_not_a_cargo_toml("package", "foo/bar/baz"); } #[cargo_test] fn package_dir_to_nonexistent_cargo_toml() { assert_cargo_toml_doesnt_exist("package", "foo/bar/baz/Cargo.toml"); } #[cargo_test] fn pkgid_dir_containing_cargo_toml() { assert_not_a_cargo_toml("pkgid", "foo"); } #[cargo_test] fn pkgid_dir_plus_file() { assert_not_a_cargo_toml("pkgid", "foo/bar"); } #[cargo_test] fn pkgid_dir_plus_path() { assert_not_a_cargo_toml("pkgid", "foo/bar/baz"); } #[cargo_test] fn pkgid_dir_to_nonexistent_cargo_toml() { assert_cargo_toml_doesnt_exist("pkgid", "foo/bar/baz/Cargo.toml"); } #[cargo_test] fn publish_dir_containing_cargo_toml() { assert_not_a_cargo_toml("publish", "foo"); } #[cargo_test] fn publish_dir_plus_file() { assert_not_a_cargo_toml("publish", "foo/bar"); } #[cargo_test] fn publish_dir_plus_path() { assert_not_a_cargo_toml("publish", "foo/bar/baz"); } #[cargo_test] fn publish_dir_to_nonexistent_cargo_toml() { assert_cargo_toml_doesnt_exist("publish", "foo/bar/baz/Cargo.toml"); } #[cargo_test] fn read_manifest_dir_containing_cargo_toml() { assert_not_a_cargo_toml("read-manifest", "foo"); } #[cargo_test] fn read_manifest_dir_plus_file() { assert_not_a_cargo_toml("read-manifest", "foo/bar"); } #[cargo_test] fn read_manifest_dir_plus_path() { assert_not_a_cargo_toml("read-manifest", "foo/bar/baz"); } #[cargo_test] fn read_manifest_dir_to_nonexistent_cargo_toml() { assert_cargo_toml_doesnt_exist("read-manifest", "foo/bar/baz/Cargo.toml"); } #[cargo_test] fn run_dir_containing_cargo_toml() { assert_not_a_cargo_toml("run", "foo"); } #[cargo_test] fn run_dir_plus_file() { assert_not_a_cargo_toml("run", "foo/bar"); } #[cargo_test] fn run_dir_plus_path() { assert_not_a_cargo_toml("run", "foo/bar/baz"); } #[cargo_test] fn run_dir_to_nonexistent_cargo_toml() { assert_cargo_toml_doesnt_exist("run", "foo/bar/baz/Cargo.toml"); } #[cargo_test] fn rustc_dir_containing_cargo_toml() { assert_not_a_cargo_toml("rustc", "foo"); } #[cargo_test] fn rustc_dir_plus_file() { assert_not_a_cargo_toml("rustc", "foo/bar"); } #[cargo_test] fn rustc_dir_plus_path() { assert_not_a_cargo_toml("rustc", "foo/bar/baz"); } #[cargo_test] fn rustc_dir_to_nonexistent_cargo_toml() { assert_cargo_toml_doesnt_exist("rustc", "foo/bar/baz/Cargo.toml"); } #[cargo_test] fn test_dir_containing_cargo_toml() { assert_not_a_cargo_toml("test", "foo"); } #[cargo_test] fn test_dir_plus_file() { assert_not_a_cargo_toml("test", "foo/bar"); } #[cargo_test] fn test_dir_plus_path() { assert_not_a_cargo_toml("test", "foo/bar/baz"); } #[cargo_test] fn test_dir_to_nonexistent_cargo_toml() { assert_cargo_toml_doesnt_exist("test", "foo/bar/baz/Cargo.toml"); } #[cargo_test] fn update_dir_containing_cargo_toml() { assert_not_a_cargo_toml("update", "foo"); } #[cargo_test] fn update_dir_plus_file() { assert_not_a_cargo_toml("update", "foo/bar"); } #[cargo_test] fn update_dir_plus_path() { assert_not_a_cargo_toml("update", "foo/bar/baz"); } #[cargo_test] fn update_dir_to_nonexistent_cargo_toml() { assert_cargo_toml_doesnt_exist("update", "foo/bar/baz/Cargo.toml"); } #[cargo_test] fn verify_project_dir_containing_cargo_toml() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("verify-project --manifest-path foo") .cwd(p.root().parent().unwrap()) .with_status(1) .with_stdout_data( str![[r#" [ { "invalid": "the manifest-path must be a path to a Cargo.toml file" } ] "#]] .is_json() .against_jsonlines(), ) .run(); } #[cargo_test] fn verify_project_dir_plus_file() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("verify-project --manifest-path foo/bar") .cwd(p.root().parent().unwrap()) .with_status(1) .with_stdout_data( str![[r#" [ { "invalid": "the manifest-path must be a path to a Cargo.toml file" } ] "#]] .is_json() .against_jsonlines(), ) .run(); } #[cargo_test] fn verify_project_dir_plus_path() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("verify-project --manifest-path foo/bar/baz") .cwd(p.root().parent().unwrap()) .with_status(1) .with_stdout_data( str![[r#" [ { "invalid": "the manifest-path must be a path to a Cargo.toml file" } ] "#]] .is_json() .against_jsonlines(), ) .run(); } #[cargo_test] fn verify_project_dir_to_nonexistent_cargo_toml() { let p = project().build(); p.cargo("verify-project --manifest-path foo/bar/baz/Cargo.toml") .cwd(p.root().parent().unwrap()) .with_status(1) .with_stdout_data( str![[r#" [ { "invalid": "manifest path `foo/bar/baz/Cargo.toml` does not exist" } ] "#]] .is_json() .against_jsonlines(), ) .run(); } cargo-0.86.0/tests/testsuite/bench.rs000064400000000000000000001531041046102023000156360ustar 00000000000000//! Tests for the `cargo bench` command. use cargo_test_support::prelude::*; use cargo_test_support::{basic_bin_manifest, basic_lib_manifest, basic_manifest, project, str}; #[cargo_test(nightly, reason = "bench")] fn cargo_bench_simple() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; fn hello() -> &'static str { "hello" } pub fn main() { println!("{}", hello()) } #[bench] fn bench_hello(_b: &mut test::Bencher) { assert_eq!(hello(), "hello") } "#, ) .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" hello "#]]) .run(); p.cargo("bench") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] unittests src/main.rs (target/release/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test bench_hello ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_bench_implicit() { let p = project() .file( "src/main.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; #[bench] fn run1(_ben: &mut test::Bencher) { } fn main() { println!("Hello main!"); } "#, ) .file( "tests/other.rs", r#" #![feature(test)] extern crate test; #[bench] fn run3(_ben: &mut test::Bencher) { } "#, ) .file( "benches/mybench.rs", r#" #![feature(test)] extern crate test; #[bench] fn run2(_ben: &mut test::Bencher) { } "#, ) .build(); p.cargo("bench --benches") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] [..] (target/release/deps/foo-[HASH][EXE]) [RUNNING] [..] (target/release/deps/mybench-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test run1 ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test run2 ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_bin_implicit() { let p = project() .file( "src/main.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; #[bench] fn run1(_ben: &mut test::Bencher) { } fn main() { println!("Hello main!"); } "#, ) .file( "tests/other.rs", r#" #![feature(test)] extern crate test; #[bench] fn run3(_ben: &mut test::Bencher) { } "#, ) .file( "benches/mybench.rs", r#" #![feature(test)] extern crate test; #[bench] fn run2(_ben: &mut test::Bencher) { } "#, ) .build(); p.cargo("bench --bins") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] [..] (target/release/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test run1 ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_tarname() { let p = project() .file( "benches/bin1.rs", r#" #![feature(test)] extern crate test; #[bench] fn run1(_ben: &mut test::Bencher) { } "#, ) .file( "benches/bin2.rs", r#" #![feature(test)] extern crate test; #[bench] fn run2(_ben: &mut test::Bencher) { } "#, ) .build(); p.cargo("bench --bench bin2") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] [..] (target/release/deps/bin2-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test run2 ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_multiple_targets() { let p = project() .file( "benches/bin1.rs", r#" #![feature(test)] extern crate test; #[bench] fn run1(_ben: &mut test::Bencher) { } "#, ) .file( "benches/bin2.rs", r#" #![feature(test)] extern crate test; #[bench] fn run2(_ben: &mut test::Bencher) { } "#, ) .file( "benches/bin3.rs", r#" #![feature(test)] extern crate test; #[bench] fn run3(_ben: &mut test::Bencher) { } "#, ) .build(); // This should not have anything about `run3` in it. p.cargo("bench --bench bin1 --bench bin2") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] benches/bin1.rs (target/release/deps/bin1-[HASH][EXE]) [RUNNING] benches/bin2.rs (target/release/deps/bin2-[HASH][EXE]) "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn cargo_bench_verbose() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; fn main() {} #[bench] fn bench_hello(_b: &mut test::Bencher) {} "#, ) .build(); p.cargo("bench -v hello") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc [..] src/main.rs [..]` [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[..]target/release/deps/foo-[HASH][EXE] hello --bench` "#]]) .with_stdout_data(str![[r#" running 1 test test bench_hello ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn many_similar_names() { let p = project() .file( "src/lib.rs", " #![feature(test)] #[cfg(test)] extern crate test; pub fn foo() {} #[bench] fn lib_bench(_b: &mut test::Bencher) {} ", ) .file( "src/main.rs", " #![feature(test)] #[cfg(test)] extern crate foo; #[cfg(test)] extern crate test; fn main() {} #[bench] fn bin_bench(_b: &mut test::Bencher) { foo::foo() } ", ) .file( "benches/foo.rs", r#" #![feature(test)] extern crate foo; extern crate test; #[bench] fn bench_bench(_b: &mut test::Bencher) { foo::foo() } "#, ) .build(); p.cargo("bench") .with_stdout_data(str![[r#" running 1 test test lib_bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test bin_bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test bench_bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn cargo_bench_failing_test() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; fn hello() -> &'static str { "hello" } pub fn main() { println!("{}", hello()) } #[bench] fn bench_hello(_b: &mut test::Bencher) { assert_eq!(hello(), "nope", "NOPE!") } "#, ) .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" hello "#]]) .run(); // Force libtest into serial execution so that the test header will be printed. p.cargo("bench -- --test-threads=1") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] [..] (target/release/deps/foo-[HASH][EXE]) [ERROR] bench failed, to rerun pass `--bin foo` "#]]) .with_stdout_data("...\n[..]NOPE![..]\n...") .with_status(101) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_with_lib_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[bin]] name = "baz" path = "src/main.rs" "#, ) .file( "src/lib.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; /// /// ```rust /// extern crate foo; /// fn main() { /// println!("{}", foo::foo()); /// } /// ``` /// pub fn foo(){} #[bench] fn lib_bench(_b: &mut test::Bencher) {} "#, ) .file( "src/main.rs", " #![feature(test)] #[allow(unused_extern_crates)] extern crate foo; #[cfg(test)] extern crate test; fn main() {} #[bench] fn bin_bench(_b: &mut test::Bencher) {} ", ) .build(); p.cargo("bench") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] [..] (target/release/deps/foo-[HASH][EXE]) [RUNNING] [..] (target/release/deps/baz-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test lib_bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test bin_bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_with_deep_lib_dep() { let p = project() .at("bar") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies.foo] path = "../foo" "#, ) .file( "src/lib.rs", " #![feature(test)] #[cfg(test)] extern crate foo; #[cfg(test)] extern crate test; #[bench] fn bar_bench(_b: &mut test::Bencher) { foo::foo(); } ", ) .build(); let _p2 = project() .file( "src/lib.rs", " #![feature(test)] #[cfg(test)] extern crate test; pub fn foo() {} #[bench] fn foo_bench(_b: &mut test::Bencher) {} ", ) .build(); p.cargo("bench") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] foo v0.0.1 ([ROOT]/foo) [COMPILING] bar v0.0.1 ([ROOT]/bar) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] [..] (target/release/deps/bar-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test bar_bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn external_bench_explicit() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[bench]] name = "bench" path = "src/bench.rs" "#, ) .file( "src/lib.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; pub fn get_hello() -> &'static str { "Hello" } #[bench] fn internal_bench(_b: &mut test::Bencher) {} "#, ) .file( "src/bench.rs", r#" #![feature(test)] #[allow(unused_extern_crates)] extern crate foo; extern crate test; #[bench] fn external_bench(_b: &mut test::Bencher) {} "#, ) .build(); p.cargo("bench") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] [..] (target/release/deps/foo-[HASH][EXE]) [RUNNING] [..] (target/release/deps/bench-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test internal_bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test external_bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn external_bench_implicit() { let p = project() .file( "src/lib.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; pub fn get_hello() -> &'static str { "Hello" } #[bench] fn internal_bench(_b: &mut test::Bencher) {} "#, ) .file( "benches/external.rs", r#" #![feature(test)] #[allow(unused_extern_crates)] extern crate foo; extern crate test; #[bench] fn external_bench(_b: &mut test::Bencher) {} "#, ) .build(); p.cargo("bench") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] [..] (target/release/deps/foo-[HASH][EXE]) [RUNNING] [..] (target/release/deps/external-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test internal_bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test external_bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_autodiscover_2015() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2015" [features] magic = [] [[bench]] name = "bench_magic" required-features = ["magic"] "#, ) .file("src/lib.rs", "") .file( "benches/bench_basic.rs", r#" #![feature(test)] #[allow(unused_extern_crates)] extern crate foo; extern crate test; #[bench] fn bench_basic(_b: &mut test::Bencher) {} "#, ) .file( "benches/bench_magic.rs", r#" #![feature(test)] #[allow(unused_extern_crates)] extern crate foo; extern crate test; #[bench] fn bench_magic(_b: &mut test::Bencher) {} "#, ) .build(); p.cargo("bench bench_basic") .with_stderr_data(str![[r#" [WARNING] An explicit [[bench]] section is specified in Cargo.toml which currently disables Cargo from automatically inferring other benchmark targets. This inference behavior will change in the Rust 2018 edition and the following files will be included as a benchmark target: * [..]bench_basic.rs This is likely to break cargo build or cargo test as these files may not be ready to be compiled as a benchmark target today. You can future-proof yourself and disable this warning by adding `autobenches = false` to your [package] section. You may also move the files to a location where Cargo would not automatically infer them to be a target, such as in subfolders. For more information on this warning you can consult https://github.com/rust-lang/cargo/issues/5330 [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] [..] (target/release/deps/foo-[HASH][EXE]) "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn dont_run_examples() { let p = project() .file("src/lib.rs", "") .file( "examples/dont-run-me-i-will-fail.rs", r#"fn main() { panic!("Examples should not be run by 'cargo test'"); }"#, ) .build(); p.cargo("bench").run(); } #[cargo_test(nightly, reason = "bench")] fn pass_through_command_line() { let p = project() .file( "src/lib.rs", " #![feature(test)] #[cfg(test)] extern crate test; #[bench] fn foo(_b: &mut test::Bencher) {} #[bench] fn bar(_b: &mut test::Bencher) {} ", ) .build(); p.cargo("bench bar") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] [..] (target/release/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test bar ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 1 filtered out; finished in [ELAPSED]s "#]]) .run(); p.cargo("bench foo") .with_stderr_data(str![[r#" [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] [..] (target/release/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test foo ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 1 filtered out; finished in [ELAPSED]s "#]]) .run(); } // Regression test for running cargo-bench twice with // tests in an rlib #[cargo_test(nightly, reason = "bench")] fn cargo_bench_twice() { let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file( "src/foo.rs", r#" #![crate_type = "rlib"] #![feature(test)] #[cfg(test)] extern crate test; #[bench] fn dummy_bench(b: &mut test::Bencher) { } "#, ) .build(); for _ in 0..2 { p.cargo("bench").run(); } } #[cargo_test(nightly, reason = "bench")] fn lib_bin_same_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] name = "foo" [[bin]] name = "foo" "#, ) .file( "src/lib.rs", " #![feature(test)] #[cfg(test)] extern crate test; #[bench] fn lib_bench(_b: &mut test::Bencher) {} ", ) .file( "src/main.rs", " #![feature(test)] #[allow(unused_extern_crates)] extern crate foo; #[cfg(test)] extern crate test; #[bench] fn bin_bench(_b: &mut test::Bencher) {} ", ) .build(); p.cargo("bench") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] [..] (target/release/deps/foo-[HASH][EXE]) [RUNNING] [..] (target/release/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test lib_bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test bin_bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn lib_with_standard_name() { let p = project() .file("Cargo.toml", &basic_manifest("syntax", "0.0.1")) .file( "src/lib.rs", " #![feature(test)] #[cfg(test)] extern crate test; /// ``` /// syntax::foo(); /// ``` pub fn foo() {} #[bench] fn foo_bench(_b: &mut test::Bencher) {} ", ) .file( "benches/bench.rs", " #![feature(test)] extern crate syntax; extern crate test; #[bench] fn bench(_b: &mut test::Bencher) { syntax::foo() } ", ) .build(); p.cargo("bench") .with_stderr_data(str![[r#" [COMPILING] syntax v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] [..] (target/release/deps/syntax-[HASH][EXE]) [RUNNING] [..] (target/release/deps/bench-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test foo_bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn lib_with_standard_name2() { let p = project() .file( "Cargo.toml", r#" [package] name = "syntax" version = "0.0.1" edition = "2015" authors = [] [lib] name = "syntax" bench = false doctest = false "#, ) .file("src/lib.rs", "pub fn foo() {}") .file( "src/main.rs", " #![feature(test)] #[cfg(test)] extern crate syntax; #[cfg(test)] extern crate test; fn main() {} #[bench] fn bench(_b: &mut test::Bencher) { syntax::foo() } ", ) .build(); p.cargo("bench") .with_stderr_data(str![[r#" [COMPILING] syntax v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] [..] (target/release/deps/syntax-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_dylib() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] name = "foo" crate-type = ["dylib"] [dependencies.bar] path = "bar" "#, ) .file( "src/lib.rs", r#" #![feature(test)] extern crate bar as the_bar; #[cfg(test)] extern crate test; pub fn bar() { the_bar::baz(); } #[bench] fn foo(_b: &mut test::Bencher) {} "#, ) .file( "benches/bench.rs", r#" #![feature(test)] extern crate foo as the_foo; extern crate test; #[bench] fn foo(_b: &mut test::Bencher) { the_foo::bar(); } "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [lib] name = "bar" crate-type = ["dylib"] "#, ) .file("bar/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("bench -v") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] [..] -C opt-level=3 [..] [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] [..] -C opt-level=3 [..] [RUNNING] [..] -C opt-level=3 [..] [RUNNING] [..] -C opt-level=3 [..] [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[..]target/release/deps/foo-[HASH][EXE] --bench` [RUNNING] `[..]target/release/deps/bench-[HASH][EXE] --bench` "#]]) .with_stdout_data(str![[r#" running 1 test test foo ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test foo ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); p.root().move_into_the_past(); p.cargo("bench -v") .with_stderr_data(str![[r#" [FRESH] bar v0.0.1 ([ROOT]/foo/bar) [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[..]target/release/deps/foo-[HASH][EXE] --bench` [RUNNING] `[..]target/release/deps/bench-[HASH][EXE] --bench` "#]]) .with_stdout_data(str![[r#" running 1 test test foo ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test foo ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_twice_with_build_cmd() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file("build.rs", "fn main() {}") .file( "src/lib.rs", " #![feature(test)] #[cfg(test)] extern crate test; #[bench] fn foo(_b: &mut test::Bencher) {} ", ) .build(); p.cargo("bench") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] [..] (target/release/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test foo ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); p.cargo("bench") .with_stderr_data(str![[r#" [FINISHED] `bench` profile [optimized] target(s) in [..] [RUNNING] [..] (target/release/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test foo ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_with_examples() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "6.6.6" edition = "2015" authors = [] [[example]] name = "teste1" [[bench]] name = "testb1" "#, ) .file( "src/lib.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; #[cfg(test)] use test::Bencher; pub fn f1() { println!("f1"); } pub fn f2() {} #[bench] fn bench_bench1(_b: &mut Bencher) { f2(); } "#, ) .file( "benches/testb1.rs", " #![feature(test)] extern crate foo; extern crate test; use test::Bencher; #[bench] fn bench_bench2(_b: &mut Bencher) { foo::f2(); } ", ) .file( "examples/teste1.rs", r#" extern crate foo; fn main() { println!("example1"); foo::f1(); } "#, ) .build(); p.cargo("bench -v") .with_stderr_data(str![[r#" [COMPILING] foo v6.6.6 ([ROOT]/foo) [RUNNING] `rustc [..]` [RUNNING] `rustc [..]` [RUNNING] `rustc [..]` [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/release/deps/foo-[HASH][EXE] --bench` [RUNNING] `[ROOT]/foo/target/release/deps/testb1-[HASH][EXE] --bench` "#]]) .with_stdout_data(str![[r#" running 1 test test bench_bench1 ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test bench_bench2 ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn test_a_bench() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.1.0" edition = "2015" [lib] name = "foo" test = false doctest = false [[bench]] name = "b" test = true "#, ) .file("src/lib.rs", "") .file("benches/b.rs", "#[test] fn foo() {}") .build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] [..] (target/debug/deps/b-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test foo ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn test_bench_no_run() { let p = project() .file("src/lib.rs", "") .file( "benches/bbaz.rs", r#" #![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_baz(_: &mut Bencher) {} "#, ) .build(); p.cargo("bench --no-run") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [EXECUTABLE] benches src/lib.rs (target/release/deps/foo-[HASH][EXE]) [EXECUTABLE] benches/bbaz.rs (target/release/deps/bbaz-[HASH][EXE]) "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn test_bench_no_run_emit_json() { let p = project() .file("src/lib.rs", "") .file( "benches/bbaz.rs", r#" #![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_baz(_: &mut Bencher) {} "#, ) .build(); p.cargo("bench --no-run --message-format json") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn test_bench_no_fail_fast() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; fn hello() -> &'static str { "hello" } pub fn main() { println!("{}", hello()) } #[bench] fn bench_hello(_b: &mut test::Bencher) { assert_eq!(hello(), "hello") } #[bench] fn bench_nope(_b: &mut test::Bencher) { assert_eq!("nope", hello(), "NOPE!") } "#, ) .file( "benches/b1.rs", r#" #![feature(test)] extern crate test; #[bench] fn b1_fail(_b: &mut test::Bencher) { assert_eq!(1, 2, "ONE=TWO"); } "#, ) .build(); p.cargo("bench --no-fail-fast -- --test-threads=1") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] unittests src/main.rs (target/release/deps/foo-[HASH][EXE]) [ERROR] bench failed, to rerun pass `--bin foo` [RUNNING] benches/b1.rs (target/release/deps/b1-[HASH][EXE]) [ERROR] bench failed, to rerun pass `--bench b1` [ERROR] 2 targets failed: `--bin foo` `--bench b1` "#]]) .with_stdout_data( r#" ... [..]NOPE![..] ... [..]ONE=TWO[..] ... "#, ) .run(); } #[cargo_test(nightly, reason = "bench")] fn test_bench_multiple_packages() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.1.0" edition = "2015" [dependencies.bar] path = "../bar" [dependencies.baz] path = "../baz" "#, ) .file("src/lib.rs", "") .build(); let _bar = project() .at("bar") .file( "Cargo.toml", r#" [package] name = "bar" authors = [] version = "0.1.0" edition = "2015" [[bench]] name = "bbar" test = true "#, ) .file("src/lib.rs", "") .file( "benches/bbar.rs", r#" #![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_bar(_b: &mut Bencher) {} "#, ) .build(); let _baz = project() .at("baz") .file( "Cargo.toml", r#" [package] name = "baz" authors = [] version = "0.1.0" edition = "2015" [[bench]] name = "bbaz" test = true "#, ) .file("src/lib.rs", "") .file( "benches/bbaz.rs", r#" #![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_baz(_b: &mut Bencher) {} "#, ) .build(); p.cargo("bench -p bar -p baz") .with_stderr_data(str![[r#" [RUNNING] [..] (target/release/deps/bbaz-[HASH][EXE]) [RUNNING] [..] (target/release/deps/bbar-[HASH][EXE]) "#]]) .with_stderr_data( str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] bar v0.1.0 ([ROOT]/bar) [COMPILING] baz v0.1.0 ([ROOT]/baz) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/release/deps/bar-[HASH][EXE]) [RUNNING] benches/bbar.rs (target/release/deps/bbar-[HASH][EXE]) [RUNNING] unittests src/lib.rs (target/release/deps/baz-[HASH][EXE]) [RUNNING] benches/bbaz.rs (target/release/deps/bbaz-[HASH][EXE]) "#]] .unordered(), ) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_all_workspace() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } [workspace] "#, ) .file("src/main.rs", "fn main() {}") .file( "benches/foo.rs", r#" #![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_foo(_: &mut Bencher) -> () { () } "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file( "bar/benches/bar.rs", r#" #![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_bar(_: &mut Bencher) -> () { () } "#, ) .build(); p.cargo("bench --workspace") .with_stderr_data(str![[r#" [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/release/deps/bar-[HASH][EXE]) [RUNNING] benches/bar.rs (target/release/deps/bar-[HASH][EXE]) [RUNNING] unittests src/main.rs (target/release/deps/foo-[HASH][EXE]) [RUNNING] benches/foo.rs (target/release/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test bench_bar ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test bench_foo ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_all_exclude() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["bar", "baz"] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file( "bar/src/lib.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; #[bench] pub fn bar(b: &mut test::Bencher) { b.iter(|| {}); } "#, ) .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file( "baz/src/lib.rs", "#[test] pub fn baz() { break_the_build(); }", ) .build(); p.cargo("bench --workspace --exclude baz") .with_stdout_data(str![[r#" running 1 test test bar ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_all_exclude_glob() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["bar", "baz"] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file( "bar/src/lib.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; #[bench] pub fn bar(b: &mut test::Bencher) { b.iter(|| {}); } "#, ) .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file( "baz/src/lib.rs", "#[test] pub fn baz() { break_the_build(); }", ) .build(); p.cargo("bench --workspace --exclude '*z'") .with_stdout_data(str![[r#" running 1 test test bar ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_all_virtual_manifest() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file( "bar/benches/bar.rs", r#" #![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_bar(_: &mut Bencher) -> () { () } "#, ) .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .file( "baz/benches/baz.rs", r#" #![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_baz(_: &mut Bencher) -> () { () } "#, ) .build(); // The order in which bar and baz are built is not guaranteed p.cargo("bench --workspace") .with_stderr_data( str![[r#" [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [COMPILING] baz v0.1.0 ([ROOT]/foo/baz) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/release/deps/bar-[HASH][EXE]) [RUNNING] benches/bar.rs (target/release/deps/bar-[HASH][EXE]) [RUNNING] unittests src/lib.rs (target/release/deps/baz-[HASH][EXE]) [RUNNING] benches/baz.rs (target/release/deps/baz-[HASH][EXE]) "#]] .unordered(), ) .with_stdout_data(str![[r#" running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test bench_bar ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test bench_baz ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_virtual_manifest_glob() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() { break_the_build(); }") .file( "bar/benches/bar.rs", r#" #![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_bar(_: &mut Bencher) -> () { break_the_build(); } "#, ) .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .file( "baz/benches/baz.rs", r#" #![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_baz(_: &mut Bencher) -> () { () } "#, ) .build(); // This should not have `bar` built or benched p.cargo("bench -p '*z'") .with_stderr_data(str![[r#" [COMPILING] baz v0.1.0 ([ROOT]/foo/baz) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/release/deps/baz-[HASH][EXE]) [RUNNING] benches/baz.rs (target/release/deps/baz-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test bench_baz ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } // https://github.com/rust-lang/cargo/issues/4287 #[cargo_test(nightly, reason = "bench")] fn legacy_bench_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [[bench]] name = "bench" "#, ) .file("src/lib.rs", "pub fn foo() {}") .file( "src/bench.rs", r#" #![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_foo(_: &mut Bencher) -> () { () } "#, ) .build(); p.cargo("bench") .with_stderr_data(str![[r#" [WARNING] path `src/bench.rs` was erroneously implicitly accepted for benchmark `bench`, please set bench.path in Cargo.toml [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/release/deps/foo-[HASH][EXE]) [RUNNING] src/bench.rs (target/release/deps/bench-[HASH][EXE]) "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_virtual_manifest_all_implied() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn foo() {}") .file( "bar/benches/bar.rs", r#" #![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_bar(_: &mut Bencher) -> () { () } "#, ) .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .file( "baz/benches/baz.rs", r#" #![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_baz(_: &mut Bencher) -> () { () } "#, ) .build(); // The order in which bar and baz are built is not guaranteed p.cargo("bench") .with_stderr_data( str![[r#" [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [COMPILING] baz v0.1.0 ([ROOT]/foo/baz) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/release/deps/bar-[HASH][EXE]) [RUNNING] benches/bar.rs (target/release/deps/bar-[HASH][EXE]) [RUNNING] unittests src/lib.rs (target/release/deps/baz-[HASH][EXE]) [RUNNING] benches/baz.rs (target/release/deps/baz-[HASH][EXE]) "#]] .unordered(), ) .with_stdout_data(str![[r#" running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test bench_bar ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test bench_baz ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn json_artifact_includes_executable_for_benchmark() { let p = project() .file( "benches/benchmark.rs", r#" #![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_foo(_: &mut Bencher) -> () { () } "#, ) .build(); p.cargo("bench --no-run --message-format=json") .with_stdout_data( str![[r#" [ { "executable": "[..]", "features": [], "filenames": "{...}", "fresh": false, "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.0.1", "profile": "{...}", "reason": "compiler-artifact", "target": { "crate_types": [ "bin" ], "doc": false, "doctest": false, "edition": "2015", "kind": [ "bench" ], "name": "benchmark", "src_path": "[ROOT]/foo/benches/benchmark.rs", "test": false } }, { "reason": "build-finished", "success": true } ] "#]] .is_json() .against_jsonlines(), ) .run(); } #[cargo_test(nightly, reason = "bench")] fn cargo_bench_print_env_verbose() { let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.0.1")) .file( "src/main.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; fn hello() -> &'static str { "hello" } pub fn main() { println!("{}", hello()) } #[bench] fn bench_hello(_b: &mut test::Bencher) { assert_eq!(hello(), "hello") } "#, ) .build(); p.cargo("bench -vv") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..]CARGO_MANIFEST_DIR=[ROOT]/foo[..] rustc[..]` [FINISHED] `bench` profile [optimized] target(s) in [..] [RUNNING] `[..]CARGO_MANIFEST_DIR=[ROOT]/foo[..] [ROOT]/foo/target/release/deps/foo-[HASH][EXE] --bench` "#]]) .run(); } cargo-0.86.0/tests/testsuite/binary_name.rs000064400000000000000000000317571046102023000170540ustar 00000000000000//! Tests for `cargo-features = ["different-binary-name"]`. use cargo_test_support::install::assert_has_installed_exe; use cargo_test_support::install::assert_has_not_installed_exe; use cargo_test_support::is_nightly; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; #[cargo_test] fn gated() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [[bin]] name = "foo" filename = "007bar" path = "src/main.rs" "#, ) .file("src/main.rs", "fn main() { assert!(true) }") .build(); // Run cargo build. p.cargo("build") .masquerade_as_nightly_cargo(&["different-binary-name"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `different-binary-name` is required The package requires the Cargo feature called `different-binary-name`, but that feature is not stabilized in this version of Cargo ([..]). Consider adding `cargo-features = ["different-binary-name"]` to the top of Cargo.toml (above the [package] table) to tell Cargo you are opting in to use this unstable feature. See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#different-binary-name for more information about the status of this feature. "#]]) .run(); } #[cargo_test] // This test checks if: // 1. The correct binary is produced // 2. The deps file has the correct content // 3. Fingerprinting works // 4. `cargo clean` command works fn binary_name1() { // Create the project. let p = project() .file( "Cargo.toml", r#" cargo-features = ["different-binary-name"] [package] name = "foo" version = "0.0.1" edition = "2015" [[bin]] name = "foo" filename = "007bar" path = "src/main.rs" "#, ) .file("src/main.rs", "fn main() { assert!(true) }") .build(); // Run cargo build. p.cargo("build") .masquerade_as_nightly_cargo(&["different-binary-name"]) .run(); // Check the name of the binary that cargo has generated. // A binary with the name of the crate should NOT be created. let foo_path = p.bin("foo"); assert!(!foo_path.is_file()); // A binary with the name provided in `filename` parameter should be created. let bar_path = p.bin("007bar"); assert!(bar_path.is_file()); // Check if deps file exists. let deps_path = p.bin("007bar").with_extension("d"); assert!(deps_path.is_file(), "{:?}", bar_path); let depinfo = p.read_file(&deps_path); // Prepare what content we expect to be present in deps file. let deps_exp = format!( "{}: {}", p.bin("007bar").to_str().unwrap(), p.root().join("src").join("main.rs").to_str().unwrap() ); // Compare actual deps content with expected deps content. assert!( depinfo.lines().any(|line| line == deps_exp), "Content of `{}` is incorrect", deps_path.to_string_lossy() ); // Run cargo second time, to verify fingerprint. p.cargo("build -p foo -v") .masquerade_as_nightly_cargo(&["different-binary-name"]) .with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Run cargo clean. p.cargo("clean -p foo") .masquerade_as_nightly_cargo(&["different-binary-name"]) .run(); // Check if the appropriate file was removed. assert!( !bar_path.is_file(), "`cargo clean` did not remove the correct files" ); } #[cargo_test] // This test checks if: // 1. Check `cargo run` // 2. Check `cargo test` // 3. Check `cargo install/uninstall` fn binary_name2() { // Create the project. let p = project() .file( "Cargo.toml", r#" cargo-features = ["different-binary-name"] [package] name = "foo" version = "0.0.1" edition = "2015" [[bin]] name = "foo" filename = "007bar" "#, ) .file( "src/main.rs", r#" fn hello(name: &str) -> String { format!("Hello, {}!", name) } fn main() { println!("{}", hello("crabs")); } #[cfg(test)] mod tests { use super::*; #[test] fn check_crabs() { assert_eq!(hello("crabs"), "Hello, crabs!"); } } "#, ) .build(); // Run cargo build. p.cargo("build") .masquerade_as_nightly_cargo(&["different-binary-name"]) .run(); // Check the name of the binary that cargo has generated. // A binary with the name of the crate should NOT be created. let foo_path = p.bin("foo"); assert!(!foo_path.is_file()); // A binary with the name provided in `filename` parameter should be created. let bar_path = p.bin("007bar"); assert!(bar_path.is_file()); // Check if `cargo test` works p.cargo("test") .masquerade_as_nightly_cargo(&["different-binary-name"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/main.rs (target/debug/deps/foo-[..][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test tests::check_crabs ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); // Check if `cargo run` is able to execute the binary p.cargo("run") .masquerade_as_nightly_cargo(&["different-binary-name"]) .with_stdout_data(str![[r#" Hello, crabs! "#]]) .run(); p.cargo("install") .masquerade_as_nightly_cargo(&["different-binary-name"]) .run(); assert_has_installed_exe(paths::cargo_home(), "007bar"); p.cargo("uninstall") .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/bin/007bar[EXE] "#]]) .masquerade_as_nightly_cargo(&["different-binary-name"]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "007bar"); } #[cargo_test] fn check_env_vars() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["different-binary-name"] [package] name = "foo" version = "0.0.1" edition = "2015" [[bin]] name = "foo" filename = "007bar" "#, ) .file( "src/main.rs", r#" fn main() { println!("{}", option_env!("CARGO_BIN_NAME").unwrap()); } "#, ) .file( "tests/integration.rs", r#" #[test] fn check_env_vars2() { let value = option_env!("CARGO_BIN_EXE_007bar").expect("Could not find environment variable."); assert!(value.contains("007bar")); } "# ) .build(); // Run cargo build. p.cargo("build") .masquerade_as_nightly_cargo(&["different-binary-name"]) .run(); p.cargo("run") .masquerade_as_nightly_cargo(&["different-binary-name"]) .with_stdout_data(str![[r#" 007bar "#]]) .run(); p.cargo("test") .masquerade_as_nightly_cargo(&["different-binary-name"]) .with_status(0) .run(); } #[cargo_test] fn check_msg_format_json() { // Create the project. let p = project() .file( "Cargo.toml", r#" cargo-features = ["different-binary-name"] [package] name = "foo" version = "0.0.1" edition = "2015" [[bin]] name = "foo" filename = "007bar" path = "src/main.rs" "#, ) .file("src/main.rs", "fn main() { assert!(true) }") .build(); // Run cargo build. p.cargo("build --message-format=json") .masquerade_as_nightly_cargo(&["different-binary-name"]) .with_stdout_data( str![[r#" [ { "executable": "[ROOT]/foo/target/debug/007bar[EXE]", "features": [], "filenames": "{...}", "fresh": false, "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.0.1", "profile": "{...}", "reason": "compiler-artifact", "target": "{...}" }, { "reason": "build-finished", "success": true } ] "#]] .is_json() .against_jsonlines(), ) .run(); } #[cargo_test] fn targets_with_relative_path_in_workspace_members() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["relative-bar"] resolver = "2" "#, ) .file( "relative-bar/Cargo.toml", r#" [package] name = "relative-bar" version = "0.1.0" edition = "2021" build = "./build.rs" [[bin]] name = "bar" path = "./src/main.rs" [lib] name = "lib" path = "./src/lib.rs" [[example]] name = "example" path = "./example.rs" [[test]] name = "test" path = "./test.rs" [[bench]] name = "bench" path = "./bench.rs" "#, ) .file("relative-bar/build.rs", "fn main() { let a = 1; }") .file("relative-bar/src/main.rs", "fn main() { let a = 1; }") .file("relative-bar/src/lib.rs", "fn a() {}") .file("relative-bar/example.rs", "fn main() { let a = 1; }") .file( "relative-bar/test.rs", r#" fn main() {} #[test] fn test_a() { let a = 1; } "#, ) .file( "relative-bar/bench.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; #[bench] fn bench_a(_b: &mut test::Bencher) { let a = 1; } "#, ) .build(); p.cargo("check") .with_stderr_data(str![[r#" ... --> relative-bar/build.rs:1:17 ... --> relative-bar/src/lib.rs:1:4 ... --> relative-bar/src/main.rs:1:17 ... "#]]) .run(); p.cargo("check --example example") .with_stderr_data(str![[r#" ... --> relative-bar/example.rs:1:17 ... "#]]) .run(); p.cargo("check --test test") .with_stderr_data(str![[r#" ... --> relative-bar/test.rs:5:35 ... "#]]) .run(); if is_nightly() { p.cargo("check --bench bench") .with_stderr_data(str![[r#" ... --> relative-bar/bench.rs:7:58 ... "#]]) .run(); } // Disable Cargo target auto-discovery. p.change_file( "relative-bar/Cargo.toml", r#" [package] name = "relative-bar" version = "0.1.0" edition = "2021" autolib = false autobins = false autoexamples = false autotests = false autobenches = false build = "./build.rs" [[bin]] name = "bar" path = "./src/main.rs" [lib] name = "lib" path = "./src/lib.rs" [[example]] name = "example" path = "./example.rs" [[test]] name = "test" path = "./test.rs" [[bench]] name = "bench" path = "./bench.rs" "#, ); p.cargo("check") .with_stderr_data(str![[r#" ... --> relative-bar/build.rs:1:17 ... --> relative-bar/src/lib.rs:1:4 ... --> relative-bar/src/main.rs:1:17 ... "#]]) .run(); p.cargo("check --example example") .with_stderr_data(str![[r#" ... --> relative-bar/example.rs:1:17 ... "#]]) .run(); p.cargo("check --test test") .with_stderr_data(str![[r#" ... --> relative-bar/test.rs:5:35 ... "#]]) .run(); if is_nightly() { p.cargo("check --bench bench") .with_stderr_data(str![[r#" ... --> relative-bar/bench.rs:7:58 ... "#]]) .run(); } } cargo-0.86.0/tests/testsuite/build.rs000064400000000000000000005434161046102023000156670ustar 00000000000000//! Tests for the `cargo build` command. use std::env; use std::fs; use std::io::Read; use std::process::Stdio; use cargo::{ core::compiler::CompileMode, core::{Shell, Workspace}, ops::CompileOptions, GlobalContext, }; use cargo_test_support::compare::assert_e2e; use cargo_test_support::paths::root; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::{ basic_bin_manifest, basic_lib_manifest, basic_manifest, cargo_exe, cargo_process, git, is_nightly, main_file, paths, process, project, rustc_host, sleep_ms, symlink_supported, t, tools, Execs, ProjectBuilder, }; use cargo_util::paths::dylib_path_envvar; #[cargo_test] fn cargo_compile_simple() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" i am foo "#]]) .run(); } #[cargo_test] fn build_with_symlink_to_path_dependency_with_build_script_in_git() { if !symlink_supported() { return; } let root = paths::root(); git::repo(&root) .nocommit_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2021" [dependencies] # the path leads through a symlink, 'symlink-to-original' is a worktree root, # and symlink-to-dir/ is a symlink to a sub-directory to be stepped through. lib = { version = "0.1.0", path = "symlink-to-original/symlink-to-dir/lib" } "#, ) .nocommit_file("src/main.rs", "fn main() { }") .nocommit_file("original/dir/lib/build.rs", "fn main() {}") .nocommit_file( "original/dir/lib/Cargo.toml", r#" [package] name = "lib" version = "0.1.0" edition = "2021" "#, ) .nocommit_file("original/dir/lib/src/lib.rs", "") .nocommit_symlink_dir("original", "symlink-to-original") .nocommit_symlink_dir("original/dir", "original/symlink-to-dir") .build(); // It is necessary to have a sub-repository and to add files so there is an index. let repo = git::init(&root.join("original")); git::add(&repo); cargo_process("build").run(); } #[cargo_test] fn cargo_fail_with_no_stderr() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", &String::from("refusal")) .build(); p.cargo("build --message-format=json") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [ERROR] could not compile `foo` (bin "foo") due to 1 previous error "#]]) .run(); } /// Checks that the `CARGO_INCREMENTAL` environment variable results in /// `rustc` getting `-C incremental` passed to it. #[cargo_test] fn cargo_compile_incremental() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("build -v") .env("CARGO_INCREMENTAL", "1") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc [..] -C incremental=[ROOT]/foo/target/debug/incremental[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("test -v") .env("CARGO_INCREMENTAL", "1") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc [..] -C incremental=[ROOT]/foo/target/debug/incremental[..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` "#]]) .run(); } #[cargo_test] fn incremental_profile() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [profile.dev] incremental = false [profile.release] incremental = true "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .env_remove("CARGO_INCREMENTAL") .with_stderr_does_not_contain("[..]C incremental=[..]") .run(); p.cargo("build -v") .env("CARGO_INCREMENTAL", "1") .with_stderr_contains("[..]C incremental=[..]") .run(); p.cargo("build --release -v") .env_remove("CARGO_INCREMENTAL") .with_stderr_contains("[..]C incremental=[..]") .run(); p.cargo("build --release -v") .env("CARGO_INCREMENTAL", "0") .with_stderr_does_not_contain("[..]C incremental=[..]") .run(); } #[cargo_test] fn incremental_config() { let p = project() .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [build] incremental = false "#, ) .build(); p.cargo("build -v") .env_remove("CARGO_INCREMENTAL") .with_stderr_does_not_contain("[..]C incremental=[..]") .run(); p.cargo("build -v") .env("CARGO_INCREMENTAL", "1") .with_stderr_contains("[..]C incremental=[..]") .run(); } #[cargo_test] fn cargo_compile_with_redundant_default_mode() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("build --debug") .with_stderr_data(str![[r#" [ERROR] unexpected argument '--debug' found tip: `--debug` is the default for `cargo build`; instead `--release` is supported Usage: cargo[EXE] build [OPTIONS] For more information, try '--help'. "#]]) .with_status(1) .run(); } #[cargo_test] fn cargo_compile_with_unsupported_short_config_flag() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("build -c net.git-fetch-with-cli=true") .with_stderr_data(str![[r#" [ERROR] unexpected argument '-c' found tip: a similar argument exists: '--config' Usage: cargo[EXE] build [OPTIONS] For more information, try '--help'. "#]]) .with_status(1) .run(); } #[cargo_test] fn cargo_compile_with_workspace_excluded() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("build --workspace --exclude foo") .with_stderr_data(str![[r#" [ERROR] no packages to compile "#]]) .with_status(101) .run(); } #[cargo_test] fn cargo_compile_manifest_path() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("build --manifest-path foo/Cargo.toml") .cwd(p.root().parent().unwrap()) .run(); assert!(p.bin("foo").is_file()); } #[cargo_test] fn cargo_compile_with_wrong_manifest_path_flag() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("build --path foo/Cargo.toml") .cwd(p.root().parent().unwrap()) .with_stderr_data(str![[r#" [ERROR] unexpected argument '--path' found tip: a similar argument exists: '--manifest-path' Usage: cargo[EXE] build [OPTIONS] For more information, try '--help'. "#]]) .with_status(1) .run(); } #[cargo_test] fn chdir_gated() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .build(); p.cargo("-C foo build") .cwd(p.root().parent().unwrap()) .with_stderr_data(str![[r#" [ERROR] the `-C` flag is unstable, pass `-Z unstable-options` on the nightly channel to enable it "#]]) .with_status(101) .run(); // No masquerade should also fail. p.cargo("-C foo -Z unstable-options build") .cwd(p.root().parent().unwrap()) .with_stderr_data(str![[r#" [ERROR] the `-C` flag is unstable, pass `-Z unstable-options` on the nightly channel to enable it "#]]) .with_status(101) .run(); } #[cargo_test] fn cargo_compile_directory_not_cwd() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .file(".cargo/config.toml", &"") .build(); p.cargo("-Zunstable-options -C foo build") .masquerade_as_nightly_cargo(&["chdir"]) .cwd(p.root().parent().unwrap()) .run(); assert!(p.bin("foo").is_file()); } #[cargo_test] fn cargo_compile_with_unsupported_short_unstable_feature_flag() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .file(".cargo/config.toml", &"") .build(); p.cargo("-zunstable-options -C foo build") .masquerade_as_nightly_cargo(&["chdir"]) .cwd(p.root().parent().unwrap()) .with_stderr_data(str![[r#" [ERROR] unexpected argument '-z' found tip: a similar argument exists: '-Z' Usage: cargo [..][OPTIONS] [COMMAND] cargo [..][OPTIONS] -Zscript [ARGS]... For more information, try '--help'. "#]]) .with_status(1) .run(); } #[cargo_test] fn cargo_compile_directory_not_cwd_with_invalid_config() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .file(".cargo/config.toml", &"!") .build(); p.cargo("-Zunstable-options -C foo build") .masquerade_as_nightly_cargo(&["chdir"]) .cwd(p.root().parent().unwrap()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] could not load Cargo configuration Caused by: could not parse TOML configuration in `[ROOT]/foo/.cargo/config.toml` Caused by: TOML parse error at line 1, column 1 | 1 | ! | ^ invalid key "#]]) .run(); } #[cargo_test] fn cargo_compile_with_invalid_manifest() { let p = project().file("Cargo.toml", "").build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: manifest is missing either a `[package]` or a `[workspace]` "#]]) .run(); } #[cargo_test] fn cargo_compile_with_invalid_manifest2() { let p = project() .file( "Cargo.toml", " [package] foo = bar ", ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid string expected `"`, `'` --> Cargo.toml:3:23 | 3 | foo = bar | ^ | "#]]) .run(); } #[cargo_test] fn cargo_compile_with_invalid_manifest3() { let p = project().file("src/Cargo.toml", "a = bar").build(); p.cargo("build --manifest-path src/Cargo.toml") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid string expected `"`, `'` --> src/Cargo.toml:1:5 | 1 | a = bar | ^ | "#]]) .run(); } #[cargo_test] fn cargo_compile_duplicate_build_targets() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] name = "main" path = "src/main.rs" crate-type = ["dylib"] [dependencies] "#, ) .file("src/main.rs", "#![allow(warnings)] fn main() {}") .build(); p.cargo("build") .with_stderr_data(str![[r#" [WARNING] file `[ROOT]/foo/src/main.rs` found to be present in multiple build targets: * `lib` target `main` * `bin` target `foo` [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cargo_compile_with_invalid_version() { let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0")) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] unexpected end of input while parsing minor version number --> Cargo.toml:4:19 | 4 | version = "1.0" | ^^^^^ | "#]]) .run(); } #[cargo_test] fn cargo_compile_with_empty_package_name() { let p = project() .file("Cargo.toml", &basic_manifest("", "0.0.0")) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package name cannot be empty --> Cargo.toml:3:16 | 3 | name = "" | ^^ | "#]]) .run(); } #[cargo_test] fn cargo_compile_with_invalid_package_name() { let p = project() .file("Cargo.toml", &basic_manifest("foo@bar", "0.0.0")) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid character `@` in package name: `foo@bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters) --> Cargo.toml:3:16 | 3 | name = "foo@bar" | ^^^^^^^^^ | "#]]) .run(); } #[cargo_test] fn cargo_compile_with_invalid_bin_target_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.0" edition = "2015" [[bin]] name = "" "#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: binary target names cannot be empty "#]]) .run(); } #[cargo_test] fn cargo_compile_with_forbidden_bin_target_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.0" edition = "2015" [[bin]] name = "build" "#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: the binary target name `build` is forbidden, it conflicts with cargo's build directory names "#]]) .run(); } #[cargo_test] fn cargo_compile_with_bin_and_crate_type() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.0" edition = "2015" [[bin]] name = "the_foo_bin" path = "src/foo.rs" crate-type = ["cdylib", "rlib"] "#, ) .file("src/foo.rs", "fn main() {}") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: the target `the_foo_bin` is a binary and can't have any crate-types set (currently "cdylib, rlib") "#]]) .run(); } #[cargo_test] fn cargo_compile_api_exposes_artifact_paths() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.0" edition = "2015" [[bin]] name = "the_foo_bin" path = "src/bin.rs" [lib] name = "the_foo_lib" path = "src/foo.rs" crate-type = ["cdylib", "rlib"] "#, ) .file("src/foo.rs", "pub fn bar() {}") .file("src/bin.rs", "pub fn main() {}") .build(); let shell = Shell::from_write(Box::new(Vec::new())); let gctx = GlobalContext::new(shell, env::current_dir().unwrap(), paths::home()); let ws = Workspace::new(&p.root().join("Cargo.toml"), &gctx).unwrap(); let compile_options = CompileOptions::new(ws.gctx(), CompileMode::Build).unwrap(); let result = cargo::ops::compile(&ws, &compile_options).unwrap(); assert_eq!(1, result.binaries.len()); assert!(result.binaries[0].path.exists()); assert!(result.binaries[0] .path .to_str() .unwrap() .contains("the_foo_bin")); assert_eq!(1, result.cdylibs.len()); // The exact library path varies by platform, but should certainly exist at least assert!(result.cdylibs[0].path.exists()); assert!(result.cdylibs[0] .path .to_str() .unwrap() .contains("the_foo_lib")); } #[cargo_test] fn cargo_compile_with_bin_and_proc() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.0" edition = "2015" [[bin]] name = "the_foo_bin" path = "src/foo.rs" proc-macro = true "#, ) .file("src/foo.rs", "fn main() {}") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: the target `the_foo_bin` is a binary and can't have `proc-macro` set `true` "#]]) .run(); } #[cargo_test] fn cargo_compile_with_invalid_lib_target_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.0" edition = "2015" [lib] name = "" "#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: library target names cannot be empty "#]]) .run(); } #[cargo_test] fn cargo_compile_with_invalid_non_numeric_dep_version() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] crossbeam = "y" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: failed to parse the version requirement `y` for dependency `crossbeam` Caused by: unexpected character 'y' while parsing major version number "#]]) .run(); } #[cargo_test] fn cargo_compile_without_manifest() { let p = project().no_manifest().build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] could not find `Cargo.toml` in `[ROOT]/foo` or any parent directory "#]]) .run(); } #[cargo_test] #[cfg(target_os = "linux")] fn cargo_compile_with_lowercase_cargo_toml() { let p = project() .no_manifest() .file("cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/lib.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] could not find `Cargo.toml` in `[ROOT]/foo` or any parent directory, but found cargo.toml please try to rename it to Cargo.toml "#]]) .run(); } #[cargo_test] fn cargo_compile_with_invalid_code() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "invalid rust code!") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [ERROR] [..] ... [ERROR] could not compile `foo` (bin "foo") due to 1 previous error "#]]) .run(); assert!(p.root().join("Cargo.lock").is_file()); } #[cargo_test] fn cargo_compile_with_invalid_code_in_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" [dependencies.baz] path = "../baz" "#, ) .file("src/main.rs", "invalid rust code!") .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "invalid rust code!") .build(); let _baz = project() .at("baz") .file("Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("src/lib.rs", "invalid rust code!") .build(); p.cargo("build") .with_status(101) .with_stderr_data( str![[r#" [COMPILING] bar v0.1.0 ([ROOT]/bar) [COMPILING] baz v0.1.0 ([ROOT]/baz) [ERROR] could not compile `bar` (lib) due to 1 previous error [ERROR] could not compile `baz` (lib) due to 1 previous error ... "#]] .unordered(), ) .run(); } #[cargo_test] fn cargo_compile_with_warnings_in_the_root_package() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {} fn dead() {}") .build(); p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [WARNING] [..]dead[..] ... [WARNING] `foo` (bin "foo") generated 1 warning [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cargo_compile_with_warnings_in_a_dep_package() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] path = "bar" [[bin]] name = "foo" "#, ) .file("src/main.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"])) .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file( "bar/src/bar.rs", r#" pub fn gimme() -> &'static str { "test passed" } fn dead() {} "#, ) .build(); p.cargo("build") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [WARNING] [..]dead[..] ... [WARNING] `bar` (lib) generated 1 warning [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" test passed "#]]) .run(); } #[cargo_test] fn cargo_compile_with_nested_deps_inferred() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] path = 'bar' [[bin]] name = "foo" "#, ) .file("src/foo.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"])) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.baz] path = "../baz" "#, ) .file( "bar/src/lib.rs", r#" extern crate baz; pub fn gimme() -> String { baz::gimme() } "#, ) .file("baz/Cargo.toml", &basic_manifest("baz", "0.5.0")) .file( "baz/src/lib.rs", r#" pub fn gimme() -> String { "test passed".to_string() } "#, ) .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); assert!(!p.bin("libbar.rlib").is_file()); assert!(!p.bin("libbaz.rlib").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" test passed "#]]) .run(); } #[cargo_test] fn cargo_compile_with_nested_deps_correct_bin() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] path = "bar" [[bin]] name = "foo" "#, ) .file("src/main.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"])) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.baz] path = "../baz" "#, ) .file( "bar/src/lib.rs", r#" extern crate baz; pub fn gimme() -> String { baz::gimme() } "#, ) .file("baz/Cargo.toml", &basic_manifest("baz", "0.5.0")) .file( "baz/src/lib.rs", r#" pub fn gimme() -> String { "test passed".to_string() } "#, ) .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); assert!(!p.bin("libbar.rlib").is_file()); assert!(!p.bin("libbaz.rlib").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" test passed "#]]) .run(); } #[cargo_test] fn cargo_compile_with_nested_deps_shorthand() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] path = "bar" "#, ) .file("src/main.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"])) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.baz] path = "../baz" [lib] name = "bar" "#, ) .file( "bar/src/bar.rs", r#" extern crate baz; pub fn gimme() -> String { baz::gimme() } "#, ) .file("baz/Cargo.toml", &basic_lib_manifest("baz")) .file( "baz/src/baz.rs", r#" pub fn gimme() -> String { "test passed".to_string() } "#, ) .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); assert!(!p.bin("libbar.rlib").is_file()); assert!(!p.bin("libbaz.rlib").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" test passed "#]]) .run(); } #[cargo_test] fn cargo_compile_with_nested_deps_longhand() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] path = "bar" version = "0.5.0" edition = "2015" [[bin]] name = "foo" "#, ) .file("src/foo.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"])) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.baz] path = "../baz" version = "0.5.0" edition = "2015" [lib] name = "bar" "#, ) .file( "bar/src/bar.rs", r#" extern crate baz; pub fn gimme() -> String { baz::gimme() } "#, ) .file("baz/Cargo.toml", &basic_lib_manifest("baz")) .file( "baz/src/baz.rs", r#" pub fn gimme() -> String { "test passed".to_string() } "#, ) .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); assert!(!p.bin("libbar.rlib").is_file()); assert!(!p.bin("libbaz.rlib").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" test passed "#]]) .run(); } // Check that Cargo gives a sensible error if a dependency can't be found // because of a name mismatch. #[cargo_test] fn cargo_compile_with_dep_name_mismatch() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = ["wycats@example.com"] [[bin]] name = "foo" [dependencies.notquitebar] path = "bar" "#, ) .file("src/bin/foo.rs", &main_file(r#""i am foo""#, &["bar"])) .file("bar/Cargo.toml", &basic_bin_manifest("bar")) .file("bar/src/bar.rs", &main_file(r#""i am bar""#, &[])) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no matching package named `notquitebar` found location searched: [ROOT]/foo/bar required by package `foo v0.0.1 ([ROOT]/foo)` "#]]) .run(); } // Ensure that renamed deps have a valid name #[cargo_test] fn cargo_compile_with_invalid_dep_rename() { let p = project() .file( "Cargo.toml", r#" [package] name = "buggin" version = "0.1.0" edition = "2015" [dependencies] "haha this isn't a valid name πŸ›" = { package = "libc", version = "0.1" } "#, ) .file("src/main.rs", &main_file(r#""What's good?""#, &[])) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid character ` ` in package name: `haha this isn't a valid name πŸ›`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters) --> Cargo.toml:8:17 | 8 | "haha this isn't a valid name πŸ›" = { package = "libc", version = "0.1" } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | "#]]) .run(); } #[cargo_test] fn cargo_compile_with_filename() { let p = project() .file("src/lib.rs", "") .file( "src/bin/a.rs", r#" extern crate foo; fn main() { println!("hello a.rs"); } "#, ) .file("examples/a.rs", r#"fn main() { println!("example"); }"#) .build(); p.cargo("build --bin bin.rs") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no bin target named `bin.rs`. Available bin targets: a "#]]) .run(); p.cargo("build --bin a.rs") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no bin target named `a.rs` Did you mean `a`? "#]]) .run(); p.cargo("build --example example.rs") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no example target named `example.rs`. Available example targets: a "#]]) .run(); p.cargo("build --example a.rs") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no example target named `a.rs` Did you mean `a`? "#]]) .run(); } #[cargo_test] fn incompatible_dependencies() { Package::new("bad", "0.1.0").publish(); Package::new("bad", "1.0.0").publish(); Package::new("bad", "1.0.1").publish(); Package::new("bad", "1.0.2").publish(); Package::new("bar", "0.1.0").dep("bad", "0.1.0").publish(); Package::new("baz", "0.1.1").dep("bad", "=1.0.0").publish(); Package::new("baz", "0.1.0").dep("bad", "=1.0.0").publish(); Package::new("qux", "0.1.2").dep("bad", ">=1.0.1").publish(); Package::new("qux", "0.1.1").dep("bad", ">=1.0.1").publish(); Package::new("qux", "0.1.0").dep("bad", ">=1.0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "0.1.0" baz = "0.1.0" qux = "0.1.0" "#, ) .file("src/main.rs", "fn main(){}") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for `bad`. ... required by package `qux v0.1.0` ... which satisfies dependency `qux = "^0.1.0"` of package `foo v0.0.1 ([ROOT]/foo)` versions that meet the requirements `>=1.0.1` are: 1.0.2, 1.0.1 all possible versions conflict with previously selected packages. previously selected package `bad v1.0.0` ... which satisfies dependency `bad = "=1.0.0"` of package `baz v0.1.0` ... which satisfies dependency `baz = "^0.1.0"` of package `foo v0.0.1 ([ROOT]/foo)` failed to select a version for `bad` which could resolve this conflict "#]]) .run(); } #[cargo_test] fn incompatible_dependencies_with_multi_semver() { Package::new("bad", "1.0.0").publish(); Package::new("bad", "1.0.1").publish(); Package::new("bad", "2.0.0").publish(); Package::new("bad", "2.0.1").publish(); Package::new("bar", "0.1.0").dep("bad", "=1.0.0").publish(); Package::new("baz", "0.1.0").dep("bad", ">=2.0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "0.1.0" baz = "0.1.0" bad = ">=1.0.1, <=2.0.0" "#, ) .file("src/main.rs", "fn main(){}") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for `bad`. ... required by package `foo v0.0.1 ([ROOT]/foo)` versions that meet the requirements `>=1.0.1, <=2.0.0` are: 2.0.0, 1.0.1 all possible versions conflict with previously selected packages. previously selected package `bad v2.0.1` ... which satisfies dependency `bad = ">=2.0.1"` of package `baz v0.1.0` ... which satisfies dependency `baz = "^0.1.0"` of package `foo v0.0.1 ([ROOT]/foo)` previously selected package `bad v1.0.0` ... which satisfies dependency `bad = "=1.0.0"` of package `bar v0.1.0` ... which satisfies dependency `bar = "^0.1.0"` of package `foo v0.0.1 ([ROOT]/foo)` failed to select a version for `bad` which could resolve this conflict "#]]) .run(); } #[cargo_test] fn compile_path_dep_then_change_version() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("build").run(); p.change_file("bar/Cargo.toml", &basic_manifest("bar", "0.0.2")); p.cargo("build").run(); } #[cargo_test] fn ignores_carriage_return_in_lockfile() { let p = project() .file("src/main.rs", "mod a; fn main() {}") .file("src/a.rs", "") .build(); p.cargo("build").run(); let lock = p.read_lockfile(); p.change_file("Cargo.lock", &lock.replace("\n", "\r\n")); p.cargo("build").run(); } #[cargo_test] fn cargo_default_env_metadata_env_var() { // Ensure that path dep + dylib + env_var get metadata // (even though path_dep + dylib should not) let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" "#, ) .file("src/lib.rs", "// hi") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [lib] name = "bar" crate-type = ["dylib"] "#, ) .file("bar/src/lib.rs", "// hello") .build(); let dll_prefix = env::consts::DLL_PREFIX; let dll_suffix = env::consts::DLL_SUFFIX; // No metadata on libbar since it's a dylib path dependency p.cargo("build -v") .with_stderr_data(format!( "\ ... [RUNNING] `rustc --crate-name foo [..]--extern bar=[ROOT]/foo/target/debug/deps/{dll_prefix}bar{dll_suffix}` ... ")) .run(); p.cargo("clean").run(); // If you set the env-var, then we expect metadata on libbar p.cargo("build -v") .env("__CARGO_DEFAULT_LIB_METADATA", "stable") .with_stderr_data(format!( "\ ... [RUNNING] `rustc --crate-name foo [..]--extern bar=[ROOT]/foo/target/debug/deps/{dll_prefix}bar-[..]{dll_suffix}` ... ")) .run(); } #[cargo_test] fn crate_env_vars() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.1-alpha.1" edition = "2015" description = "This is foo" homepage = "https://example.com" repository = "https://example.com/repo.git" authors = ["wycats@example.com"] license = "MIT OR Apache-2.0" license-file = "license.txt" rust-version = "1.61.0" readme = "../../README.md" [[bin]] name = "foo-bar" path = "src/main.rs" "#, ) .file( "src/main.rs", r#" extern crate foo; static VERSION_MAJOR: &'static str = env!("CARGO_PKG_VERSION_MAJOR"); static VERSION_MINOR: &'static str = env!("CARGO_PKG_VERSION_MINOR"); static VERSION_PATCH: &'static str = env!("CARGO_PKG_VERSION_PATCH"); static VERSION_PRE: &'static str = env!("CARGO_PKG_VERSION_PRE"); static VERSION: &'static str = env!("CARGO_PKG_VERSION"); static CARGO_MANIFEST_DIR: &'static str = env!("CARGO_MANIFEST_DIR"); static CARGO_MANIFEST_PATH: &'static str = env!("CARGO_MANIFEST_PATH"); static PKG_NAME: &'static str = env!("CARGO_PKG_NAME"); static HOMEPAGE: &'static str = env!("CARGO_PKG_HOMEPAGE"); static REPOSITORY: &'static str = env!("CARGO_PKG_REPOSITORY"); static LICENSE: &'static str = env!("CARGO_PKG_LICENSE"); static LICENSE_FILE: &'static str = env!("CARGO_PKG_LICENSE_FILE"); static DESCRIPTION: &'static str = env!("CARGO_PKG_DESCRIPTION"); static RUST_VERSION: &'static str = env!("CARGO_PKG_RUST_VERSION"); static README: &'static str = env!("CARGO_PKG_README"); static BIN_NAME: &'static str = env!("CARGO_BIN_NAME"); static CRATE_NAME: &'static str = env!("CARGO_CRATE_NAME"); fn main() { let s = format!("{}-{}-{} @ {} in {} file {}", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_PRE, CARGO_MANIFEST_DIR, CARGO_MANIFEST_PATH); assert_eq!(s, foo::version()); println!("{}", s); assert_eq!("foo", PKG_NAME); assert_eq!("foo-bar", BIN_NAME); assert_eq!("foo_bar", CRATE_NAME); assert_eq!("https://example.com", HOMEPAGE); assert_eq!("https://example.com/repo.git", REPOSITORY); assert_eq!("MIT OR Apache-2.0", LICENSE); assert_eq!("license.txt", LICENSE_FILE); assert_eq!("This is foo", DESCRIPTION); assert_eq!("1.61.0", RUST_VERSION); assert_eq!("../../README.md", README); let s = format!("{}.{}.{}-{}", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_PRE); assert_eq!(s, VERSION); // Verify CARGO_TARGET_TMPDIR isn't set for bins assert!(option_env!("CARGO_TARGET_TMPDIR").is_none()); } "#, ) .file( "src/lib.rs", r#" use std::env; use std::path::PathBuf; pub fn version() -> String { format!("{}-{}-{} @ {} in {} file {}", env!("CARGO_PKG_VERSION_MAJOR"), env!("CARGO_PKG_VERSION_MINOR"), env!("CARGO_PKG_VERSION_PATCH"), env!("CARGO_PKG_VERSION_PRE"), env!("CARGO_MANIFEST_DIR"), env!("CARGO_MANIFEST_PATH")) } pub fn check_no_int_test_env() { env::var("CARGO_TARGET_DIR").unwrap_err(); } pub fn check_tmpdir(tmp: Option<&'static str>) { let tmpdir: PathBuf = tmp.unwrap().into(); let exe: PathBuf = env::current_exe().unwrap().into(); let mut expected: PathBuf = exe.parent().unwrap() .parent().unwrap() .parent().unwrap() .into(); expected.push("tmp"); assert_eq!(tmpdir, expected); // Check that CARGO_TARGET_TMPDIR isn't set for lib code assert!(option_env!("CARGO_TARGET_TMPDIR").is_none()); env::var("CARGO_TARGET_TMPDIR").unwrap_err(); } #[test] fn unit_env_cargo_target_tmpdir() { // Check that CARGO_TARGET_TMPDIR isn't set for unit tests assert!(option_env!("CARGO_TARGET_TMPDIR").is_none()); env::var("CARGO_TARGET_TMPDIR").unwrap_err(); } "#, ) .file( "examples/ex-env-vars.rs", r#" static PKG_NAME: &'static str = env!("CARGO_PKG_NAME"); static BIN_NAME: &'static str = env!("CARGO_BIN_NAME"); static CRATE_NAME: &'static str = env!("CARGO_CRATE_NAME"); fn main() { assert_eq!("foo", PKG_NAME); assert_eq!("ex-env-vars", BIN_NAME); assert_eq!("ex_env_vars", CRATE_NAME); // Verify CARGO_TARGET_TMPDIR isn't set for examples assert!(option_env!("CARGO_TARGET_TMPDIR").is_none()); } "#, ) .file( "tests/env.rs", r#" #[test] fn integration_env_cargo_target_tmpdir() { foo::check_tmpdir(option_env!("CARGO_TARGET_TMPDIR")); } "#, ); let p = if is_nightly() { p.file( "benches/env.rs", r#" #![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_env_cargo_target_tmpdir(_: &mut Bencher) { foo::check_tmpdir(option_env!("CARGO_TARGET_TMPDIR")); } "#, ) .build() } else { p.build() }; println!("build"); p.cargo("build -v").run(); println!("bin"); p.process(&p.bin("foo-bar")) .with_stdout_data(str![[r#" 0-5-1 @ alpha.1 in [ROOT]/foo file [ROOT]/foo/Cargo.toml "#]]) .run(); println!("example"); p.cargo("run --example ex-env-vars -v").run(); println!("test"); p.cargo("test -v").run(); if is_nightly() { println!("bench"); p.cargo("bench -v").run(); } } #[cargo_test] fn crate_authors_env_vars() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.1-alpha.1" edition = "2015" authors = ["wycats@example.com", "neikos@example.com"] "#, ) .file( "src/main.rs", r#" extern crate foo; static AUTHORS: &'static str = env!("CARGO_PKG_AUTHORS"); fn main() { let s = "wycats@example.com:neikos@example.com"; assert_eq!(AUTHORS, foo::authors()); println!("{}", AUTHORS); assert_eq!(s, AUTHORS); } "#, ) .file( "src/lib.rs", r#" pub fn authors() -> String { format!("{}", env!("CARGO_PKG_AUTHORS")) } "#, ) .build(); println!("build"); p.cargo("build -v").run(); println!("bin"); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" wycats@example.com:neikos@example.com "#]]) .run(); println!("test"); p.cargo("test -v").run(); } #[cargo_test] fn vv_prints_rustc_env_vars() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = ["escape='\"@example.com"] "#, ) .file("src/main.rs", "fn main() {}") .build(); let mut b = p.cargo("build -vv"); #[cfg(windows)] { b.with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] CARGO_PKG_AUTHORS="escape='/"@example.com"&& [..] set CARGO_PKG_NAME=foo&& [..] rustc [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } #[cfg(not(windows))] { b.with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] CARGO_PKG_AUTHORS='escape='/''"@example.com' [..] CARGO_PKG_NAME=foo [..] rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } b.run(); } // The tester may already have LD_LIBRARY_PATH=::/foo/bar which leads to a false positive error fn setenv_for_removing_empty_component(mut execs: Execs) -> Execs { let v = dylib_path_envvar(); if let Ok(search_path) = env::var(v) { let new_search_path = env::join_paths(env::split_paths(&search_path).filter(|e| !e.as_os_str().is_empty())) .expect("join_paths"); execs.env(v, new_search_path); // build_command() will override LD_LIBRARY_PATH accordingly } execs } // Regression test for #4277 #[cargo_test] fn crate_library_path_env_var() { let p = project() .file( "src/main.rs", &format!( r#" fn main() {{ let search_path = env!("{}"); let paths = std::env::split_paths(&search_path).collect::>(); assert!(!paths.contains(&"".into())); }} "#, dylib_path_envvar() ), ) .build(); setenv_for_removing_empty_component(p.cargo("run")).run(); } // See https://github.com/rust-lang/cargo/issues/14194 #[cargo_test] fn issue_14194_deduplicate_library_path_env_var() { let p = project() .file( "src/main.rs", &format!( r#" use std::process::Command; fn main() {{ let level: i32 = std::env::args().nth(1).unwrap().parse().unwrap(); let txt = "var.txt"; let lib_path = std::env::var("{}").unwrap(); // Make sure we really have something in dylib search path. let count = std::env::split_paths(&lib_path).count(); assert!(count > 0); if level >= 3 {{ std::fs::write(txt, &lib_path).unwrap(); }} else {{ let prev_lib_path = std::fs::read_to_string(txt).unwrap(); // Ensure no duplicate insertion to dylib search paths // when calling `cargo run` recursively. assert_eq!(lib_path, prev_lib_path); }} if level == 0 {{ return; }} let _ = Command::new(std::env!("CARGO")) .arg("run") .arg("--") .arg((level - 1).to_string()) .status() .unwrap(); }} "#, dylib_path_envvar(), ), ) .build(); setenv_for_removing_empty_component(p.cargo("run -- 3")) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE] 3` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE] 2` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE] 1` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE] 0` "#]]) .run(); } // Regression test for #4277 #[cargo_test] fn build_with_fake_libc_not_loading() { let p = project() .file("src/main.rs", "fn main() {}") .file("src/lib.rs", r#" "#) .file("libc.so.6", r#""#) .build(); setenv_for_removing_empty_component(p.cargo("build")).run(); } // this is testing that src/.rs still works (for now) #[cargo_test] fn many_crate_types_old_style_lib_location() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [lib] name = "foo" crate-type = ["rlib", "dylib"] "#, ) .file("src/foo.rs", "pub fn foo() {}") .build(); p.cargo("build") .with_stderr_data(str![[r#" [WARNING] path `src/foo.rs` was erroneously implicitly accepted for library `foo`, please rename the file to `src/lib.rs` or set lib.path in Cargo.toml [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.root().join("target/debug/libfoo.rlib").is_file()); let fname = format!("{}foo{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX); assert!(p.root().join("target/debug").join(&fname).is_file()); } #[cargo_test] fn many_crate_types_correct() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [lib] name = "foo" crate-type = ["rlib", "dylib"] "#, ) .file("src/lib.rs", "pub fn foo() {}") .build(); p.cargo("build").run(); assert!(p.root().join("target/debug/libfoo.rlib").is_file()); let fname = format!("{}foo{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX); assert!(p.root().join("target/debug").join(&fname).is_file()); } #[cargo_test] fn set_both_dylib_and_cdylib_crate_types() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [lib] name = "foo" crate-type = ["cdylib", "dylib"] "#, ) .file("src/lib.rs", "pub fn foo() {}") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: library `foo` cannot set the crate type of both `dylib` and `cdylib` "#]]) .run(); } #[cargo_test] fn self_dependency() { let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" authors = [] [dependencies.test] path = "." [lib] name = "test" path = "src/test.rs" "#, ) .file("src/test.rs", "fn main() {}") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cyclic package dependency: package `test v0.0.0 ([ROOT]/foo)` depends on itself. Cycle: package `test v0.0.0 ([ROOT]/foo)` ... which satisfies path dependency `test` of package `test v0.0.0 ([ROOT]/foo)` "#]]) .run(); } #[cargo_test] /// Make sure broken and loop symlinks don't break the build /// /// This test requires you to be able to make symlinks. /// For windows, this may require you to enable developer mode. fn ignore_broken_symlinks() { if !symlink_supported() { return; } let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", &main_file(r#""i am foo""#, &[])) .symlink("Notafile", "bar") // To hit the symlink directory, we need a build script // to trigger a full scan of package files. .file("build.rs", &main_file(r#""build script""#, &[])) .symlink_dir("a/b", "a/b/c/d/foo") .build(); p.cargo("build") .with_stderr_data(str![[r#" [WARNING] File system loop found: [ROOT]/foo/a/b/c/d/foo points to an ancestor [ROOT]/foo/a/b [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" i am foo "#]]) .run(); } #[cargo_test] fn missing_lib_and_bin() { let p = project().build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: no targets specified in the manifest either src/lib.rs, src/main.rs, a [lib] section, or [[bin]] section must be present "#]]) .run(); } #[cargo_test] fn lto_build() { let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" authors = [] [profile.release] lto = true "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v --release") .with_stderr_data(str![[r#" [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name test --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]link -C opt-level=3 -C lto [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn explicit_examples() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" authors = [] [lib] name = "foo" path = "src/lib.rs" [[example]] name = "hello" path = "examples/ex-hello.rs" [[example]] name = "goodbye" path = "examples/ex-goodbye.rs" "#, ) .file( "src/lib.rs", r#" pub fn get_hello() -> &'static str { "Hello" } pub fn get_goodbye() -> &'static str { "Goodbye" } pub fn get_world() -> &'static str { "World" } "#, ) .file( "examples/ex-hello.rs", r#" extern crate foo; fn main() { println!("{}, {}!", foo::get_hello(), foo::get_world()); } "#, ) .file( "examples/ex-goodbye.rs", r#" extern crate foo; fn main() { println!("{}, {}!", foo::get_goodbye(), foo::get_world()); } "#, ) .build(); p.cargo("build --examples").run(); p.process(&p.bin("examples/hello")) .with_stdout_data(str![[r#" Hello, World! "#]]) .run(); p.process(&p.bin("examples/goodbye")) .with_stdout_data(str![[r#" Goodbye, World! "#]]) .run(); } #[cargo_test] fn non_existing_test() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" [lib] name = "foo" path = "src/lib.rs" [[test]] name = "hello" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build --tests -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: can't find `hello` test at `tests/hello.rs` or `tests/hello/main.rs`. Please specify test.path if you want to use a non-default path. "#]]) .run(); } #[cargo_test] fn non_existing_example() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" [lib] name = "foo" path = "src/lib.rs" [[example]] name = "hello" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build --examples -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: can't find `hello` example at `examples/hello.rs` or `examples/hello/main.rs`. Please specify example.path if you want to use a non-default path. "#]]) .run(); } #[cargo_test] fn non_existing_benchmark() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" [lib] name = "foo" path = "src/lib.rs" [[bench]] name = "hello" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build --benches -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: can't find `hello` bench at `benches/hello.rs` or `benches/hello/main.rs`. Please specify bench.path if you want to use a non-default path. "#]]) .run(); } #[cargo_test] fn non_existing_binary() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/lib.rs", "") .file("src/bin/ehlo.rs", "") .build(); p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: can't find `foo` bin at `src/bin/foo.rs` or `src/bin/foo/main.rs`. Please specify bin.path if you want to use a non-default path. "#]]) .run(); } #[cargo_test] fn commonly_wrong_path_of_test() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" [lib] name = "foo" path = "src/lib.rs" [[test]] name = "foo" "#, ) .file("src/lib.rs", "") .file("test/foo.rs", "") .build(); p.cargo("build --tests -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: can't find `foo` test at default paths, but found a file at `test/foo.rs`. Perhaps rename the file to `tests/foo.rs` for target auto-discovery, or specify test.path if you want to use a non-default path. "#]]) .run(); } #[cargo_test] fn commonly_wrong_path_of_example() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" [lib] name = "foo" path = "src/lib.rs" [[example]] name = "foo" "#, ) .file("src/lib.rs", "") .file("example/foo.rs", "") .build(); p.cargo("build --examples -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: can't find `foo` example at default paths, but found a file at `example/foo.rs`. Perhaps rename the file to `examples/foo.rs` for target auto-discovery, or specify example.path if you want to use a non-default path. "#]]) .run(); } #[cargo_test] fn commonly_wrong_path_of_benchmark() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" [lib] name = "foo" path = "src/lib.rs" [[bench]] name = "foo" "#, ) .file("src/lib.rs", "") .file("bench/foo.rs", "") .build(); p.cargo("build --benches -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: can't find `foo` bench at default paths, but found a file at `bench/foo.rs`. Perhaps rename the file to `benches/foo.rs` for target auto-discovery, or specify bench.path if you want to use a non-default path. "#]]) .run(); } #[cargo_test] fn commonly_wrong_path_binary() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/lib.rs", "") .file("src/bins/foo.rs", "") .build(); p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: can't find `foo` bin at default paths, but found a file at `src/bins/foo.rs`. Perhaps rename the file to `src/bin/foo.rs` for target auto-discovery, or specify bin.path if you want to use a non-default path. "#]]) .run(); } #[cargo_test] fn commonly_wrong_path_subdir_binary() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/lib.rs", "") .file("src/bins/foo/main.rs", "") .build(); p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: can't find `foo` bin at default paths, but found a file at `src/bins/foo/main.rs`. Perhaps rename the file to `src/bin/foo/main.rs` for target auto-discovery, or specify bin.path if you want to use a non-default path. "#]]) .run(); } #[cargo_test] fn found_multiple_target_files() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/lib.rs", "") .file("src/bin/foo.rs", "") .file("src/bin/foo/main.rs", "") .build(); p.cargo("build -v") .with_status(101) // Don't assert the inferred paths since the order is non-deterministic. .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: cannot infer path for `foo` bin Cargo doesn't know which to use because multiple target files found at `src/bin/foo[..]rs` and `src/bin/foo[..].rs`. "#]]) .run(); } #[cargo_test] fn legacy_binary_paths_warnings() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" authors = [] [[bin]] name = "bar" "#, ) .file("src/lib.rs", "") .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [WARNING] An explicit [[bin]] section is specified in Cargo.toml which currently disables Cargo from automatically inferring other binary targets. This inference behavior will change in the Rust 2018 edition and the following files will be included as a binary target: * src/main.rs This is likely to break cargo build or cargo test as these files may not be ready to be compiled as a binary target today. You can future-proof yourself and disable this warning by adding `autobins = false` to your [package] section. You may also move the files to a location where Cargo would not automatically infer them to be a target, such as in subfolders. For more information on this warning you can consult https://github.com/rust-lang/cargo/issues/5330 [WARNING] path `src/main.rs` was erroneously implicitly accepted for binary `bar`, please set bin.path in Cargo.toml [COMPILING] foo v1.0.0 ([ROOT]/foo) [RUNNING] `rustc [..]` [RUNNING] `rustc [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" authors = [] [[bin]] name = "bar" "#, ) .file("src/lib.rs", "") .file("src/bin/main.rs", "fn main() {}") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [WARNING] An explicit [[bin]] section is specified in Cargo.toml which currently disables Cargo from automatically inferring other binary targets. This inference behavior will change in the Rust 2018 edition and the following files will be included as a binary target: * src/bin/main.rs This is likely to break cargo build or cargo test as these files may not be ready to be compiled as a binary target today. You can future-proof yourself and disable this warning by adding `autobins = false` to your [package] section. You may also move the files to a location where Cargo would not automatically infer them to be a target, such as in subfolders. For more information on this warning you can consult https://github.com/rust-lang/cargo/issues/5330 [WARNING] path `src/bin/main.rs` was erroneously implicitly accepted for binary `bar`, please set bin.path in Cargo.toml [COMPILING] foo v1.0.0 ([ROOT]/foo) [RUNNING] `rustc [..]` [RUNNING] `rustc [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" authors = [] [[bin]] name = "bar" "#, ) .file("src/bar.rs", "fn main() {}") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [WARNING] path `src/bar.rs` was erroneously implicitly accepted for binary `bar`, please set bin.path in Cargo.toml [COMPILING] foo v1.0.0 ([ROOT]/foo) [RUNNING] `rustc [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn implicit_examples() { let p = project() .file( "src/lib.rs", r#" pub fn get_hello() -> &'static str { "Hello" } pub fn get_goodbye() -> &'static str { "Goodbye" } pub fn get_world() -> &'static str { "World" } "#, ) .file( "examples/hello.rs", r#" extern crate foo; fn main() { println!("{}, {}!", foo::get_hello(), foo::get_world()); } "#, ) .file( "examples/goodbye.rs", r#" extern crate foo; fn main() { println!("{}, {}!", foo::get_goodbye(), foo::get_world()); } "#, ) .build(); p.cargo("build --examples").run(); p.process(&p.bin("examples/hello")) .with_stdout_data(str![[r#" Hello, World! "#]]) .run(); p.process(&p.bin("examples/goodbye")) .with_stdout_data(str![[r#" Goodbye, World! "#]]) .run(); } #[cargo_test] fn standard_build_no_ndebug() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/foo.rs", r#" fn main() { if cfg!(debug_assertions) { println!("slow") } else { println!("fast") } } "#, ) .build(); p.cargo("build").run(); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" slow "#]]) .run(); } #[cargo_test] fn release_build_ndebug() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/foo.rs", r#" fn main() { if cfg!(debug_assertions) { println!("slow") } else { println!("fast") } } "#, ) .build(); p.cargo("build --release").run(); p.process(&p.release_bin("foo")) .with_stdout_data(str![[r#" fast "#]]) .run(); } #[cargo_test] fn inferred_main_bin() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("build").run(); p.process(&p.bin("foo")).run(); } #[cargo_test] fn deletion_causes_failure() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" "#, ) .file("src/main.rs", "extern crate bar; fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("build").run(); p.change_file("Cargo.toml", &basic_manifest("foo", "0.0.1")); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) error[E0463]: can't find crate for `bar` ... [ERROR] could not compile `foo` (bin "foo") due to 1 previous error "#]]) .run(); } #[cargo_test] fn bad_cargo_toml_in_target_dir() { let p = project() .file("src/main.rs", "fn main() {}") .file("target/Cargo.toml", "bad-toml") .build(); p.cargo("build").run(); p.process(&p.bin("foo")).run(); } #[cargo_test] fn lib_with_standard_name() { let p = project() .file("Cargo.toml", &basic_manifest("syntax", "0.0.1")) .file("src/lib.rs", "pub fn foo() {}") .file( "src/main.rs", "extern crate syntax; fn main() { syntax::foo() }", ) .build(); p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] syntax v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn simple_staticlib() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" edition = "2015" [lib] name = "foo" crate-type = ["staticlib"] "#, ) .file("src/lib.rs", "pub fn foo() {}") .build(); // env var is a test for #1381 p.cargo("build").env("CARGO_LOG", "nekoneko=trace").run(); } #[cargo_test] fn staticlib_rlib_and_bin() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" edition = "2015" [lib] name = "foo" crate-type = ["staticlib", "rlib"] "#, ) .file("src/lib.rs", "pub fn foo() {}") .file("src/main.rs", "extern crate foo; fn main() { foo::foo(); }") .build(); p.cargo("build -v").run(); } #[cargo_test] fn opt_out_of_bin() { let p = project() .file( "Cargo.toml", r#" bin = [] [package] name = "foo" authors = [] version = "0.0.1" edition = "2015" "#, ) .file("src/lib.rs", "") .file("src/main.rs", "bad syntax") .build(); p.cargo("build").run(); } #[cargo_test] fn single_lib() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" edition = "2015" [lib] name = "foo" path = "src/bar.rs" "#, ) .file("src/bar.rs", "") .build(); p.cargo("build").run(); } #[cargo_test] fn freshness_ignores_excluded() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] build = "build.rs" exclude = ["src/b*.rs"] "#, ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "pub fn bar() -> i32 { 1 }") .build(); foo.root().move_into_the_past(); foo.cargo("build") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Smoke test to make sure it doesn't compile again println!("first pass"); foo.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Modify an ignored file and make sure we don't rebuild println!("second pass"); foo.change_file("src/bar.rs", ""); foo.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rebuild_preserves_out_dir() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] build = 'build.rs' "#, ) .file( "build.rs", r#" use std::env; use std::fs::File; use std::path::Path; fn main() { let path = Path::new(&env::var("OUT_DIR").unwrap()).join("foo"); if env::var_os("FIRST").is_some() { File::create(&path).unwrap(); } else { File::create(&path).unwrap(); } } "#, ) .file("src/lib.rs", "pub fn bar() -> i32 { 1 }") .build(); foo.root().move_into_the_past(); foo.cargo("build") .env("FIRST", "1") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); foo.change_file("src/bar.rs", ""); foo.cargo("build") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn dep_no_libs() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies.bar] path = "bar" "#, ) .file("src/lib.rs", "pub fn bar() -> i32 { 1 }") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.0")) .file("bar/src/main.rs", "") .build(); foo.cargo("build").run(); } #[cargo_test] fn recompile_space_in_name() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [lib] name = "foo" path = "src/my lib.rs" "#, ) .file("src/my lib.rs", "") .build(); foo.cargo("build").run(); foo.root().move_into_the_past(); foo.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cfg(unix)] #[cargo_test] fn credentials_is_unreadable() { use cargo_test_support::paths::home; use std::os::unix::prelude::*; let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/lib.rs", "") .build(); let credentials = home().join(".cargo/credentials.toml"); t!(fs::create_dir_all(credentials.parent().unwrap())); t!(fs::write( &credentials, r#" [registry] token = "api-token" "# )); let stat = fs::metadata(credentials.as_path()).unwrap(); let mut perms = stat.permissions(); perms.set_mode(0o000); fs::set_permissions(credentials, perms).unwrap(); p.cargo("build").run(); } #[cfg(unix)] #[cargo_test] fn ignore_bad_directories() { use std::os::unix::prelude::*; let foo = project() .file("Cargo.toml", &basic_manifest("foo", "0.0.0")) .file("src/lib.rs", "") .build(); let dir = foo.root().join("tmp"); fs::create_dir(&dir).unwrap(); let stat = fs::metadata(&dir).unwrap(); let mut perms = stat.permissions(); perms.set_mode(0o644); fs::set_permissions(&dir, perms.clone()).unwrap(); foo.cargo("build").run(); perms.set_mode(0o755); fs::set_permissions(&dir, perms).unwrap(); } #[cargo_test] fn bad_cargo_config() { let foo = project() .file("Cargo.toml", &basic_manifest("foo", "0.0.0")) .file("src/lib.rs", "") .file(".cargo/config.toml", "this is not valid toml") .build(); foo.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] could not load Cargo configuration Caused by: could not parse TOML configuration in `[ROOT]/foo/.cargo/config.toml` Caused by: TOML parse error at line 1, column 6 | 1 | this is not valid toml | ^ expected `.`, `=` "#]]) .run(); } #[cargo_test] fn cargo_platform_specific_dependency() { let host = rustc_host(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] build = "build.rs" [target.{host}.dependencies] dep = {{ path = "dep" }} [target.{host}.build-dependencies] build = {{ path = "build" }} [target.{host}.dev-dependencies] dev = {{ path = "dev" }} "#, host = host ), ) .file("src/main.rs", "extern crate dep; fn main() { dep::dep() }") .file( "tests/foo.rs", "extern crate dev; #[test] fn foo() { dev::dev() }", ) .file( "build.rs", "extern crate build; fn main() { build::build(); }", ) .file("dep/Cargo.toml", &basic_manifest("dep", "0.5.0")) .file("dep/src/lib.rs", "pub fn dep() {}") .file("build/Cargo.toml", &basic_manifest("build", "0.5.0")) .file("build/src/lib.rs", "pub fn build() {}") .file("dev/Cargo.toml", &basic_manifest("dev", "0.5.0")) .file("dev/src/lib.rs", "pub fn dev() {}") .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); p.cargo("test").run(); } #[cargo_test] fn bad_platform_specific_dependency() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [target.wrong-target.dependencies.bar] path = "bar" "#, ) .file("src/main.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"])) .file("bar/Cargo.toml", &basic_manifest("bar", "0.5.0")) .file( "bar/src/lib.rs", r#"pub fn gimme() -> String { format!("") }"#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] foo v0.5.0 ([ROOT]/foo) error[E0463]: can't find crate for `bar` ... [ERROR] could not compile `foo` (bin "foo") due to 1 previous error "#]]) .run(); } #[cargo_test] fn cargo_platform_specific_dependency_wrong_platform() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [target.non-existing-triplet.dependencies.bar] path = "bar" "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.5.0")) .file( "bar/src/lib.rs", "invalid rust file, should not be compiled", ) .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")).run(); let lockfile = p.read_lockfile(); assert!(lockfile.contains("bar")); } #[cargo_test] fn example_as_lib() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[example]] name = "ex" crate-type = ["lib"] "#, ) .file("src/lib.rs", "") .file("examples/ex.rs", "") .build(); p.cargo("build --example=ex").run(); assert!(p.example_lib("ex", "lib").is_file()); } #[cargo_test] fn example_as_rlib() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[example]] name = "ex" crate-type = ["rlib"] "#, ) .file("src/lib.rs", "") .file("examples/ex.rs", "") .build(); p.cargo("build --example=ex").run(); assert!(p.example_lib("ex", "rlib").is_file()); } #[cargo_test] fn example_as_dylib() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[example]] name = "ex" crate-type = ["dylib"] "#, ) .file("src/lib.rs", "") .file("examples/ex.rs", "") .build(); p.cargo("build --example=ex").run(); assert!(p.example_lib("ex", "dylib").is_file()); } #[cargo_test] fn example_as_proc_macro() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[example]] name = "ex" crate-type = ["proc-macro"] "#, ) .file("src/lib.rs", "") .file( "examples/ex.rs", r#" extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro] pub fn eat(_item: TokenStream) -> TokenStream { "".parse().unwrap() } "#, ) .build(); p.cargo("build --example=ex").run(); assert!(p.example_lib("ex", "proc-macro").is_file()); } #[cargo_test] fn example_bin_same_name() { let p = project() .file("src/main.rs", "fn main() {}") .file("examples/foo.rs", "fn main() {}") .build(); p.cargo("build --examples").run(); assert!(!p.bin("foo").is_file()); // We expect a file of the form bin/foo-{metadata_hash} assert!(p.bin("examples/foo").is_file()); p.cargo("build --examples").run(); assert!(!p.bin("foo").is_file()); // We expect a file of the form bin/foo-{metadata_hash} assert!(p.bin("examples/foo").is_file()); } #[cargo_test] fn compile_then_delete() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("run -v").run(); assert!(p.bin("foo").is_file()); if cfg!(windows) { // On windows unlinking immediately after running often fails, so sleep sleep_ms(100); } fs::remove_file(&p.bin("foo")).unwrap(); p.cargo("run -v").run(); } #[cargo_test] fn transitive_dependencies_not_available() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.aaaaa] path = "a" "#, ) .file( "src/main.rs", "extern crate bbbbb; extern crate aaaaa; fn main() {}", ) .file( "a/Cargo.toml", r#" [package] name = "aaaaa" version = "0.0.1" edition = "2015" authors = [] [dependencies.bbbbb] path = "../b" "#, ) .file("a/src/lib.rs", "extern crate bbbbb;") .file("b/Cargo.toml", &basic_manifest("bbbbb", "0.0.1")) .file("b/src/lib.rs", "") .build(); p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] bbbbb v0.0.1 ([ROOT]/foo/b) [RUNNING] `rustc [..] [COMPILING] aaaaa v0.0.1 ([ROOT]/foo/a) [RUNNING] `rustc [..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]` error[E0463]: can't find crate for `bbbbb` ... [ERROR] could not compile `foo` (bin "foo") due to 1 previous error Caused by: process didn't exit successfully: `rustc [..]` ([EXIT_STATUS]: 1) "#]]) .run(); } #[cargo_test] fn cyclic_deps_rejected() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.a] path = "a" "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [dependencies.foo] path = ".." "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cyclic package dependency: package `a v0.0.1 ([ROOT]/foo/a)` depends on itself. Cycle: package `a v0.0.1 ([ROOT]/foo/a)` ... which satisfies path dependency `a` of package `foo v0.0.1 ([ROOT]/foo)` ... which satisfies path dependency `foo` of package `a v0.0.1 ([ROOT]/foo/a)` "#]]) .run(); } #[cargo_test] fn predictable_filenames() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] name = "foo" crate-type = ["dylib", "rlib"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v").run(); assert!(p.root().join("target/debug/libfoo.rlib").is_file()); let dylib_name = format!("{}foo{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX); assert!(p.root().join("target/debug").join(dylib_name).is_file()); } #[cargo_test] fn dashes_to_underscores() { let p = project() .file("Cargo.toml", &basic_manifest("foo-bar", "0.0.1")) .file("src/lib.rs", "") .file("src/main.rs", "extern crate foo_bar; fn main() {}") .build(); p.cargo("build -v").run(); assert!(p.bin("foo-bar").is_file()); } #[cargo_test] fn dashes_in_crate_name_bad() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] name = "foo-bar" "#, ) .file("src/lib.rs", "") .file("src/main.rs", "extern crate foo_bar; fn main() {}") .build(); p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: library target names cannot contain hyphens: foo-bar "#]]) .run(); } #[cargo_test] fn rustc_env_var() { let p = project().file("src/lib.rs", "").build(); p.cargo("build -v") .env("RUSTC", "rustc-that-does-not-exist") .with_status(101) .with_stderr_data(str![[r#" [ERROR] could not execute process `rustc-that-does-not-exist -vV` (never executed) Caused by: [..] "#]]) .run(); assert!(!p.bin("a").is_file()); } #[cargo_test] fn filtering() { let p = project() .file("src/lib.rs", "") .file("src/bin/a.rs", "fn main() {}") .file("src/bin/b.rs", "fn main() {}") .file("examples/a.rs", "fn main() {}") .file("examples/b.rs", "fn main() {}") .build(); p.cargo("build --lib").run(); assert!(!p.bin("a").is_file()); p.cargo("build --bin=a --example=a").run(); assert!(p.bin("a").is_file()); assert!(!p.bin("b").is_file()); assert!(p.bin("examples/a").is_file()); assert!(!p.bin("examples/b").is_file()); } #[cargo_test] fn filtering_implicit_bins() { let p = project() .file("src/lib.rs", "") .file("src/bin/a.rs", "fn main() {}") .file("src/bin/b.rs", "fn main() {}") .file("examples/a.rs", "fn main() {}") .file("examples/b.rs", "fn main() {}") .build(); p.cargo("build --bins").run(); assert!(p.bin("a").is_file()); assert!(p.bin("b").is_file()); assert!(!p.bin("examples/a").is_file()); assert!(!p.bin("examples/b").is_file()); } #[cargo_test] fn filtering_implicit_examples() { let p = project() .file("src/lib.rs", "") .file("src/bin/a.rs", "fn main() {}") .file("src/bin/b.rs", "fn main() {}") .file("examples/a.rs", "fn main() {}") .file("examples/b.rs", "fn main() {}") .build(); p.cargo("build --examples").run(); assert!(!p.bin("a").is_file()); assert!(!p.bin("b").is_file()); assert!(p.bin("examples/a").is_file()); assert!(p.bin("examples/b").is_file()); } #[cargo_test] fn ignore_dotfile() { let p = project() .file("src/bin/.a.rs", "") .file("src/bin/a.rs", "fn main() {}") .build(); p.cargo("build").run(); } #[cargo_test] fn ignore_dotdirs() { let p = project() .file("src/bin/a.rs", "fn main() {}") .file(".git/Cargo.toml", "") .file(".pc/dummy-fix.patch/Cargo.toml", "") .build(); p.cargo("build").run(); } #[cargo_test] fn dotdir_root() { let p = ProjectBuilder::new(root().join(".foo")) .file("src/bin/a.rs", "fn main() {}") .build(); p.cargo("build").run(); } #[cargo_test] fn custom_target_dir_env() { let p = project().file("src/main.rs", "fn main() {}").build(); let exe_name = format!("foo{}", env::consts::EXE_SUFFIX); p.cargo("build").env("CARGO_TARGET_DIR", "foo/target").run(); assert!(p.root().join("foo/target/debug").join(&exe_name).is_file()); assert!(!p.root().join("target/debug").join(&exe_name).is_file()); p.cargo("build").run(); assert!(p.root().join("foo/target/debug").join(&exe_name).is_file()); assert!(p.root().join("target/debug").join(&exe_name).is_file()); p.cargo("build") .env("CARGO_BUILD_TARGET_DIR", "foo2/target") .run(); assert!(p.root().join("foo2/target/debug").join(&exe_name).is_file()); p.change_file( ".cargo/config.toml", r#" [build] target-dir = "foo/target" "#, ); p.cargo("build").env("CARGO_TARGET_DIR", "bar/target").run(); assert!(p.root().join("bar/target/debug").join(&exe_name).is_file()); assert!(p.root().join("foo/target/debug").join(&exe_name).is_file()); assert!(p.root().join("target/debug").join(&exe_name).is_file()); } #[cargo_test] fn custom_target_dir_line_parameter() { let p = project().file("src/main.rs", "fn main() {}").build(); let exe_name = format!("foo{}", env::consts::EXE_SUFFIX); p.cargo("build --target-dir foo/target").run(); assert!(p.root().join("foo/target/debug").join(&exe_name).is_file()); assert!(!p.root().join("target/debug").join(&exe_name).is_file()); p.cargo("build").run(); assert!(p.root().join("foo/target/debug").join(&exe_name).is_file()); assert!(p.root().join("target/debug").join(&exe_name).is_file()); p.change_file( ".cargo/config.toml", r#" [build] target-dir = "foo/target" "#, ); p.cargo("build --target-dir bar/target").run(); assert!(p.root().join("bar/target/debug").join(&exe_name).is_file()); assert!(p.root().join("foo/target/debug").join(&exe_name).is_file()); assert!(p.root().join("target/debug").join(&exe_name).is_file()); p.cargo("build --target-dir foobar/target") .env("CARGO_TARGET_DIR", "bar/target") .run(); assert!(p .root() .join("foobar/target/debug") .join(&exe_name) .is_file()); assert!(p.root().join("bar/target/debug").join(&exe_name).is_file()); assert!(p.root().join("foo/target/debug").join(&exe_name).is_file()); assert!(p.root().join("target/debug").join(&exe_name).is_file()); } #[cargo_test] fn build_multiple_packages() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.d1] path = "d1" [dependencies.d2] path = "d2" [[bin]] name = "foo" "#, ) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .file("d1/Cargo.toml", &basic_bin_manifest("d1")) .file("d1/src/lib.rs", "") .file("d1/src/main.rs", "fn main() { println!(\"d1\"); }") .file( "d2/Cargo.toml", r#" [package] name = "d2" version = "0.0.1" edition = "2015" authors = [] [[bin]] name = "d2" doctest = false "#, ) .file("d2/src/main.rs", "fn main() { println!(\"d2\"); }") .build(); p.cargo("build -p d1 -p d2 -p foo").run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" i am foo "#]]) .run(); let d1_path = &p .build_dir() .join("debug") .join(format!("d1{}", env::consts::EXE_SUFFIX)); let d2_path = &p .build_dir() .join("debug") .join(format!("d2{}", env::consts::EXE_SUFFIX)); assert!(d1_path.is_file()); p.process(d1_path) .with_stdout_data(str![[r#" d1 "#]]) .run(); assert!(d2_path.is_file()); p.process(d2_path) .with_stdout_data(str![[r#" d2 "#]]) .run(); } #[cargo_test] fn invalid_spec() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.d1] path = "d1" [[bin]] name = "foo" "#, ) .file("src/bin/foo.rs", &main_file(r#""i am foo""#, &[])) .file("d1/Cargo.toml", &basic_bin_manifest("d1")) .file("d1/src/lib.rs", "") .file("d1/src/main.rs", "fn main() { println!(\"d1\"); }") .build(); p.cargo("build -p notAValidDep") .with_status(101) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [ERROR] package ID specification `notAValidDep` did not match any packages "#]]) .run(); p.cargo("build -p d1 -p notAValidDep") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package ID specification `notAValidDep` did not match any packages "#]]) .run(); } #[cargo_test] fn manifest_with_bom_is_ok() { let p = project() .file( "Cargo.toml", "\u{FEFF} [package] name = \"foo\" version = \"0.0.1\" edition = \"2015\" authors = [] ", ) .file("src/lib.rs", "") .build(); p.cargo("build -v").run(); } #[cargo_test] fn panic_abort_compiles_with_panic_abort() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [profile.dev] panic = 'abort' "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] -C panic=abort [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn compiler_json_error_format() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] path = "bar" "#, ) .file( "build.rs", "fn main() { println!(\"cargo::rustc-cfg=xyz\") }", ) .file("src/main.rs", "fn main() { let unused = 92; }") .file("bar/Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("bar/src/lib.rs", r#"fn dead() {}"#) .build(); let output = |fresh| { r#" [ { "executable": null, "features": [], "fresh": $FRESH, "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.5.0", "reason": "compiler-artifact", "target": { "kind": ["custom-build"], "...": "{...}" }, "...": "{...}" }, { "manifest_path": "[ROOT]/foo/bar/Cargo.toml", "package_id": "path+[ROOTURL]/foo/bar#0.5.0", "reason": "compiler-message", "target": { "kind": ["lib"], "...": "{...}" }, "...": "{...}" }, { "executable": null, "features": [], "fresh": $FRESH, "manifest_path": "[ROOT]/foo/bar/Cargo.toml", "package_id": "path+[ROOTURL]/foo/bar#0.5.0", "reason": "compiler-artifact", "target": { "kind": ["lib"], "...": "{...}" }, "...": "{...}" }, { "cfgs": [ "xyz" ], "env": [], "linked_libs": [], "linked_paths": [], "out_dir": "[ROOT]/foo/target/debug/build/foo-[HASH]/out", "package_id": "path+[ROOTURL]/foo#0.5.0", "reason": "build-script-executed" }, { "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.5.0", "reason": "compiler-message", "target": { "kind": ["bin"], "...": "{...}" }, "...": "{...}" }, { "features": [], "fresh": $FRESH, "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.5.0", "reason": "compiler-artifact", "target": { "kind": ["bin"], "...": "{...}" }, "...": "{...}" }, { "reason": "build-finished", "success": true }, "{...}" ] "# .replace("$FRESH", fresh) .is_json() .against_jsonlines() .unordered() }; // Use `jobs=1` to ensure that the order of messages is consistent. p.cargo("build -v --message-format=json --jobs=1") .with_stdout_data(output("false")) .run(); // With fresh build, we should repeat the artifacts, // and replay the cached compiler warnings. p.cargo("build -v --message-format=json --jobs=1") .with_stdout_data(output("true")) .run(); } #[cargo_test] fn wrong_message_format_option() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --message-format XML") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid message format specifier: `xml` "#]]) .run(); } #[cargo_test] fn message_format_json_forward_stderr() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() { let unused = 0; }") .build(); p.cargo("rustc --release --bin foo --message-format JSON") .with_stdout_data( str![[r#" [ { "manifest_path": "[ROOT]/foo/Cargo.toml", "message": "{...}", "package_id": "path+[ROOTURL]/foo#0.5.0", "reason": "compiler-message", "target": { "kind": ["bin"], "...": "{...}" }, "...": "{...}" }, { "features": [], "fresh": false, "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.5.0", "reason": "compiler-artifact", "target": { "kind": ["bin"], "...": "{...}" }, "...": "{...}" }, { "reason": "build-finished", "success": true }, "{...}" ] "#]] .is_json() .against_jsonlines() .unordered(), ) .run(); } #[cargo_test] fn no_warn_about_package_metadata() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [package.metadata] foo = "bar" a = true b = 3 [package.metadata.another] bar = 3 "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn no_warn_about_workspace_metadata() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo"] [workspace.metadata] something = "something_else" x = 1 y = 2 [workspace.metadata.another] bar = 12 "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("foo/src/lib.rs", "") .build(); p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cargo_build_empty_target() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --target") .arg("") .with_status(101) .with_stderr_data(str![[r#" [ERROR] target was empty "#]]) .run(); } #[cargo_test] fn cargo_build_with_unsupported_short_target_flag() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -t") .arg("") .with_stderr_data(str![[r#" [ERROR] unexpected argument '-t' found tip: a similar argument exists: '--target' Usage: cargo[EXE] build [OPTIONS] For more information, try '--help'. "#]]) .with_status(1) .run(); } #[cargo_test] fn build_all_workspace() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } [workspace] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("build --workspace") .with_stderr_data(str![[r#" [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_all_exclude() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["bar", "baz"] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() { break_the_build(); }") .build(); p.cargo("build --workspace --exclude baz") .with_stderr_data( str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn cargo_build_with_unsupported_short_exclude_flag() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["bar", "baz"] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() { break_the_build(); }") .build(); p.cargo("build --workspace -x baz") .with_stderr_data(str![[r#" [ERROR] unexpected argument '-x' found tip: a similar argument exists: '--exclude' Usage: cargo[EXE] build [OPTIONS] For more information, try '--help'. "#]]) .with_status(1) .run(); } #[cargo_test] fn build_all_exclude_not_found() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("build --workspace --exclude baz") .with_stderr_data( str![[r#" [WARNING] excluded package(s) `baz` not found in workspace `[ROOT]/foo` [COMPILING] foo v0.1.0 ([ROOT]/foo) [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn build_all_exclude_glob() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["bar", "baz"] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() { break_the_build(); }") .build(); p.cargo("build --workspace --exclude '*z'") .with_stderr_data( str![[r#" [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn build_all_exclude_glob_not_found() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("build --workspace --exclude '*z'") .with_stderr_data( str![[r#" [WARNING] excluded package pattern(s) `*z` not found in workspace `[ROOT]/foo` [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn build_all_exclude_broken_glob() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("build --workspace --exclude '[*z'") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot build glob pattern from `[*z` Caused by: ... "#]]) .run(); } #[cargo_test] fn build_all_workspace_implicit_examples() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } [workspace] "#, ) .file("src/lib.rs", "") .file("src/bin/a.rs", "fn main() {}") .file("src/bin/b.rs", "fn main() {}") .file("examples/c.rs", "fn main() {}") .file("examples/d.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "") .file("bar/src/bin/e.rs", "fn main() {}") .file("bar/src/bin/f.rs", "fn main() {}") .file("bar/examples/g.rs", "fn main() {}") .file("bar/examples/h.rs", "fn main() {}") .build(); p.cargo("build --workspace --examples") .with_stderr_data(str![[r#" [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(!p.bin("a").is_file()); assert!(!p.bin("b").is_file()); assert!(p.bin("examples/c").is_file()); assert!(p.bin("examples/d").is_file()); assert!(!p.bin("e").is_file()); assert!(!p.bin("f").is_file()); assert!(p.bin("examples/g").is_file()); assert!(p.bin("examples/h").is_file()); } #[cargo_test] fn build_all_virtual_manifest() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); // The order in which bar and baz are built is not guaranteed p.cargo("build --workspace") .with_stderr_data( str![[r#" [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [COMPILING] baz v0.1.0 ([ROOT]/foo/baz) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn build_virtual_manifest_all_implied() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); // The order in which `bar` and `baz` are built is not guaranteed. p.cargo("build") .with_stderr_data( str![[r#" [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [COMPILING] baz v0.1.0 ([ROOT]/foo/baz) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn build_virtual_manifest_one_project() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() { break_the_build(); }") .build(); p.cargo("build -p bar") .with_stderr_data(str![[r#" [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_virtual_manifest_glob() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() { break_the_build(); }") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("build -p '*z'") .with_stderr_data(str![[r#" [COMPILING] baz v0.1.0 ([ROOT]/foo/baz) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_virtual_manifest_glob_not_found() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("build -p bar -p '*z'") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package pattern(s) `*z` not found in workspace `[ROOT]/foo` "#]]) .run(); } #[cargo_test] fn build_virtual_manifest_broken_glob() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("build -p '[*z'") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot build glob pattern from `[*z` Caused by: ... "#]]) .run(); } #[cargo_test] fn build_all_virtual_manifest_implicit_examples() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "") .file("bar/src/bin/a.rs", "fn main() {}") .file("bar/src/bin/b.rs", "fn main() {}") .file("bar/examples/c.rs", "fn main() {}") .file("bar/examples/d.rs", "fn main() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "") .file("baz/src/bin/e.rs", "fn main() {}") .file("baz/src/bin/f.rs", "fn main() {}") .file("baz/examples/g.rs", "fn main() {}") .file("baz/examples/h.rs", "fn main() {}") .build(); // The order in which bar and baz are built is not guaranteed p.cargo("build --workspace --examples") .with_stderr_data( str![[r#" [COMPILING] baz v0.1.0 ([ROOT]/foo/baz) [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); assert!(!p.bin("a").is_file()); assert!(!p.bin("b").is_file()); assert!(p.bin("examples/c").is_file()); assert!(p.bin("examples/d").is_file()); assert!(!p.bin("e").is_file()); assert!(!p.bin("f").is_file()); assert!(p.bin("examples/g").is_file()); assert!(p.bin("examples/h").is_file()); } #[cargo_test] fn build_all_member_dependency_same_name() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" [dependencies] a = "0.1.0" "#, ) .file("a/src/lib.rs", "pub fn a() {}") .build(); Package::new("a", "0.1.0").publish(); p.cargo("build --workspace") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] a v0.1.0 (registry `dummy-registry`) [COMPILING] a v0.1.0 [COMPILING] a v0.1.0 ([ROOT]/foo/a) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn run_proper_binary() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.0" edition = "2015" [[bin]] name = "main" [[bin]] name = "other" "#, ) .file("src/lib.rs", "") .file( "src/bin/main.rs", r#"fn main() { panic!("This should never be run."); }"#, ) .file("src/bin/other.rs", "fn main() {}") .build(); p.cargo("run --bin other").run(); } #[cargo_test] fn run_proper_binary_main_rs() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/lib.rs", "") .file("src/bin/main.rs", "fn main() {}") .build(); p.cargo("run --bin foo").run(); } #[cargo_test] fn run_proper_alias_binary_from_src() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.0" edition = "2015" [[bin]] name = "foo" [[bin]] name = "bar" "#, ) .file("src/foo.rs", r#"fn main() { println!("foo"); }"#) .file("src/bar.rs", r#"fn main() { println!("bar"); }"#) .build(); p.cargo("build --workspace").run(); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" foo "#]]) .run(); p.process(&p.bin("bar")) .with_stdout_data(str![[r#" bar "#]]) .run(); } #[cargo_test] fn run_proper_alias_binary_main_rs() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.0" edition = "2015" [[bin]] name = "foo" [[bin]] name = "bar" "#, ) .file("src/main.rs", r#"fn main() { println!("main"); }"#) .build(); p.cargo("build --workspace").run(); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" main "#]]) .run(); p.process(&p.bin("bar")) .with_stdout_data(str![[r#" main "#]]) .run(); } #[cargo_test] fn run_proper_binary_main_rs_as_foo() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/foo.rs", r#" fn main() { panic!("This should never be run."); }"#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("run --bin foo").run(); } #[cargo_test] fn rustc_wrapper() { let p = project().file("src/lib.rs", "").build(); let wrapper = tools::echo_wrapper(); p.cargo("build -v") .env("RUSTC_WRAPPER", &wrapper) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..]/rustc-echo-wrapper[EXE] rustc --crate-name foo [..]` WRAPPER CALLED: rustc --crate-name foo [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.build_dir().rm_rf(); p.cargo("build -v") .env("RUSTC_WORKSPACE_WRAPPER", &wrapper) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..]/rustc-echo-wrapper[EXE] rustc --crate-name foo [..]` WRAPPER CALLED: rustc --crate-name foo [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } /// Checks what happens when both rust-wrapper and rustc-workspace-wrapper are set. #[cargo_test] fn rustc_wrapper_precendence() { let p = project().file("src/lib.rs", "").build(); let rustc_wrapper = tools::echo_wrapper(); let ws_wrapper = rustc_wrapper.with_file_name("rustc-ws-wrapper"); assert_ne!(rustc_wrapper, ws_wrapper); std::fs::hard_link(&rustc_wrapper, &ws_wrapper).unwrap(); p.cargo("build -v") .env("RUSTC_WRAPPER", &rustc_wrapper) .env("RUSTC_WORKSPACE_WRAPPER", &ws_wrapper) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..]/rustc-echo-wrapper[EXE] [..]/rustc-ws-wrapper rustc --crate-name foo [..]` WRAPPER CALLED: [..]/rustc-ws-wrapper rustc --crate-name foo [..] WRAPPER CALLED: rustc --crate-name foo [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rustc_wrapper_queries() { // Check that the invocations querying rustc for information are done with the wrapper. let p = project().file("src/lib.rs", "").build(); let wrapper = tools::echo_wrapper(); p.cargo("build") .env("CARGO_LOG", "cargo::util::rustc=debug") .env("RUSTC_WRAPPER", &wrapper) .with_stderr_contains("[..]running [..]rustc-echo-wrapper[EXE] rustc -vV[..]") .with_stderr_contains( "[..]running [..]rustc-echo-wrapper[EXE] rustc - --crate-name ___ --print[..]", ) .run(); p.build_dir().rm_rf(); p.cargo("build") .env("CARGO_LOG", "cargo::util::rustc=debug") .env("RUSTC_WORKSPACE_WRAPPER", &wrapper) .with_stderr_contains("[..]running [..]rustc-echo-wrapper[EXE] rustc -vV[..]") .with_stderr_contains( "[..]running [..]rustc-echo-wrapper[EXE] rustc - --crate-name ___ --print[..]", ) .run(); } #[cargo_test] fn rustc_wrapper_relative() { Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); let wrapper = tools::echo_wrapper(); let exe_name = wrapper.file_name().unwrap().to_str().unwrap(); let relative_path = format!("./{}", exe_name); fs::hard_link(&wrapper, p.root().join(exe_name)).unwrap(); p.cargo("build -v") .env("RUSTC_WRAPPER", &relative_path) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [COMPILING] bar v1.0.0 [RUNNING] `[ROOT]/foo/./rustc-echo-wrapper[EXE] rustc --crate-name bar [..]` WRAPPER CALLED: rustc --crate-name bar [..] [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/./rustc-echo-wrapper[EXE] rustc --crate-name foo [..]` WRAPPER CALLED: rustc --crate-name foo [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.build_dir().rm_rf(); p.cargo("build -v") .env("RUSTC_WORKSPACE_WRAPPER", &relative_path) .with_stderr_data(str![[r#" [COMPILING] bar v1.0.0 [RUNNING] `rustc --crate-name bar [..]` [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/./rustc-echo-wrapper[EXE] rustc --crate-name foo [..]` WRAPPER CALLED: rustc --crate-name foo [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.build_dir().rm_rf(); p.change_file( ".cargo/config.toml", &format!( r#" build.rustc-wrapper = "./{}" "#, exe_name ), ); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] bar v1.0.0 [RUNNING] `[ROOT]/foo/./rustc-echo-wrapper[EXE] rustc --crate-name bar [..]` WRAPPER CALLED: rustc --crate-name bar [..] [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/./rustc-echo-wrapper[EXE] rustc --crate-name foo [..]` WRAPPER CALLED: rustc --crate-name foo [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rustc_wrapper_from_path() { let p = project().file("src/lib.rs", "").build(); p.cargo("build -v") .env("RUSTC_WRAPPER", "wannabe_sccache") .with_status(101) .with_stderr_data(str![[r#" [ERROR] could not execute process `wannabe_sccache rustc -vV` (never executed) Caused by: [..] "#]]) .run(); p.build_dir().rm_rf(); p.cargo("build -v") .env("RUSTC_WORKSPACE_WRAPPER", "wannabe_sccache") .with_status(101) .with_stderr_data(str![[r#" [ERROR] could not execute process `wannabe_sccache rustc -vV` (never executed) Caused by: [..] "#]]) .run(); } #[cargo_test] fn cdylib_not_lifted() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.1.0" edition = "2015" [lib] crate-type = ["cdylib"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("build").run(); let files = if cfg!(windows) { if cfg!(target_env = "msvc") { vec!["foo.dll.lib", "foo.dll.exp", "foo.dll"] } else { vec!["libfoo.dll.a", "foo.dll"] } } else if cfg!(target_os = "macos") { vec!["libfoo.dylib"] } else { vec!["libfoo.so"] }; for file in files { println!("checking: {}", file); assert!(p.root().join("target/debug/deps").join(&file).is_file()); } } #[cargo_test] fn cdylib_final_outputs() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo-bar" authors = [] version = "0.1.0" edition = "2015" [lib] crate-type = ["cdylib"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("build").run(); let files = if cfg!(windows) { if cfg!(target_env = "msvc") { vec!["foo_bar.dll.lib", "foo_bar.dll"] } else { vec!["foo_bar.dll", "libfoo_bar.dll.a"] } } else if cfg!(target_os = "macos") { vec!["libfoo_bar.dylib"] } else { vec!["libfoo_bar.so"] }; for file in files { println!("checking: {}", file); assert!(p.root().join("target/debug").join(&file).is_file()); } } #[cargo_test] // NOTE: Windows MSVC and wasm32-unknown-emscripten do not use metadata. Skip them. // See #[cfg(not(all(target_os = "windows", target_env = "msvc")))] fn no_dep_info_collision_when_cdylib_and_bin_coexist() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" [lib] crate-type = ["cdylib"] "#, ) .file("src/main.rs", "fn main() {}") .file("src/lib.rs", "") .build(); p.cargo("build -v") .with_stderr_data( str![[r#" [COMPILING] foo v1.0.0 ([ROOT]/foo) [RUNNING] `rustc [..] --crate-type bin [..] -C metadata=[..]` [RUNNING] `rustc [..] --crate-type cdylib [..] -C metadata=[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); let deps_dir = p.target_debug_dir().join("deps"); assert!(deps_dir.join("foo.d").exists()); let dep_info_count = deps_dir .read_dir() .unwrap() .filter(|e| { let filename = e.as_ref().unwrap().file_name(); let filename = filename.to_str().unwrap(); filename.starts_with("foo") && filename.ends_with(".d") }) .count(); // cdylib -> foo.d // bin -> foo-.d assert_eq!(dep_info_count, 2); } #[cargo_test] fn deterministic_cfg_flags() { // This bug is non-deterministic. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] build = "build.rs" [features] default = ["f_a", "f_b", "f_c", "f_d"] f_a = [] f_b = [] f_c = [] f_d = [] "#, ) .file( "build.rs", r#" fn main() { println!("cargo::rustc-cfg=cfg_a"); println!("cargo::rustc-cfg=cfg_b"); println!("cargo::rustc-cfg=cfg_c"); println!("cargo::rustc-cfg=cfg_d"); println!("cargo::rustc-cfg=cfg_e"); } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..] --cfg[..]default[..]--cfg[..]f_a[..]--cfg[..]f_b[..] --cfg[..]f_c[..]--cfg[..]f_d[..] --cfg cfg_a --cfg cfg_b --cfg cfg_c --cfg cfg_d --cfg cfg_e` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn explicit_bins_without_paths() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [[bin]] name = "foo" [[bin]] name = "bar" "#, ) .file("src/lib.rs", "") .file("src/main.rs", "fn main() {}") .file("src/bin/bar.rs", "fn main() {}") .build(); p.cargo("build").run(); } #[cargo_test] fn no_bin_in_src_with_lib() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/lib.rs", "") .file("src/foo.rs", "fn main() {}") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: can't find `foo` bin at `src/bin/foo.rs` or `src/bin/foo/main.rs`. Please specify bin.path if you want to use a non-default path. "#]]) .run(); } #[cargo_test] fn inferred_bins() { let p = project() .file("src/main.rs", "fn main() {}") .file("src/bin/bar.rs", "fn main() {}") .file("src/bin/baz/main.rs", "fn main() {}") .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); assert!(p.bin("bar").is_file()); assert!(p.bin("baz").is_file()); } #[cargo_test] fn inferred_bins_duplicate_name() { // this should fail, because we have two binaries with the same name let p = project() .file("src/main.rs", "fn main() {}") .file("src/bin/bar.rs", "fn main() {}") .file("src/bin/bar/main.rs", "fn main() {}") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: found duplicate binary name bar, but all binary targets must have a unique name "#]]) .run(); } #[cargo_test] fn inferred_bin_path() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [[bin]] name = "bar" # Note, no `path` key! "#, ) .file("src/bin/bar/main.rs", "fn main() {}") .build(); p.cargo("build").run(); assert!(p.bin("bar").is_file()); } #[cargo_test] fn inferred_examples() { let p = project() .file("src/lib.rs", "fn main() {}") .file("examples/bar.rs", "fn main() {}") .file("examples/baz/main.rs", "fn main() {}") .build(); p.cargo("build --examples").run(); assert!(p.bin("examples/bar").is_file()); assert!(p.bin("examples/baz").is_file()); } #[cargo_test] fn inferred_tests() { let p = project() .file("src/lib.rs", "fn main() {}") .file("tests/bar.rs", "fn main() {}") .file("tests/baz/main.rs", "fn main() {}") .build(); p.cargo("test --test=bar --test=baz").run(); } #[cargo_test] fn inferred_benchmarks() { let p = project() .file("src/lib.rs", "fn main() {}") .file("benches/bar.rs", "fn main() {}") .file("benches/baz/main.rs", "fn main() {}") .build(); p.cargo("bench --bench=bar --bench=baz").run(); } #[cargo_test] fn no_infer_dirs() { let p = project() .file("src/lib.rs", "fn main() {}") .file("examples/dir.rs/dummy", "") .file("benches/dir.rs/dummy", "") .file("tests/dir.rs/dummy", "") .build(); p.cargo("build --examples --benches --tests").run(); // should not fail with "is a directory" } #[cargo_test] fn target_edition() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [lib] edition = "2018" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]--edition=2018 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn target_edition_override() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2018" [lib] edition = "2015" "#, ) .file( "src/lib.rs", " pub fn async() {} pub fn try() {} pub fn await() {} ", ) .build(); p.cargo("build -v").run(); } #[cargo_test] fn same_metadata_different_directory() { // A top-level crate built in two different workspaces should have the // same metadata hash. let p = project() .at("foo1") .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); let output = t!(String::from_utf8(p.cargo("build -v").run().stderr,)); let metadata = output .split_whitespace() .find(|arg| arg.starts_with("metadata=")) .unwrap(); let p = project() .at("foo2") .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("build -v") .with_stderr_data(format!("...\n[..]{metadata}[..]\n...")) .run(); } #[cargo_test] fn building_a_dependent_crate_without_bin_should_fail() { Package::new("testless", "0.1.0") .file( "Cargo.toml", r#" [package] name = "testless" version = "0.1.0" edition = "2015" [[bin]] name = "a_bin" "#, ) .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] testless = "0.1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] testless v0.1.0 (registry `dummy-registry`) [ERROR] failed to download replaced source registry `crates-io` Caused by: failed to parse manifest at `[ROOT]/home/.cargo/registry/src/-[HASH]/testless-0.1.0/Cargo.toml` Caused by: can't find `a_bin` bin at `src/bin/a_bin.rs` or `src/bin/a_bin/main.rs`. Please specify bin.path if you want to use a non-default path. "#]]) .run(); } #[cargo_test] #[cfg(any(target_os = "macos", target_os = "ios"))] fn uplift_dsym_of_bin_on_mac() { let p = project() .file("src/main.rs", "fn main() { panic!(); }") .file("src/bin/b.rs", "fn main() { panic!(); }") .file("examples/c.rs", "fn main() { panic!(); }") .file("tests/d.rs", "fn main() { panic!(); }") .build(); p.cargo("build --bins --examples --tests") .enable_mac_dsym() .run(); assert!(p.target_debug_dir().join("foo.dSYM").is_dir()); assert!(p.target_debug_dir().join("b.dSYM").is_dir()); assert!(p.target_debug_dir().join("b.dSYM").is_symlink()); assert!(p.target_debug_dir().join("examples/c.dSYM").is_dir()); assert!(!p.target_debug_dir().join("c.dSYM").exists()); assert!(!p.target_debug_dir().join("d.dSYM").exists()); } #[cargo_test] #[cfg(any(target_os = "macos", target_os = "ios"))] fn uplift_dsym_of_bin_on_mac_when_broken_link_exists() { let p = project() .file("src/main.rs", "fn main() { panic!(); }") .build(); let dsym = p.target_debug_dir().join("foo.dSYM"); p.cargo("build").enable_mac_dsym().run(); assert!(dsym.is_dir()); // Simulate the situation where the underlying dSYM bundle goes missing // but the uplifted symlink to it remains. This would previously cause // builds to permanently fail until the bad symlink was manually removed. dsym.rm_rf(); p.symlink( p.target_debug_dir() .join("deps") .join("foo-baaaaaadbaaaaaad.dSYM"), &dsym, ); assert!(dsym.is_symlink()); assert!(!dsym.exists()); p.cargo("build").enable_mac_dsym().run(); assert!(dsym.is_dir()); } #[cargo_test] #[cfg(all(target_os = "windows", target_env = "msvc"))] fn uplift_pdb_of_bin_on_windows() { let p = project() .file("src/main.rs", "fn main() { panic!(); }") .file("src/bin/b.rs", "fn main() { panic!(); }") .file("src/bin/foo-bar.rs", "fn main() { panic!(); }") .file("examples/c.rs", "fn main() { panic!(); }") .file("tests/d.rs", "fn main() { panic!(); }") .build(); p.cargo("build --bins --examples --tests").run(); assert!(p.target_debug_dir().join("foo.pdb").is_file()); assert!(p.target_debug_dir().join("b.pdb").is_file()); assert!(p.target_debug_dir().join("examples/c.pdb").exists()); assert!(p.target_debug_dir().join("foo-bar.exe").is_file()); assert!(p.target_debug_dir().join("foo_bar.pdb").is_file()); assert!(!p.target_debug_dir().join("c.pdb").exists()); assert!(!p.target_debug_dir().join("d.pdb").exists()); } #[cargo_test] #[cfg(target_os = "linux")] fn uplift_dwp_of_bin_on_linux() { let p = project() .file("src/main.rs", "fn main() { panic!(); }") .file("src/bin/b.rs", "fn main() { panic!(); }") .file("src/bin/foo-bar.rs", "fn main() { panic!(); }") .file("examples/c.rs", "fn main() { panic!(); }") .file("tests/d.rs", "fn main() { panic!(); }") .build(); p.cargo("build --bins --examples --tests") .enable_split_debuginfo_packed() .run(); assert!(p.target_debug_dir().join("foo.dwp").is_file()); assert!(p.target_debug_dir().join("b.dwp").is_file()); assert!(p.target_debug_dir().join("examples/c.dwp").exists()); assert!(p.target_debug_dir().join("foo-bar").is_file()); assert!(p.target_debug_dir().join("foo-bar.dwp").is_file()); assert!(!p.target_debug_dir().join("c.dwp").exists()); assert!(!p.target_debug_dir().join("d.dwp").exists()); } // Ensure that `cargo build` chooses the correct profile for building // targets based on filters (assuming `--profile` is not specified). #[cargo_test] fn build_filter_infer_profile() { let p = project() .file("src/lib.rs", "") .file("src/main.rs", "fn main() {}") .file("tests/t1.rs", "") .file("benches/b1.rs", "") .file("examples/ex1.rs", "fn main() {}") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..]` [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]link[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]].unordered()) .run(); p.root().join("target").rm_rf(); p.cargo("build -v --test=t1") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..] -C debuginfo=2 [..]` [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]link[..] -C debuginfo=2 [..]` [RUNNING] `rustc --crate-name t1 --edition=2015 tests/t1.rs [..]--emit=[..]link[..] -C debuginfo=2 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]].unordered()) .run(); p.root().join("target").rm_rf(); // Bench uses test profile without `--release`. p.cargo("build -v --bench=b1") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link [..]-C debuginfo=2 [..]` [RUNNING] `rustc --crate-name b1 --edition=2015 benches/b1.rs [..]--emit=[..]link[..] -C embed-bitcode=no -C debuginfo=2 [..]--test [..]` [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]link [..]-C debuginfo=2 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]].unordered()) .run(); } #[cargo_test] fn targets_selected_default() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("build -v") // Binaries. .with_stderr_contains( "[RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin \ --emit=[..]link[..]", ) // Benchmarks. .with_stderr_does_not_contain( "[RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--emit=[..]link \ -C opt-level=3 --test [..]", ) // Unit tests. .with_stderr_does_not_contain( "[RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--emit=[..]link[..]\ -C debuginfo=2 --test [..]", ) .run(); } #[cargo_test] fn targets_selected_all() { let p = project().file("src/main.rs", "fn main() {}").build(); // The first RUNNING is for unit tests // The second RUNNING is for binaries p.cargo("build -v --all-targets") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--emit=[..]link [..]-C debuginfo=2 -[..]-test[..]` [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]link[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]].unordered()) .run(); } #[cargo_test] fn all_targets_no_lib() { let p = project().file("src/main.rs", "fn main() {}").build(); // The first RUNNING is for unit tests // The second RUNNING is for binaries p.cargo("build -v --all-targets") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--emit=[..]link[..] -C debuginfo=2 [..]--test [..]` [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]link[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]].unordered()) .run(); } #[cargo_test] fn no_linkable_target() { // Issue 3169: this is currently not an error as per discussion in PR #4797. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] the_lib = { path = "the_lib" } "#, ) .file("src/main.rs", "fn main() {}") .file( "the_lib/Cargo.toml", r#" [package] name = "the_lib" version = "0.1.0" edition = "2015" [lib] name = "the_lib" crate-type = ["staticlib"] "#, ) .file("the_lib/src/lib.rs", "pub fn foo() {}") .build(); p.cargo("build") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [WARNING] The package `the_lib` provides no linkable target. The compiler might raise an error while compiling `foo`. Consider adding 'dylib' or 'rlib' to key `crate-type` in `the_lib`'s Cargo.toml. This warning might turn into a hard error in the future. [COMPILING] the_lib v0.1.0 ([ROOT]/foo/the_lib) [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn avoid_dev_deps() { Package::new("foo", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dev-dependencies] baz = "1.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] no matching package named `baz` found location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `bar v0.1.0 ([ROOT]/foo)` "#]]) .run(); p.cargo("build -Zavoid-dev-deps") .masquerade_as_nightly_cargo(&["avoid-dev-deps"]) .run(); } #[cargo_test] fn default_cargo_config_jobs() { let p = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [build] jobs = 1 "#, ) .build(); p.cargo("build -v").run(); } #[cargo_test] fn good_cargo_config_jobs() { let p = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [build] jobs = 4 "#, ) .build(); p.cargo("build -v").run(); } #[cargo_test] fn good_jobs() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("build --jobs 1").run(); p.cargo("build --jobs -1").run(); p.cargo("build --jobs default").run(); } #[cargo_test] fn invalid_cargo_config_jobs() { let p = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [build] jobs = 0 "#, ) .build(); p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] jobs may not be 0 "#]]) .run(); } #[cargo_test] fn invalid_jobs() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("build --jobs 0") .with_status(101) .with_stderr_data(str![[r#" [ERROR] jobs may not be 0 "#]]) .run(); p.cargo("build --jobs over9000") .with_status(101) .with_stderr_data(str![[r#" [ERROR] could not parse `over9000`. Number of parallel jobs should be `default` or a number. "#]]) .run(); } #[cargo_test] fn target_filters_workspace() { let ws = project() .at("ws") .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file("a/Cargo.toml", &basic_lib_manifest("a")) .file("a/src/lib.rs", "") .file("a/examples/ex1.rs", "fn main() {}") .file("b/Cargo.toml", &basic_bin_manifest("b")) .file("b/src/lib.rs", "") .file("b/src/main.rs", "fn main() {}") .build(); ws.cargo("build -v --example ex") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no example target named `ex` Did you mean `ex1`? "#]]) .run(); ws.cargo("build -v --example 'ex??'") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no example target matches pattern `ex??` Did you mean `ex1`? "#]]) .run(); ws.cargo("build -v --lib") .with_stderr_data( str![[r#" [COMPILING] a v0.5.0 ([ROOT]/ws/a) [COMPILING] b v0.5.0 ([ROOT]/ws/b) [RUNNING] `rustc [..]a/src/lib.rs[..]` [RUNNING] `rustc [..]b/src/lib.rs[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); ws.cargo("build -v --example ex1") .with_stderr_data(str![[r#" [COMPILING] a v0.5.0 ([ROOT]/ws/a) [RUNNING] `rustc [..]a/examples/ex1.rs[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn target_filters_workspace_not_found() { let ws = project() .at("ws") .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file("a/Cargo.toml", &basic_bin_manifest("a")) .file("a/src/main.rs", "fn main() {}") .file("b/Cargo.toml", &basic_bin_manifest("b")) .file("b/src/main.rs", "fn main() {}") .build(); ws.cargo("build -v --lib") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no library targets found in packages: a, b "#]]) .run(); } #[cfg(unix)] #[cargo_test] fn signal_display() { // Cause the compiler to crash with a signal. let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] pm = { path = "pm" } "#, ) .file( "src/lib.rs", r#" #[macro_use] extern crate pm; #[derive(Foo)] pub struct S; "#, ) .file( "pm/Cargo.toml", r#" [package] name = "pm" version = "0.1.0" edition = "2015" [lib] proc-macro = true "#, ) .file( "pm/src/lib.rs", r#" extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro_derive(Foo)] pub fn derive(_input: TokenStream) -> TokenStream { std::process::abort() } "#, ) .build(); foo.cargo("build") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] pm v0.1.0 ([ROOT]/foo/pm) [COMPILING] foo v0.1.0 ([ROOT]/foo) [ERROR] could not compile `foo` (lib) Caused by: process didn't exit successfully: `rustc [..]` (signal: 6, SIGABRT: process abort signal) "#]]) .with_status(101) .run(); } #[cargo_test] fn tricky_pipelining() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } "#, ) .file("src/lib.rs", "extern crate bar;") .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file("bar/src/lib.rs", "") .build(); foo.cargo("build -p bar").run(); foo.cargo("build -p foo").run(); } #[cargo_test] fn pipelining_works() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } "#, ) .file("src/lib.rs", "extern crate bar;") .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file("bar/src/lib.rs", "") .build(); foo.cargo("build") .with_stdout_data(str![]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn pipelining_big_graph() { // Create a crate graph of the form {a,b}{0..29}, where {a,b}(n) depend on {a,b}(n+1) // Then have `foo`, a binary crate, depend on the whole thing. let mut project = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] a1 = { path = "a1" } b1 = { path = "b1" } "#, ) .file("src/main.rs", "fn main(){}"); for n in 0..30 { for x in &["a", "b"] { project = project .file( &format!("{x}{n}/Cargo.toml", x = x, n = n), &format!( r#" [package] name = "{x}{n}" version = "0.1.0" edition = "2015" [dependencies] a{np1} = {{ path = "../a{np1}" }} b{np1} = {{ path = "../b{np1}" }} "#, x = x, n = n, np1 = n + 1 ), ) .file(&format!("{x}{n}/src/lib.rs", x = x, n = n), ""); } } let foo = project .file("a30/Cargo.toml", &basic_lib_manifest("a30")) .file( "a30/src/lib.rs", r#"compile_error!("don't actually build me");"#, ) .file("b30/Cargo.toml", &basic_lib_manifest("b30")) .file("b30/src/lib.rs", "") .build(); foo.cargo("build -p foo") .with_status(101) .with_stderr_data( str![[r#" [COMPILING] a30 v0.5.0 ([ROOT]/foo/a30) [ERROR] don't actually build me ... [ERROR] could not compile `a30` (lib) due to 1 previous error ... "#]] .unordered(), ) .run(); } #[cargo_test] fn forward_rustc_output() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = '2018' [dependencies] bar = { path = "bar" } "#, ) .file("src/lib.rs", "bar::foo!();") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [lib] proc-macro = true "#, ) .file( "bar/src/lib.rs", r#" extern crate proc_macro; use proc_macro::*; #[proc_macro] pub fn foo(input: TokenStream) -> TokenStream { println!("a"); println!("b"); println!("{{}}"); eprintln!("c"); eprintln!("d"); eprintln!("{{a"); // "malformed json" input } "#, ) .build(); foo.cargo("build") .with_stdout_data(str![[r#" a b {} "#]]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [COMPILING] foo v0.1.0 ([ROOT]/foo) c d {a [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_lib_only() { let p = project() .file("src/main.rs", "fn main() {}") .file("src/lib.rs", r#" "#) .build(); p.cargo("build --lib -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..] -L dependency=[ROOT]/foo/target/debug/deps` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_with_no_lib() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --lib") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no library targets found in package `foo` "#]]) .run(); } #[cargo_test] fn build_with_relative_cargo_home_path() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = ["wycats@example.com"] [dependencies] "test-dependency" = { path = "src/test_dependency" } "#, ) .file("src/main.rs", "fn main() {}") .file("src/test_dependency/src/lib.rs", r#" "#) .file( "src/test_dependency/Cargo.toml", &basic_manifest("test-dependency", "0.0.1"), ) .build(); p.cargo("build").env("CARGO_HOME", "./cargo_home/").run(); } #[cargo_test] fn user_specific_cfgs_are_filtered_out() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", r#"fn main() {}"#) .file( "build.rs", r#" fn main() { assert!(std::env::var_os("CARGO_CFG_PROC_MACRO").is_none()); assert!(std::env::var_os("CARGO_CFG_DEBUG_ASSERTIONS").is_none()); } "#, ) .build(); p.cargo("rustc -- --cfg debug_assertions --cfg proc_macro -Aunknown_lints -Aexplicit_builtin_cfgs_in_flags") .run(); p.process(&p.bin("foo")).run(); } #[cargo_test] fn close_output() { // What happens when stdout or stderr is closed during a build. // Server to know when rustc has spawned. let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap(); let addr = listener.local_addr().unwrap(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [lib] proc-macro = true [[bin]] name = "foobar" "#, ) .file( "src/lib.rs", &r#" use proc_macro::TokenStream; use std::io::Read; #[proc_macro] pub fn repro(_input: TokenStream) -> TokenStream { println!("hello stdout!"); eprintln!("hello stderr!"); // Tell the test we have started. let mut socket = std::net::TcpStream::connect("__ADDR__").unwrap(); // Wait for the test to tell us to start printing. let mut buf = [0]; drop(socket.read_exact(&mut buf)); let use_stderr = std::env::var("__CARGO_REPRO_STDERR").is_ok(); // Emit at least 1MB of data. // Linux pipes can buffer up to 64KB. // This test seems to be sensitive to having other threads // calling fork. My hypothesis is that the stdout/stderr // file descriptors are duplicated into the child process, // and during the short window between fork and exec, the // file descriptor is kept alive long enough for the // build to finish. It's a half-baked theory, but this // seems to prevent the spurious errors in CI. // An alternative solution is to run this test in // a single-threaded environment. for i in 0..100000 { if use_stderr { eprintln!("0123456789{}", i); } else { println!("0123456789{}", i); } } TokenStream::new() } "# .replace("__ADDR__", &addr.to_string()), ) .file( "src/bin/foobar.rs", r#" foo::repro!(); fn main() {} "#, ) .build(); // The `stderr` flag here indicates if this should forcefully close stderr or stdout. let spawn = |stderr: bool| { let mut cmd = p.cargo("build").build_command(); cmd.stdout(Stdio::piped()).stderr(Stdio::piped()); if stderr { cmd.env("__CARGO_REPRO_STDERR", "1"); } let mut child = cmd.spawn().unwrap(); // Wait for proc macro to start. let pm_conn = listener.accept().unwrap().0; // Close stderr or stdout. if stderr { drop(child.stderr.take()); } else { drop(child.stdout.take()); } // Tell the proc-macro to continue; drop(pm_conn); // Read the output from the other channel. let out: &mut dyn Read = if stderr { child.stdout.as_mut().unwrap() } else { child.stderr.as_mut().unwrap() }; let mut result = String::new(); out.read_to_string(&mut result).unwrap(); let status = child.wait().unwrap(); assert!(!status.success()); result }; let stderr = spawn(false); assert_e2e().eq( &stderr, str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) hello stderr! [ERROR] [BROKEN_PIPE] [WARNING] build failed, waiting for other jobs to finish... "#]] .unordered(), ); // Try again with stderr. p.build_dir().rm_rf(); let stdout = spawn(true); assert_eq!(stdout, "hello stdout!\n"); } #[cargo_test] fn close_output_during_drain() { // Test to close the output during the build phase (drain_the_queue). // There was a bug where it would hang. // Server to know when rustc has spawned. let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap(); let addr = listener.local_addr().unwrap(); // Create a wrapper so the test can know when compiling has started. let rustc_wrapper = { let p = project() .at("compiler") .file("Cargo.toml", &basic_manifest("compiler", "1.0.0")) .file( "src/main.rs", &r#" use std::process::Command; use std::env; use std::io::Read; fn main() { // Only wait on the first dependency. if matches!(env::var("CARGO_PKG_NAME").as_deref(), Ok("dep")) { let mut socket = std::net::TcpStream::connect("__ADDR__").unwrap(); // Wait for the test to tell us to start printing. let mut buf = [0]; drop(socket.read_exact(&mut buf)); } let mut cmd = Command::new("rustc"); for arg in env::args_os().skip(1) { cmd.arg(arg); } std::process::exit(cmd.status().unwrap().code().unwrap()); } "# .replace("__ADDR__", &addr.to_string()), ) .build(); p.cargo("build").run(); p.bin("compiler") }; Package::new("dep", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] dep = "1.0" "#, ) .file("src/lib.rs", "") .build(); // Spawn cargo, wait for the first rustc to start, and then close stderr. let mut cmd = process(&cargo_exe()) .arg("check") .cwd(p.root()) .env("RUSTC", rustc_wrapper) .build_command(); cmd.stdout(Stdio::piped()).stderr(Stdio::piped()); let mut child = cmd.spawn().expect("cargo should spawn"); // Wait for the rustc wrapper to start. let rustc_conn = listener.accept().unwrap().0; // Close stderr to force an error. drop(child.stderr.take()); // Tell the wrapper to continue. drop(rustc_conn); match child.wait() { Ok(status) => assert!(!status.success()), Err(e) => panic!("child wait failed: {}", e), } } use cargo_test_support::registry::Dependency; #[cargo_test] fn reduced_reproduction_8249() { // https://github.com/rust-lang/cargo/issues/8249 Package::new("a-src", "0.1.0").links("a").publish(); Package::new("a-src", "0.2.0").links("a").publish(); Package::new("b", "0.1.0") .add_dep(Dependency::new("a-src", "0.1").optional(true)) .publish(); Package::new("b", "0.2.0") .add_dep(Dependency::new("a-src", "0.2").optional(true)) .publish(); Package::new("c", "1.0.0") .add_dep(&Dependency::new("b", "0.1.0")) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] b = { version = "*", features = ["a-src"] } a-src = "*" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); cargo_util::paths::append(&p.root().join("Cargo.toml"), b"c = \"*\"").unwrap(); p.cargo("check").run(); p.cargo("check").run(); } #[cargo_test] fn target_directory_backup_exclusion() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); // Newly created target/ should have CACHEDIR.TAG inside... p.cargo("build").run(); let cachedir_tag = p.build_dir().join("CACHEDIR.TAG"); assert!(cachedir_tag.is_file()); assert!(fs::read_to_string(&cachedir_tag) .unwrap() .starts_with("Signature: 8a477f597d28d172789f06886806bc55")); // ...but if target/ already exists CACHEDIR.TAG should not be created in it. fs::remove_file(&cachedir_tag).unwrap(); p.cargo("build").run(); assert!(!&cachedir_tag.is_file()); } #[cargo_test] fn simple_terminal_width() { let p = project() .file( "src/lib.rs", r#" pub fn foo() { let _: () = 42; } "#, ) .build(); p.cargo("build -v") .env("__CARGO_TEST_TTY_WIDTH_DO_NOT_USE_THIS", "20") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]--diagnostic-width=20[..] error[E0308][..] ... [ERROR] could not compile `foo` (lib) due to 1 previous error Caused by: process didn't exit successfully: `rustc [..]` ([EXIT_STATUS]: 1) "#]]) .run(); p.cargo("doc -v") .env("__CARGO_TEST_TTY_WIDTH_DO_NOT_USE_THIS", "20") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustdoc [..]--diagnostic-width=20[..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); } #[cargo_test] fn build_script_o0_default() { let p = project() .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); p.cargo("build -v --release") .with_stderr_does_not_contain("[..]build_script_build[..]opt-level[..]") .run(); } #[cargo_test] fn build_script_o0_default_even_with_release() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.release] opt-level = 1 "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); p.cargo("build -v --release") .with_stderr_does_not_contain("[..]build_script_build[..]opt-level[..]") .run(); } #[cargo_test] fn primary_package_env_var() { // Test that CARGO_PRIMARY_PACKAGE is enabled only for "foo" and not for any dependency. let is_primary_package = r#" pub fn is_primary_package() -> bool {{ option_env!("CARGO_PRIMARY_PACKAGE").is_some() }} "#; Package::new("qux", "0.1.0") .file("src/lib.rs", is_primary_package) .publish(); let baz = git::new("baz", |project| { project .file("Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("src/lib.rs", is_primary_package) }); let foo = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = {{ path = "bar" }} baz = {{ git = '{}' }} qux = "0.1" "#, baz.url() ), ) .file( "src/lib.rs", &format!( r#" extern crate bar; extern crate baz; extern crate qux; {} #[test] fn verify_primary_package() {{ assert!(!bar::is_primary_package()); assert!(!baz::is_primary_package()); assert!(!qux::is_primary_package()); assert!(is_primary_package()); }} "#, is_primary_package ), ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", is_primary_package) .build(); foo.cargo("test").run(); } #[cargo_test] fn renamed_uplifted_artifact_remains_unmodified_after_rebuild() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.0" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build").run(); let bin = p.bin("foo"); let renamed_bin = p.bin("foo-renamed"); fs::rename(&bin, &renamed_bin).unwrap(); p.change_file("src/main.rs", "fn main() { eprintln!(\"hello, world\"); }"); p.cargo("build").run(); let not_the_same = !same_file::is_same_file(bin, renamed_bin).unwrap(); assert!(not_the_same, "renamed uplifted artifact must be unmodified"); } cargo-0.86.0/tests/testsuite/build_plan.rs000064400000000000000000000124551046102023000166730ustar 00000000000000//! Tests for --build-plan feature. use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{basic_bin_manifest, basic_manifest, main_file, project, str}; #[cargo_test] fn cargo_build_plan_simple() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("build --build-plan -Zunstable-options") .masquerade_as_nightly_cargo(&["build-plan"]) .with_stdout_data( str![[r#" { "inputs": [ "[ROOT]/foo/Cargo.toml" ], "invocations": [ { "args": "{...}", "compile_mode": "build", "cwd": "[ROOT]/foo", "deps": [], "env": "{...}", "kind": null, "links": "{...}", "outputs": "{...}", "package_name": "foo", "package_version": "0.5.0", "program": "rustc", "target_kind": [ "bin" ] } ] } "#]] .is_json(), ) .run(); assert!(!p.bin("foo").is_file()); } #[cargo_test] fn cargo_build_plan_single_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.5.0" [dependencies] bar = { path = "bar" } "#, ) .file( "src/lib.rs", r#" extern crate bar; pub fn foo() { bar::bar(); } #[test] fn test() { foo(); } "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("build --build-plan -Zunstable-options") .masquerade_as_nightly_cargo(&["build-plan"]) .with_stdout_data( str![[r#" { "inputs": [ "[ROOT]/foo/Cargo.toml", "[ROOT]/foo/bar/Cargo.toml" ], "invocations": [ { "args": "{...}", "compile_mode": "build", "cwd": "[ROOT]/foo", "deps": [], "env": "{...}", "kind": null, "links": {}, "outputs": [ "[ROOT]/foo/target/debug/deps/libbar-[HASH].rlib", "[ROOT]/foo/target/debug/deps/libbar-[HASH].rmeta" ], "package_name": "bar", "package_version": "0.0.1", "program": "rustc", "target_kind": [ "lib" ] }, { "args": "{...}", "compile_mode": "build", "cwd": "[ROOT]/foo", "deps": [ 0 ], "env": "{...}", "kind": null, "links": "{...}", "outputs": [ "[ROOT]/foo/target/debug/deps/libfoo-[HASH].rlib", "[ROOT]/foo/target/debug/deps/libfoo-[HASH].rmeta" ], "package_name": "foo", "package_version": "0.5.0", "program": "rustc", "target_kind": [ "lib" ] } ] } "#]] .is_json(), ) .run(); } #[cargo_test] fn cargo_build_plan_build_script() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" authors = ["wycats@example.com"] build = "build.rs" "#, ) .file("src/main.rs", r#"fn main() {}"#) .file("build.rs", r#"fn main() {}"#) .build(); p.cargo("build --build-plan -Zunstable-options") .masquerade_as_nightly_cargo(&["build-plan"]) .with_stdout_data( str![[r#" { "inputs": [ "[ROOT]/foo/Cargo.toml" ], "invocations": [ { "args": "{...}", "compile_mode": "build", "cwd": "[ROOT]/foo", "deps": [], "env": "{...}", "kind": null, "links": "{...}", "outputs": "{...}", "package_name": "foo", "package_version": "0.5.0", "program": "rustc", "target_kind": [ "custom-build" ] }, { "args": "{...}", "compile_mode": "run-custom-build", "cwd": "[ROOT]/foo", "deps": [ 0 ], "env": "{...}", "kind": null, "links": {}, "outputs": [], "package_name": "foo", "package_version": "0.5.0", "program": "[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build", "target_kind": [ "custom-build" ] }, { "args": "{...}", "compile_mode": "build", "cwd": "[ROOT]/foo", "deps": [ 1 ], "env": "{...}", "kind": null, "links": "{...}", "outputs": "{...}", "package_name": "foo", "package_version": "0.5.0", "program": "rustc", "target_kind": [ "bin" ] } ] } "#]] .is_json(), ) .run(); } #[cargo_test] fn build_plan_with_dev_dep() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" authors = [] [dev-dependencies] bar = "*" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build --build-plan -Zunstable-options") .masquerade_as_nightly_cargo(&["build-plan"]) .run(); } cargo-0.86.0/tests/testsuite/build_script.rs000064400000000000000000005024041046102023000172430ustar 00000000000000//! Tests for build.rs scripts. use std::env; use std::fs; use std::io; use std::thread; use cargo_test_support::compare::assert_e2e; use cargo_test_support::paths::cargo_home; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::tools; use cargo_test_support::{ basic_manifest, cargo_exe, cross_compile, is_coarse_mtime, project, project_in, }; use cargo_test_support::{git, rustc_host, sleep_ms, slow_cpu_multiplier, symlink_supported}; use cargo_util::paths::{self, remove_dir_all}; #[cargo_test] fn custom_build_script_failed() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] build = "build.rs" "#, ) .file("src/main.rs", "fn main() {}") .file("build.rs", "fn main() { std::process::exit(101); }") .build(); p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [ERROR] failed to run custom build command for `foo v0.5.0 ([ROOT]/foo)` Caused by: process didn't exit successfully: `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` ([EXIT_STATUS]: 101) "#]]) .run(); } #[cargo_test] fn custom_build_script_failed_backtraces_message() { // In this situation (no dependency sharing), debuginfo is turned off in // `dev.build-override`. However, if an error occurs running e.g. a build // script, and backtraces are opted into: a message explaining how to // improve backtraces is also displayed. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] build = "build.rs" "#, ) .file("src/main.rs", "fn main() {}") .file("build.rs", "fn main() { std::process::exit(101); }") .build(); p.cargo("build -v") .env("RUST_BACKTRACE", "1") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [ERROR] failed to run custom build command for `foo v0.5.0 ([ROOT]/foo)` [NOTE] To improve backtraces for build dependencies, set the CARGO_PROFILE_DEV_BUILD_OVERRIDE_DEBUG=true environment variable to enable debug information generation. Caused by: process didn't exit successfully: `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` ([EXIT_STATUS]: 101) "#]]) .run(); p.cargo("check -v") .env("RUST_BACKTRACE", "1") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [ERROR] failed to run custom build command for `foo v0.5.0 ([ROOT]/foo)` [NOTE] To improve backtraces for build dependencies, set the CARGO_PROFILE_DEV_BUILD_OVERRIDE_DEBUG=true environment variable to enable debug information generation. Caused by: process didn't exit successfully: `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` ([EXIT_STATUS]: 101) "#]]) .run(); } #[cargo_test] fn custom_build_script_failed_backtraces_message_with_debuginfo() { // This is the same test as `custom_build_script_failed_backtraces_message` above, this time // ensuring that the message dedicated to improving backtraces by requesting debuginfo is not // shown when debuginfo is already turned on. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] build = "build.rs" "#, ) .file("src/main.rs", "fn main() {}") .file("build.rs", "fn main() { std::process::exit(101); }") .build(); p.cargo("build -v") .env("RUST_BACKTRACE", "1") .env("CARGO_PROFILE_DEV_BUILD_OVERRIDE_DEBUG", "true") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [ERROR] failed to run custom build command for `foo v0.5.0 ([ROOT]/foo)` Caused by: process didn't exit successfully: `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` ([EXIT_STATUS]: 101) "#]]) .run(); } #[cargo_test] fn custom_build_env_vars() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [features] bar_feat = ["bar/foo", "bar/other-feature"] [dependencies.bar] path = "bar" "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] build = "build.rs" [features] foo = [] other-feature = [] "#, ) .file("bar/src/lib.rs", "pub fn hello() {}"); let cargo = cargo_exe().canonicalize().unwrap(); let cargo = cargo.to_str().unwrap(); let rustc = paths::resolve_executable("rustc".as_ref()) .unwrap() .canonicalize() .unwrap(); let rustc = rustc.to_str().unwrap(); let file_content = format!( r##" use std::env; use std::path::Path; fn main() {{ let _target = env::var("TARGET").unwrap(); let _ncpus = env::var("NUM_JOBS").unwrap(); let _dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let opt = env::var("OPT_LEVEL").unwrap(); assert_eq!(opt, "0"); let opt = env::var("PROFILE").unwrap(); assert_eq!(opt, "debug"); let debug = env::var("DEBUG").unwrap(); assert_eq!(debug, "true"); let out = env::var("OUT_DIR").unwrap(); assert!(out.starts_with(r"{0}")); assert!(Path::new(&out).is_dir()); let _host = env::var("HOST").unwrap(); let _feat = env::var("CARGO_FEATURE_FOO").unwrap(); let feat = env::var("CARGO_CFG_FEATURE").unwrap(); assert_eq!(feat, "foo,other-feature"); let cargo = env::var("CARGO").unwrap(); if env::var_os("CHECK_CARGO_IS_RUSTC").is_some() {{ assert_eq!(cargo, r#"{rustc}"#); }} else {{ assert_eq!(cargo, r#"{cargo}"#); }} let rustc = env::var("RUSTC").unwrap(); assert_eq!(rustc, "rustc"); let rustdoc = env::var("RUSTDOC").unwrap(); assert_eq!(rustdoc, "rustdoc"); assert!(env::var("RUSTC_WRAPPER").is_err()); assert!(env::var("RUSTC_WORKSPACE_WRAPPER").is_err()); assert!(env::var("RUSTC_LINKER").is_err()); assert!(env::var("RUSTFLAGS").is_err()); let rustflags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap(); assert_eq!(rustflags, ""); }} "##, p.root() .join("target") .join("debug") .join("build") .display(), ); let p = p.file("bar/build.rs", &file_content).build(); p.cargo("build --features bar_feat").run(); p.cargo("build --features bar_feat") // we use rustc since $CARGO is only used if it points to a path that exists .env("CHECK_CARGO_IS_RUSTC", "1") .env(cargo::CARGO_ENV, rustc) .run(); } #[cargo_test] fn custom_build_env_var_rustflags() { let rustflags = "--cfg=special"; let rustflags_alt = "--cfg=notspecial"; let p = project() .file( ".cargo/config.toml", &format!( r#" [build] rustflags = ["{}"] "#, rustflags ), ) .file( "build.rs", &format!( r#" use std::env; fn main() {{ // Static assertion that exactly one of the cfg paths is always taken. assert!(env::var("RUSTFLAGS").is_err()); let x; #[cfg(special)] {{ assert_eq!(env::var("CARGO_ENCODED_RUSTFLAGS").unwrap(), "{}"); x = String::new(); }} #[cfg(notspecial)] {{ assert_eq!(env::var("CARGO_ENCODED_RUSTFLAGS").unwrap(), "{}"); x = String::new(); }} let _ = x; }} "#, rustflags, rustflags_alt, ), ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); // RUSTFLAGS overrides build.rustflags, so --cfg=special shouldn't be passed p.cargo("check").env("RUSTFLAGS", rustflags_alt).run(); } #[cargo_test] fn custom_build_env_var_encoded_rustflags() { // NOTE: We use "-Clink-arg=-B nope" here rather than, say, "-A missing_docs", since for the // latter it won't matter if the whitespace accidentally gets split, as rustc will do the right // thing either way. let p = project() .file( ".cargo/config.toml", r#" [build] rustflags = ["-Clink-arg=-B nope", "--cfg=foo"] "#, ) .file( "build.rs", r#" use std::env; fn main() {{ assert_eq!(env::var("CARGO_ENCODED_RUSTFLAGS").unwrap(), "-Clink-arg=-B nope\x1f--cfg=foo"); }} "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); } #[cargo_test] fn custom_build_env_var_rustc_wrapper() { let wrapper = tools::echo_wrapper(); let p = project() .file( "build.rs", r#" use std::env; fn main() {{ assert_eq!( env::var("RUSTC_WRAPPER").unwrap(), env::var("CARGO_RUSTC_WRAPPER_CHECK").unwrap() ); }} "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .env("CARGO_BUILD_RUSTC_WRAPPER", &wrapper) .env("CARGO_RUSTC_WRAPPER_CHECK", &wrapper) .run(); } #[cargo_test] fn custom_build_env_var_rustc_workspace_wrapper() { let wrapper = tools::echo_wrapper(); // Workspace wrapper should be set for any crate we're operating directly on. let p = project() .file( "build.rs", r#" use std::env; fn main() {{ assert_eq!( env::var("RUSTC_WORKSPACE_WRAPPER").unwrap(), env::var("CARGO_RUSTC_WORKSPACE_WRAPPER_CHECK").unwrap() ); }} "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .env("CARGO_BUILD_RUSTC_WORKSPACE_WRAPPER", &wrapper) .env("CARGO_RUSTC_WORKSPACE_WRAPPER_CHECK", &wrapper) .run(); // But should not be set for a crate from the registry, as then it's not in a workspace. Package::new("bar", "0.1.0") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" links = "a" "#, ) .file( "build.rs", r#" use std::env; fn main() {{ assert!(env::var("RUSTC_WORKSPACE_WRAPPER").is_err()); }} "#, ) .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .env("CARGO_BUILD_RUSTC_WORKSPACE_WRAPPER", &wrapper) .run(); } #[cargo_test] fn custom_build_env_var_rustc_linker() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let p = project() .file( ".cargo/config.toml", &format!( r#" [target.{}] linker = "/path/to/linker" "#, target ), ) .file( "build.rs", r#" use std::env; fn main() { assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/linker")); } "#, ) .file("src/lib.rs", "") .build(); // no crate type set => linker never called => build succeeds if and // only if build.rs succeeds, despite linker binary not existing. p.cargo("build --target").arg(&target).run(); } // Only run this test on linux, since it's difficult to construct // a case suitable for all platforms. // See:https://github.com/rust-lang/cargo/pull/12535#discussion_r1306618264 #[cargo_test] #[cfg(target_os = "linux")] fn custom_build_env_var_rustc_linker_with_target_cfg() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let p = project() .file( ".cargo/config.toml", r#" [target.'cfg(target_pointer_width = "32")'] linker = "/path/to/linker" "#, ) .file( "build.rs", r#" use std::env; fn main() { assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/linker")); } "#, ) .file("src/lib.rs", "") .build(); // no crate type set => linker never called => build succeeds if and // only if build.rs succeeds, despite linker binary not existing. p.cargo("build --target").arg(&target).run(); } #[cargo_test] fn custom_build_env_var_rustc_linker_bad_host_target() { let target = rustc_host(); let p = project() .file( ".cargo/config.toml", &format!( r#" [target.{}] linker = "/path/to/linker" "#, target ), ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "") .build(); // build.rs should fail since host == target when no target is set p.cargo("build --verbose") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin [..]-C linker=[..]/path/to/linker [..]` [ERROR] linker `[..]/path/to/linker` not found ... "#]]) .run(); } #[cargo_test] fn custom_build_env_var_rustc_linker_host_target() { let target = rustc_host(); let p = project() .file( ".cargo/config.toml", &format!( r#" target-applies-to-host = false [target.{}] linker = "/path/to/linker" "#, target ), ) .file( "build.rs", r#" use std::env; fn main() { assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/linker")); } "#, ) .file("src/lib.rs", "") .build(); // no crate type set => linker never called => build succeeds if and // only if build.rs succeeds, despite linker binary not existing. p.cargo("build -Z target-applies-to-host --target") .arg(&target) .masquerade_as_nightly_cargo(&["target-applies-to-host"]) .run(); } #[cargo_test] fn custom_build_env_var_rustc_linker_host_target_env() { let target = rustc_host(); let p = project() .file( ".cargo/config.toml", &format!( r#" [target.{}] linker = "/path/to/linker" "#, target ), ) .file( "build.rs", r#" use std::env; fn main() { assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/linker")); } "#, ) .file("src/lib.rs", "") .build(); // no crate type set => linker never called => build succeeds if and // only if build.rs succeeds, despite linker binary not existing. p.cargo("build -Z target-applies-to-host --target") .env("CARGO_TARGET_APPLIES_TO_HOST", "false") .arg(&target) .masquerade_as_nightly_cargo(&["target-applies-to-host"]) .run(); } #[cargo_test] fn custom_build_invalid_host_config_feature_flag() { let target = rustc_host(); let p = project() .file( ".cargo/config.toml", &format!( r#" [target.{}] linker = "/path/to/linker" "#, target ), ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "") .build(); // build.rs should fail due to -Zhost-config being set without -Ztarget-applies-to-host p.cargo("build -Z host-config --target") .arg(&target) .masquerade_as_nightly_cargo(&["host-config"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the -Zhost-config flag requires the -Ztarget-applies-to-host flag to be set "#]]) .run(); } #[cargo_test] fn custom_build_linker_host_target_with_bad_host_config() { let target = rustc_host(); let p = project() .file( ".cargo/config.toml", &format!( r#" [host] linker = "/path/to/host/linker" [target.{}] linker = "/path/to/target/linker" "#, target ), ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "") .build(); // build.rs should fail due to bad host linker being set p.cargo("build -Z target-applies-to-host -Z host-config --verbose --target") .arg(&target) .masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"]) .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin [..]-C linker=[..]/path/to/host/linker [..]` [ERROR] linker `[..]/path/to/host/linker` not found ... "#]]) .run(); } #[cargo_test] fn custom_build_linker_bad_host() { let target = rustc_host(); let p = project() .file( ".cargo/config.toml", &format!( r#" [host] linker = "/path/to/host/linker" [target.{}] linker = "/path/to/target/linker" "#, target ), ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "") .build(); // build.rs should fail due to bad host linker being set p.cargo("build -Z target-applies-to-host -Z host-config --verbose --target") .arg(&target) .masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"]) .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin [..]-C linker=[..]/path/to/host/linker [..]` [ERROR] linker `[..]/path/to/host/linker` not found ... "#]]) .run(); } #[cargo_test] fn custom_build_linker_bad_host_with_arch() { let target = rustc_host(); let p = project() .file( ".cargo/config.toml", &format!( r#" [host] linker = "/path/to/host/linker" [host.{}] linker = "/path/to/host/arch/linker" [target.{}] linker = "/path/to/target/linker" "#, target, target ), ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "") .build(); // build.rs should fail due to bad host linker being set p.cargo("build -Z target-applies-to-host -Z host-config --verbose --target") .arg(&target) .masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"]) .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin [..]-C linker=[..]/path/to/host/arch/linker [..]` [ERROR] linker `[..]/path/to/host/arch/linker` not found ... "#]]) .run(); } #[cargo_test] fn custom_build_env_var_rustc_linker_cross_arch_host() { let target = rustc_host(); let cross_target = cross_compile::alternate(); let p = project() .file( ".cargo/config.toml", &format!( r#" [host.{}] linker = "/path/to/host/arch/linker" [target.{}] linker = "/path/to/target/linker" "#, cross_target, target ), ) .file( "build.rs", r#" use std::env; fn main() { assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/target/linker")); } "#, ) .file("src/lib.rs", "") .build(); // build.rs should be built fine since cross target != host target. // assertion should succeed since it's still passed the target linker p.cargo("build -Z target-applies-to-host -Z host-config --verbose --target") .arg(&target) .masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"]) .run(); } #[cargo_test] fn custom_build_linker_bad_cross_arch_host() { let target = rustc_host(); let cross_target = cross_compile::alternate(); let p = project() .file( ".cargo/config.toml", &format!( r#" [host] linker = "/path/to/host/linker" [host.{}] linker = "/path/to/host/arch/linker" [target.{}] linker = "/path/to/target/linker" "#, cross_target, target ), ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "") .build(); // build.rs should fail due to bad host linker being set p.cargo("build -Z target-applies-to-host -Z host-config --verbose --target") .arg(&target) .masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"]) .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin [..] -C linker=[..]/path/to/host/linker [..]` [ERROR] linker `[..]/path/to/host/linker` not found ... "#]]) .run(); } #[cargo_test] fn custom_build_script_wrong_rustc_flags() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] build = "build.rs" "#, ) .file("src/main.rs", "fn main() {}") .file( "build.rs", r#"fn main() { println!("cargo::rustc-flags=-aaa -bbb"); }"#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [ERROR] Only `-l` and `-L` flags are allowed in build script of `foo v0.5.0 ([ROOT]/foo)`: `-aaa -bbb` "#]]) .run(); } #[cargo_test] fn custom_build_script_rustc_flags() { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.foo] path = "foo" "#, ) .file("src/main.rs", "fn main() {}") .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] build = "build.rs" "#, ) .file("foo/src/lib.rs", "") .file( "foo/build.rs", r#" fn main() { println!("cargo::rustc-flags=-l nonexistinglib -L /dummy/path1 -L /dummy/path2"); } "#, ) .build(); p.cargo("build --verbose").with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] foo v0.5.0 ([ROOT]/foo/foo) [RUNNING] `rustc --crate-name build_script_build --edition=2015 foo/build.rs [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo --edition=2015 foo/src/lib.rs [..]-L dependency=[ROOT]/foo/target/debug/deps -L /dummy/path1 -L /dummy/path2 -l nonexistinglib` [COMPILING] bar v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name bar --edition=2015 src/main.rs [..]-L dependency=[ROOT]/foo/target/debug/deps --extern foo=[ROOT]/foo/target/debug/deps/libfoo-[HASH].rlib -L /dummy/path1 -L /dummy/path2` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn custom_build_script_rustc_flags_no_space() { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.foo] path = "foo" "#, ) .file("src/main.rs", "fn main() {}") .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] build = "build.rs" "#, ) .file("foo/src/lib.rs", "") .file( "foo/build.rs", r#" fn main() { println!("cargo::rustc-flags=-lnonexistinglib -L/dummy/path1 -L/dummy/path2"); } "#, ) .build(); p.cargo("build --verbose").with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] foo v0.5.0 ([ROOT]/foo/foo) [RUNNING] `rustc --crate-name build_script_build --edition=2015 foo/build.rs [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo --edition=2015 foo/src/lib.rs [..]-L dependency=[ROOT]/foo/target/debug/deps -L /dummy/path1 -L /dummy/path2 -l nonexistinglib` [COMPILING] bar v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name bar --edition=2015 src/main.rs [..]-L dependency=[ROOT]/foo/target/debug/deps --extern foo=[ROOT]/foo/target/debug/deps/libfoo-[HASH].rlib -L /dummy/path1 -L /dummy/path2` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn links_no_build_cmd() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] links = "a" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: package specifies that it links to `a` but does not have a custom build script "#]]) .run(); } #[cargo_test] fn links_duplicates() { // this tests that the links_duplicates are caught at resolver time let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] links = "a" build = "build.rs" [dependencies.a-sys] path = "a-sys" "#, ) .file("src/lib.rs", "") .file("build.rs", "") .file( "a-sys/Cargo.toml", r#" [package] name = "a-sys" version = "0.5.0" edition = "2015" authors = [] links = "a" build = "build.rs" "#, ) .file("a-sys/src/lib.rs", "") .file("a-sys/build.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to select a version for `a-sys`. ... required by package `foo v0.5.0 ([ROOT]/foo)` versions that meet the requirements `*` are: 0.5.0 the package `a-sys` links to the native library `a`, but it conflicts with a previous package which links to `a` as well: package `foo v0.5.0 ([ROOT]/foo)` Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the `links = "a"` value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links. failed to select a version for `a-sys` which could resolve this conflict "#]]) .run(); } #[cargo_test] fn links_duplicates_old_registry() { // Test old links validator. See `validate_links`. Package::new("bar", "0.1.0") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" links = "a" "#, ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" links = "a" [dependencies] bar = "0.1" "#, ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [ERROR] multiple packages link to native library `a`, but a native library can be linked only once package `bar v0.1.0` ... which satisfies dependency `bar = "^0.1"` (locked to 0.1.0) of package `foo v0.1.0 ([ROOT]/foo)` links to native library `a` package `foo v0.1.0 ([ROOT]/foo)` also links to native library `a` "#]]) .run(); } #[cargo_test] fn links_duplicates_deep_dependency() { // this tests that the links_duplicates are caught at resolver time let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] links = "a" build = "build.rs" [dependencies.a] path = "a" "#, ) .file("src/lib.rs", "") .file("build.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" [dependencies.a-sys] path = "a-sys" "#, ) .file("a/src/lib.rs", "") .file("a/build.rs", "") .file( "a/a-sys/Cargo.toml", r#" [package] name = "a-sys" version = "0.5.0" edition = "2015" authors = [] links = "a" build = "build.rs" "#, ) .file("a/a-sys/src/lib.rs", "") .file("a/a-sys/build.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to select a version for `a-sys`. ... required by package `a v0.5.0 ([ROOT]/foo/a)` ... which satisfies path dependency `a` of package `foo v0.5.0 ([ROOT]/foo)` versions that meet the requirements `*` are: 0.5.0 the package `a-sys` links to the native library `a`, but it conflicts with a previous package which links to `a` as well: package `foo v0.5.0 ([ROOT]/foo)` Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the `links = "a"` value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links. failed to select a version for `a-sys` which could resolve this conflict "#]]) .run(); } #[cargo_test] fn overrides_and_links() { let target = rustc_host(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" [dependencies.a] path = "a" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" use std::env; fn main() { assert_eq!(env::var("DEP_FOO_FOO").ok().expect("FOO missing"), "bar"); assert_eq!(env::var("DEP_FOO_BAR").ok().expect("BAR missing"), "baz"); } "#, ) .file( ".cargo/config.toml", &format!( r#" [target.{}.foo] rustc-flags = "-L foo -L bar" foo = "bar" bar = "baz" "#, target ), ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] links = "foo" build = "build.rs" "#, ) .file("a/src/lib.rs", "") .file("a/build.rs", "not valid rust code") .build(); p.cargo("build -v") .with_stderr_data( str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] a v0.5.0 ([ROOT]/foo/a) [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build [..]` [RUNNING] `rustc --crate-name a [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..] -L foo -L bar` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn unused_overrides() { let target = rustc_host(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .file( ".cargo/config.toml", &format!( r#" [target.{}.foo] rustc-flags = "-L foo -L bar" foo = "bar" bar = "baz" "#, target ), ) .build(); p.cargo("build -v").run(); } #[cargo_test] fn links_passes_env_vars() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" [dependencies.a] path = "a" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" use std::env; fn main() { assert_eq!(env::var("DEP_FOO_FOO").unwrap(), "bar"); assert_eq!(env::var("DEP_FOO_BAR").unwrap(), "baz"); } "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] links = "foo" build = "build.rs" "#, ) .file("a/src/lib.rs", "") .file( "a/build.rs", r#" use std::env; fn main() { let lib = env::var("CARGO_MANIFEST_LINKS").unwrap(); assert_eq!(lib, "foo"); println!("cargo::metadata=foo=bar"); println!("cargo::metadata=bar=baz"); } "#, ) .build(); p.cargo("build -v").run(); } #[cargo_test] fn only_rerun_build_script() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); p.cargo("build -v").run(); p.root().move_into_the_past(); p.change_file("some-new-file", ""); p.root().move_into_the_past(); p.cargo("build -v") .with_stderr_data(str![[r#" [DIRTY] foo v0.5.0 ([ROOT]/foo): the precalculated components changed [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rebuild_continues_to_pass_env_vars() { let a = project() .at("a") .file( "Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] links = "foo" build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" use std::time::Duration; fn main() { println!("cargo::metadata=foo=bar"); println!("cargo::metadata=bar=baz"); std::thread::sleep(Duration::from_millis(500)); } "#, ) .build(); a.root().move_into_the_past(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" [dependencies.a] path = '{}' "#, a.root().display() ), ) .file("src/lib.rs", "") .file( "build.rs", r#" use std::env; fn main() { assert_eq!(env::var("DEP_FOO_FOO").unwrap(), "bar"); assert_eq!(env::var("DEP_FOO_BAR").unwrap(), "baz"); } "#, ) .build(); p.cargo("build -v").run(); p.root().move_into_the_past(); p.change_file("some-new-file", ""); p.root().move_into_the_past(); p.cargo("build -v").run(); } #[cargo_test] fn testing_and_such() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); println!("build"); p.cargo("build -v").run(); p.root().move_into_the_past(); p.change_file("src/lib.rs", ""); p.root().move_into_the_past(); println!("test"); p.cargo("test -vj1") .with_stderr_data(str![[r#" [DIRTY] foo v0.5.0 ([ROOT]/foo): the precalculated components changed [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..]` [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [DOCTEST] foo [RUNNING] `rustdoc [..]--test [..]` "#]]) .with_stdout_data(str![[r#" running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); println!("doc"); p.cargo("doc -v") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustdoc [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); p.change_file("src/main.rs", "fn main() {}"); println!("run"); p.cargo("run") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); } #[cargo_test] fn propagation_of_l_flags() { let target = rustc_host(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies.a] path = "a" "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] links = "bar" build = "build.rs" [dependencies.b] path = "../b" "#, ) .file("a/src/lib.rs", "") .file( "a/build.rs", r#"fn main() { println!("cargo::rustc-flags=-L bar"); }"#, ) .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.5.0" edition = "2015" authors = [] links = "foo" build = "build.rs" "#, ) .file("b/src/lib.rs", "") .file("b/build.rs", "bad file") .file( ".cargo/config.toml", &format!( r#" [target.{}.foo] rustc-flags = "-L foo" "#, target ), ) .build(); p.cargo("build -v -j1") .with_stderr_data(str![[r#" ... [RUNNING] `rustc --crate-name a [..] -L bar -L foo` [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -L bar -L foo` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn propagation_of_l_flags_new() { let target = rustc_host(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies.a] path = "a" "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] links = "bar" build = "build.rs" [dependencies.b] path = "../b" "#, ) .file("a/src/lib.rs", "") .file( "a/build.rs", r#" fn main() { println!("cargo::rustc-link-search=bar"); } "#, ) .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.5.0" edition = "2015" authors = [] links = "foo" build = "build.rs" "#, ) .file("b/src/lib.rs", "") .file("b/build.rs", "bad file") .file( ".cargo/config.toml", &format!( r#" [target.{}.foo] rustc-link-search = ["foo"] "#, target ), ) .build(); p.cargo("build -v -j1") .with_stderr_data(str![[r#" ... [RUNNING] `rustc --crate-name a [..] -L bar -L foo` [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -L bar -L foo` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_deps_simple() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" [build-dependencies.a] path = "a" "#, ) .file("src/lib.rs", "") .file( "build.rs", " #[allow(unused_extern_crates)] extern crate a; fn main() {} ", ) .file("a/Cargo.toml", &basic_manifest("a", "0.5.0")) .file("a/src/lib.rs", "") .build(); p.cargo("build -v").with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] a v0.5.0 ([ROOT]/foo/a) [RUNNING] `rustc --crate-name a [..]` [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build [..] build.rs [..] --extern a=[ROOT]/foo/target/debug/deps/liba-[HASH].rlib` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn build_deps_not_for_normal() { let target = rustc_host(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" [build-dependencies.aaaaa] path = "a" "#, ) .file( "src/lib.rs", "#[allow(unused_extern_crates)] extern crate aaaaa;", ) .file( "build.rs", " #[allow(unused_extern_crates)] extern crate aaaaa; fn main() {} ", ) .file("a/Cargo.toml", &basic_manifest("aaaaa", "0.5.0")) .file("a/src/lib.rs", "") .build(); p.cargo("build -v --target") .arg(&target) .with_status(101) .with_stderr_data( str![[r#" ... error[E0463]: can't find crate for `aaaaa` [ERROR] could not compile `foo` (lib) due to 1 previous error Caused by: process didn't exit successfully: `rustc --crate-name foo[..]` ([EXIT_STATUS]: 1) "#]] .unordered(), ) .run(); } #[cargo_test] fn build_cmd_with_a_build_cmd() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" [build-dependencies.a] path = "a" "#, ) .file("src/lib.rs", "") .file( "build.rs", " #[allow(unused_extern_crates)] extern crate a; fn main() {} ", ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" [build-dependencies.b] path = "../b" "#, ) .file("a/src/lib.rs", "") .file( "a/build.rs", "#[allow(unused_extern_crates)] extern crate b; fn main() {}", ) .file("b/Cargo.toml", &basic_manifest("b", "0.5.0")) .file("b/src/lib.rs", "") .build(); p.cargo("build -v").with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] b v0.5.0 ([ROOT]/foo/b) [RUNNING] `rustc --crate-name b [..]` [COMPILING] a v0.5.0 ([ROOT]/foo/a) [RUNNING] `rustc --crate-name build_script_build [..] a/build.rs [..] --extern b=[ROOT]/foo/target/debug/deps/libb-[HASH].rlib` [RUNNING] `[ROOT]/foo/target/debug/build/a-[HASH]/build-script-build` [RUNNING] `rustc --crate-name a [..]a/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C metadata=[..] --out-dir [ROOT]/foo/target/debug/deps -L dependency=[ROOT]/foo/target/debug/deps` [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin --emit=[..]link[..]-C metadata=[..] --out-dir [ROOT]/foo/target/debug/build/foo-[HASH] -L dependency=[ROOT]/foo/target/debug/deps --extern a=[ROOT]/foo/target/debug/deps/liba-[HASH].rlib` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..]src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C debuginfo=2 [..]-C metadata=[..] --out-dir [ROOT]/foo/target/debug/deps -L dependency=[ROOT]/foo/target/debug/deps` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn out_dir_is_preserved() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" use std::env; use std::fs::File; use std::path::Path; fn main() { let out = env::var("OUT_DIR").unwrap(); File::create(Path::new(&out).join("foo")).unwrap(); } "#, ) .build(); // Make the file p.cargo("build -v").run(); // Change to asserting that it's there p.change_file( "build.rs", r#" use std::env; use std::fs::File; use std::path::Path; fn main() { let out = env::var("OUT_DIR").unwrap(); File::open(&Path::new(&out).join("foo")).unwrap(); } "#, ); p.cargo("build -v") .with_stderr_data(str![[r#" [DIRTY] foo v0.5.0 ([ROOT]/foo): the file `build.rs` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Run a fresh build where file should be preserved p.cargo("build -v") .with_stderr_data(str![[r#" [FRESH] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // One last time to make sure it's still there. p.change_file("foo", ""); p.cargo("build -v") .with_stderr_data(str![[r#" [DIRTY] foo v0.5.0 ([ROOT]/foo): the precalculated components changed [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn output_separate_lines() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::rustc-flags=-L foo"); println!("cargo::rustc-flags=-l static=foo"); } "#, ) .build(); p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..] -L foo -l static=foo` [ERROR] could not find native static library `foo`, perhaps an -L flag is missing? ... "#]]) .run(); } #[cargo_test] fn output_separate_lines_new() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::rustc-link-search=foo"); println!("cargo::rustc-link-lib=static=foo"); println!("cargo::rustc-link-lib=bar"); println!("cargo::rustc-link-search=bar"); } "#, ) .build(); // The order of the arguments passed to rustc is important. p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..] -L foo -L bar -l static=foo -l bar` [ERROR] could not find native static library `foo`, perhaps an -L flag is missing? ... "#]]) .run(); } #[cargo_test] fn code_generation() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "src/main.rs", r#" include!(concat!(env!("OUT_DIR"), "/hello.rs")); fn main() { println!("{}", message()); } "#, ) .file( "build.rs", r#" use std::env; use std::fs; use std::path::PathBuf; fn main() { let dst = PathBuf::from(env::var("OUT_DIR").unwrap()); fs::write(dst.join("hello.rs"), " pub fn message() -> &'static str { \"Hello, World!\" } ") .unwrap(); } "#, ) .build(); p.cargo("run") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .with_stdout_data(str![[r#" Hello, World! "#]]) .run(); p.cargo("test").run(); } #[cargo_test] fn release_with_build_script() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() {} "#, ) .build(); p.cargo("build -v --release").run(); } #[cargo_test] fn build_script_only() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("build.rs", r#"fn main() {}"#) .build(); p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: no targets specified in the manifest either src/lib.rs, src/main.rs, a [lib] section, or [[bin]] section must be present "#]]) .run(); } #[cargo_test] fn shared_dep_with_a_build_script() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" [dependencies.a] path = "a" [build-dependencies.b] path = "b" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("a/build.rs", "fn main() {}") .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.5.0" edition = "2015" authors = [] [dependencies.a] path = "../a" "#, ) .file("b/src/lib.rs", "") .build(); p.cargo("build -v").run(); } #[cargo_test] fn test_a_lib_with_a_build_command() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "src/lib.rs", r#" include!(concat!(env!("OUT_DIR"), "/foo.rs")); /// ``` /// foo::bar(); /// ``` pub fn bar() { assert_eq!(foo(), 1); } "#, ) .file( "build.rs", r#" use std::env; use std::fs; use std::path::PathBuf; fn main() { let out = PathBuf::from(env::var("OUT_DIR").unwrap()); fs::write(out.join("foo.rs"), "fn foo() -> i32 { 1 }").unwrap(); } "#, ) .build(); p.cargo("test").run(); } #[cargo_test] fn test_dev_dep_build_script() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dev-dependencies.a] path = "a" "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("a/build.rs", "fn main() {}") .file("a/src/lib.rs", "") .build(); p.cargo("test").run(); } #[cargo_test] fn build_script_with_dynamic_native_dependency() { let build = project() .at("builder") .file( "Cargo.toml", r#" [package] name = "builder" version = "0.0.1" edition = "2015" authors = [] [lib] name = "builder" crate-type = ["dylib"] "#, ) .file("src/lib.rs", "#[no_mangle] pub extern fn foo() {}") .build(); let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" [build-dependencies.bar] path = "bar" "#, ) .file("build.rs", "extern crate bar; fn main() { bar::bar() }") .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "bar/build.rs", r#" use std::env; use std::fs; use std::path::PathBuf; fn main() { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let root = PathBuf::from(env::var("BUILDER_ROOT").unwrap()); let file = format!("{}builder{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX); let src = root.join(&file); let dst = out_dir.join(&file); fs::copy(src, dst).unwrap(); if cfg!(target_env = "msvc") { fs::copy(root.join("builder.dll.lib"), out_dir.join("builder.dll.lib")).unwrap(); } println!("cargo::rustc-link-search=native={}", out_dir.display()); } "#, ) .file( "bar/src/lib.rs", r#" pub fn bar() { #[cfg_attr(not(target_env = "msvc"), link(name = "builder"))] #[cfg_attr(target_env = "msvc", link(name = "builder.dll"))] extern { fn foo(); } unsafe { foo() } } "#, ) .build(); build .cargo("build -v") .env("CARGO_LOG", "cargo::ops::cargo_rustc") .run(); let root = build.root().join("target").join("debug"); foo.cargo("build -v") .env("BUILDER_ROOT", root) .env("CARGO_LOG", "cargo::ops::cargo_rustc") .run(); } #[cargo_test] fn profile_and_opt_level_set_correctly() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" use std::env; fn main() { assert_eq!(env::var("OPT_LEVEL").unwrap(), "3"); assert_eq!(env::var("PROFILE").unwrap(), "release"); assert_eq!(env::var("DEBUG").unwrap(), "false"); } "#, ) .build(); p.cargo("bench").run(); } #[cargo_test] fn profile_debug_0() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [profile.dev] debug = 0 "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" use std::env; fn main() { assert_eq!(env::var("OPT_LEVEL").unwrap(), "0"); assert_eq!(env::var("PROFILE").unwrap(), "debug"); assert_eq!(env::var("DEBUG").unwrap(), "false"); } "#, ) .build(); p.cargo("build").run(); } #[cargo_test] fn build_script_with_lto() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" [profile.dev] lto = true "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); p.cargo("build").run(); } #[cargo_test] fn test_duplicate_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] build = "build.rs" [dependencies.bar] path = "bar" [build-dependencies.bar] path = "bar" "#, ) .file( "src/main.rs", r#" extern crate bar; fn main() { bar::do_nothing() } "#, ) .file( "build.rs", r#" extern crate bar; fn main() { bar::do_nothing() } "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn do_nothing() {}") .build(); p.cargo("build").run(); } #[cargo_test] fn cfg_feedback() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/main.rs", "#[cfg(foo)] fn main() {}") .file( "build.rs", r#"fn main() { println!("cargo::rustc-cfg=foo"); }"#, ) .build(); p.cargo("build -v").run(); } #[cargo_test] fn cfg_override() { let target = rustc_host(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] links = "a" build = "build.rs" "#, ) .file("src/main.rs", "#[cfg(foo)] fn main() {}") .file("build.rs", "") .file( ".cargo/config.toml", &format!( r#" [target.{}.a] rustc-cfg = ["foo"] "#, target ), ) .build(); p.cargo("build -v").run(); } #[cargo_test] fn cfg_test() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "build.rs", r#"fn main() { println!("cargo::rustc-cfg=foo"); println!("cargo::rustc-check-cfg=cfg(foo)"); }"#, ) .file( "src/lib.rs", r#" /// /// ``` /// extern crate foo; /// /// fn main() { /// foo::foo() /// } /// ``` /// #[cfg(foo)] pub fn foo() {} #[cfg(foo)] #[test] fn test_foo() { foo() } "#, ) .file("tests/test.rs", "#[cfg(foo)] #[test] fn test_bar() {}") .build(); p.cargo("test -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..] --cfg foo[..]` [RUNNING] `rustc --crate-name foo [..] --cfg foo[..]` [RUNNING] `rustc --crate-name test [..] --cfg foo[..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [RUNNING] `[ROOT]/foo/target/debug/deps/test-[HASH][EXE]` [DOCTEST] foo [RUNNING] `rustdoc [..]--cfg foo[..]` "#]]) .with_stdout_data(str![[r#" running 1 test test test_foo ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test test_bar ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test src/lib.rs - foo (line 3) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cfg_doc() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" [dependencies.bar] path = "bar" "#, ) .file( "build.rs", r#"fn main() { println!("cargo::rustc-cfg=foo"); }"#, ) .file("src/lib.rs", "#[cfg(foo)] pub fn foo() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "bar/build.rs", r#"fn main() { println!("cargo::rustc-cfg=bar"); }"#, ) .file("bar/src/lib.rs", "#[cfg(bar)] pub fn bar() {}") .build(); p.cargo("doc").run(); assert!(p.root().join("target/doc").is_dir()); assert!(p.root().join("target/doc/foo/fn.foo.html").is_file()); assert!(p.root().join("target/doc/bar/fn.bar.html").is_file()); } #[cargo_test] fn cfg_override_test() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" links = "a" [lints.rust] unexpected_cfgs = "allow" # bc of override, stable/nightly, tests "#, ) .file("build.rs", "") .file( ".cargo/config.toml", &format!( r#" [target.{}.a] rustc-cfg = ["foo"] "#, rustc_host() ), ) .file( "src/lib.rs", r#" /// /// ``` /// extern crate foo; /// /// fn main() { /// foo::foo() /// } /// ``` /// #[cfg(foo)] pub fn foo() {} #[cfg(foo)] #[test] fn test_foo() { foo() } "#, ) .file("tests/test.rs", "#[cfg(foo)] #[test] fn test_bar() {}") .build(); p.cargo("test -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo[..]` [RUNNING] `rustc --crate-name foo[..]` [RUNNING] `rustc --crate-name test[..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [RUNNING] `[ROOT]/foo/target/debug/deps/test-[HASH][EXE]` [DOCTEST] foo [RUNNING] `rustdoc [..] --cfg foo[..]` "#]]) .with_stdout_data(str![[r#" running 1 test test test_foo ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test test_bar ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test src/lib.rs - foo (line 3) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cfg_override_doc() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" links = "a" [dependencies.bar] path = "bar" "#, ) .file( ".cargo/config.toml", &format!( r#" [target.{target}.a] rustc-cfg = ["foo"] [target.{target}.b] rustc-cfg = ["bar"] "#, target = rustc_host() ), ) .file("build.rs", "") .file("src/lib.rs", "#[cfg(foo)] pub fn foo() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" links = "b" "#, ) .file("bar/build.rs", "") .file("bar/src/lib.rs", "#[cfg(bar)] pub fn bar() {}") .build(); p.cargo("doc").run(); assert!(p.root().join("target/doc").is_dir()); assert!(p.root().join("target/doc/foo/fn.foo.html").is_file()); assert!(p.root().join("target/doc/bar/fn.bar.html").is_file()); } #[cargo_test] fn env_build() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "src/main.rs", r#" const FOO: &'static str = env!("FOO"); fn main() { println!("{}", FOO); } "#, ) .file( "build.rs", r#"fn main() { println!("cargo::rustc-env=FOO=foo"); }"#, ) .build(); p.cargo("build -v").run(); p.cargo("run -v") .with_stdout_data(str![[r#" foo "#]]) .run(); } #[cargo_test] fn env_test() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "build.rs", r#"fn main() { println!("cargo::rustc-env=FOO=foo"); }"#, ) .file( "src/lib.rs", r#"pub const FOO: &'static str = env!("FOO"); "#, ) .file( "tests/test.rs", r#" extern crate foo; #[test] fn test_foo() { assert_eq!("foo", foo::FOO); } "#, ) .build(); p.cargo("test -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build[..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo[..]` [RUNNING] `rustc --crate-name foo[..]` [RUNNING] `rustc --crate-name test[..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [RUNNING] `[ROOT]/foo/target/debug/deps/test-[HASH][EXE]` [DOCTEST] foo [RUNNING] `rustdoc --edition=2015 --crate-type lib --color auto --crate-name foo[..]` "#]]) .with_stdout_data(str![[r#" running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test test_foo ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn env_doc() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "src/main.rs", r#" const FOO: &'static str = env!("FOO"); fn main() {} "#, ) .file( "build.rs", r#"fn main() { println!("cargo::rustc-env=FOO=foo"); }"#, ) .build(); p.cargo("doc -v").run(); } #[cargo_test] fn flags_go_into_tests() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] b = { path = "b" } "#, ) .file("src/lib.rs", "") .file("tests/foo.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = { path = "../a" } "#, ) .file("b/src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("a/src/lib.rs", "") .file( "a/build.rs", r#" fn main() { println!("cargo::rustc-link-search=test"); } "#, ) .build(); p.cargo("test -v --test=foo") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] a v0.5.0 ([ROOT]/foo/a) [RUNNING] `rustc [..] a/build.rs [..]` [RUNNING] `[ROOT]/foo/target/debug/build/a-[HASH]/build-script-build` [RUNNING] `rustc [..] a/src/lib.rs [..] -L test` [COMPILING] b v0.5.0 ([ROOT]/foo/b) [RUNNING] `rustc [..] b/src/lib.rs [..] -L test` [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc [..] src/lib.rs [..] -L test` [RUNNING] `rustc [..] tests/foo.rs [..] -L test` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` "#]]) .with_stdout_data(str![[r#" running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); p.cargo("test -v -pb --lib") .with_stderr_data(str![[r#" [FRESH] a v0.5.0 ([ROOT]/foo/a) [COMPILING] b v0.5.0 ([ROOT]/foo/b) [RUNNING] `rustc --crate-name b [..] -L test` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/b-[HASH][EXE]` "#]]) .with_stdout_data(str![[r#" running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn diamond_passes_args_only_once() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = { path = "a" } b = { path = "b" } "#, ) .file("src/lib.rs", "") .file("tests/foo.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] [dependencies] b = { path = "../b" } c = { path = "../c" } "#, ) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.5.0" edition = "2015" authors = [] [dependencies] c = { path = "../c" } "#, ) .file("b/src/lib.rs", "") .file( "c/Cargo.toml", r#" [package] name = "c" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "c/build.rs", r#" fn main() { println!("cargo::rustc-link-search=native=test"); } "#, ) .file("c/src/lib.rs", "") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [LOCKING] 3 packages to latest compatible versions [COMPILING] c v0.5.0 ([ROOT]/foo/c) [RUNNING] `rustc --crate-name build_script_build [..]` [RUNNING] `[ROOT]/foo/target/debug/build/c-[HASH]/build-script-build` [RUNNING] `rustc --crate-name c [..] -L native=test` [COMPILING] b v0.5.0 ([ROOT]/foo/b) [RUNNING] `rustc --crate-name b [..] -L native=test` [COMPILING] a v0.5.0 ([ROOT]/foo/a) [RUNNING] `rustc --crate-name a [..] -L native=test` [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -L native=test` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn adding_an_override_invalidates() { let target = rustc_host(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] links = "foo" build = "build.rs" "#, ) .file("src/lib.rs", "") .file(".cargo/config.toml", "") .file( "build.rs", r#" fn main() { println!("cargo::rustc-link-search=native=foo"); } "#, ) .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..] -L native=foo` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file( ".cargo/config.toml", &format!( " [target.{}.foo] rustc-link-search = [\"native=bar\"] ", target ), ); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -L native=bar` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn changing_an_override_invalidates() { let target = rustc_host(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] links = "foo" build = "build.rs" "#, ) .file("src/lib.rs", "") .file( ".cargo/config.toml", &format!( " [target.{}.foo] rustc-link-search = [\"native=foo\"] ", target ), ) .file("build.rs", "") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -L native=foo` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file( ".cargo/config.toml", &format!( " [target.{}.foo] rustc-link-search = [\"native=bar\"] ", target ), ); p.cargo("build -v") .with_stderr_data(str![[r#" [DIRTY] foo v0.5.0 ([ROOT]/foo): the precalculated components changed [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -L native=bar` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn fresh_builds_possible_with_link_libs() { // The bug is non-deterministic. Sometimes you can get a fresh build let target = rustc_host(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] links = "nativefoo" build = "build.rs" "#, ) .file("src/lib.rs", "") .file( ".cargo/config.toml", &format!( " [target.{}.nativefoo] rustc-link-lib = [\"a\"] rustc-link-search = [\"./b\"] rustc-flags = \"-l z -L ./\" ", target ), ) .file("build.rs", "") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc [..] src/lib.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -v") .with_stderr_data(str![[r#" [FRESH] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn fresh_builds_possible_with_multiple_metadata_overrides() { // The bug is non-deterministic. Sometimes you can get a fresh build let target = rustc_host(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] links = "foo" build = "build.rs" "#, ) .file("src/lib.rs", "") .file( ".cargo/config.toml", &format!( " [target.{}.foo] a = \"\" b = \"\" c = \"\" d = \"\" e = \"\" ", target ), ) .file("build.rs", "") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc [..] src/lib.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -v") .with_stderr_data(str![[r#" [FRESH] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn generate_good_d_files() { // this is here to stop regression on an issue where build.rs rerun-if-changed paths aren't // made absolute properly, which in turn interacts poorly with the dep-info-basedir setting, // and the dep-info files have other-crate-relative paths spat out in them let p = project() .file( "awoo/Cargo.toml", r#" [package] name = "awoo" version = "0.5.0" edition = "2015" build = "build.rs" "#, ) .file("awoo/src/lib.rs", "") .file( "awoo/build.rs", r#" fn main() { println!("cargo::rerun-if-changed=build.rs"); println!("cargo::rerun-if-changed=barkbarkbark"); } "#, ) .file( "Cargo.toml", r#" [package] name = "meow" version = "0.5.0" edition = "2015" [dependencies] awoo = { path = "awoo" } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v").run(); let dot_d_path = p.bin("meow").with_extension("d"); println!("*meow at* {:?}", dot_d_path); let dot_d = fs::read_to_string(&dot_d_path).unwrap(); println!("*.d file content*: {}", &dot_d); assert_e2e().eq( &dot_d, str![[r#" [ROOT]/foo/target/debug/meow[EXE]: [ROOT]/foo/awoo/barkbarkbark [ROOT]/foo/awoo/build.rs [ROOT]/foo/awoo/src/lib.rs [ROOT]/foo/src/main.rs "#]], ); // paths relative to dependency roots should not be allowed assert!(!dot_d .split_whitespace() .any(|v| v == "barkbarkbark" || v == "build.rs")); p.change_file( ".cargo/config.toml", r#" [build] dep-info-basedir="." "#, ); p.cargo("build -v").run(); let dot_d = fs::read_to_string(&dot_d_path).unwrap(); println!("*.d file content with dep-info-basedir*: {}", &dot_d); assert_e2e().eq( &dot_d, str![[r#" target/debug/meow[EXE]: awoo/barkbarkbark awoo/build.rs awoo/src/lib.rs src/main.rs "#]], ); // paths relative to dependency roots should not be allowed assert!(!dot_d .split_whitespace() .any(|v| v == "barkbarkbark" || v == "build.rs")); } #[cargo_test] fn generate_good_d_files_for_external_tools() { // This tests having a relative paths going out of the // project root in config's dep-info-basedir let p = project_in("rust_things") .file( "awoo/Cargo.toml", r#" [package] name = "awoo" version = "0.5.0" edition = "2015" build = "build.rs" "#, ) .file("awoo/src/lib.rs", "") .file( "awoo/build.rs", r#" fn main() { println!("cargo::rerun-if-changed=build.rs"); println!("cargo::rerun-if-changed=barkbarkbark"); } "#, ) .file( "Cargo.toml", r#" [package] name = "meow" version = "0.5.0" edition = "2015" [dependencies] awoo = { path = "awoo" } "#, ) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [build] dep-info-basedir="../.." "#, ) .build(); p.cargo("build -v").run(); let dot_d_path = p.bin("meow").with_extension("d"); let dot_d = fs::read_to_string(&dot_d_path).unwrap(); println!("*.d file content with dep-info-basedir*: {}", &dot_d); assert_e2e().eq(&dot_d, str![[r#" rust_things/foo/target/debug/meow[EXE]: rust_things/foo/awoo/barkbarkbark rust_things/foo/awoo/build.rs rust_things/foo/awoo/src/lib.rs rust_things/foo/src/main.rs "#]]); } #[cargo_test] fn rebuild_only_on_explicit_paths() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::rerun-if-changed=foo"); println!("cargo::rerun-if-changed=bar"); } "#, ) .build(); p.cargo("build -v").run(); // files don't exist, so should always rerun if they don't exist println!("run without"); p.cargo("build -v") .with_stderr_data(str![[r#" [DIRTY] foo v0.5.0 ([ROOT]/foo): the file `foo` is missing [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc [..] src/lib.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); sleep_ms(1000); p.change_file("foo", ""); p.change_file("bar", ""); sleep_ms(1000); // make sure the to-be-created outfile has a timestamp distinct from the infiles // now the exist, so run once, catch the mtime, then shouldn't run again println!("run with"); p.cargo("build -v") .with_stderr_data(str![[r#" [DIRTY] foo v0.5.0 ([ROOT]/foo): the file `foo` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc [..] src/lib.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); println!("run with2"); p.cargo("build -v") .with_stderr_data(str![[r#" [FRESH] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); sleep_ms(1000); // random other files do not affect freshness println!("run baz"); p.change_file("baz", "// modified"); p.cargo("build -v") .with_stderr_data(str![[r#" [FRESH] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // but changing dependent files does println!("run foo change"); p.change_file("foo", "// modified"); p.cargo("build -v") .with_stderr_data(str![[r#" [DIRTY] foo v0.5.0 ([ROOT]/foo): the file `foo` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc [..] src/lib.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // .. as does deleting a file println!("run bar delete"); fs::remove_file(p.root().join("bar")).unwrap(); p.cargo("build -v") .with_stderr_data(str![[r#" [DIRTY] foo v0.5.0 ([ROOT]/foo): the file `bar` is missing [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc [..] src/lib.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn doctest_receives_build_link_args() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies.a] path = "a" "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] links = "bar" build = "build.rs" "#, ) .file("a/src/lib.rs", "") .file( "a/build.rs", r#" fn main() { println!("cargo::rustc-link-search=native=bar"); } "#, ) .build(); p.cargo("test -v") .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..]--crate-name foo --test [..]-L native=bar[..]` "#]]) .run(); } #[cargo_test] fn please_respect_the_dag() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" [dependencies] a = { path = 'a' } "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::rustc-link-search=native=foo"); } "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] links = "bar" build = "build.rs" "#, ) .file("a/src/lib.rs", "") .file( "a/build.rs", r#" fn main() { println!("cargo::rustc-link-search=native=bar"); } "#, ) .build(); p.cargo("build -v") .with_stderr_data(str![[r#" ... [RUNNING] `rustc --crate-name foo [..] -L native=foo -L native=bar` ... "#]]) .run(); } #[cargo_test] fn non_utf8_output() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "build.rs", r#" use std::io::prelude::*; fn main() { let mut out = std::io::stdout(); // print something that's not utf8 out.write_all(b"\xff\xff\n").unwrap(); // now print some cargo metadata that's utf8 println!("cargo::rustc-cfg=foo"); // now print more non-utf8 out.write_all(b"\xff\xff\n").unwrap(); } "#, ) .file("src/main.rs", "#[cfg(foo)] fn main() {}") .build(); p.cargo("build -v").run(); } #[cargo_test] fn custom_target_dir() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = { path = "a" } "#, ) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [build] target-dir = 'test' "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("a/build.rs", "fn main() {}") .file("a/src/lib.rs", "") .build(); p.cargo("build -v").run(); } #[cargo_test] fn panic_abort_with_build_scripts() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [profile.release] panic = 'abort' [dependencies] a = { path = "a" } "#, ) .file( "src/lib.rs", "#[allow(unused_extern_crates)] extern crate a;", ) .file("build.rs", "fn main() {}") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" [build-dependencies] b = { path = "../b" } "#, ) .file("a/src/lib.rs", "") .file( "a/build.rs", "#[allow(unused_extern_crates)] extern crate b; fn main() {}", ) .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.5.0" edition = "2015" authors = [] "#, ) .file("b/src/lib.rs", "") .build(); p.cargo("build -v --release").run(); p.root().join("target").rm_rf(); p.cargo("test --release -v") .with_stderr_does_not_contain("[..]panic=abort[..]") .run(); } #[cargo_test] fn warnings_emitted() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::warning=foo"); println!("cargo::warning=bar"); } "#, ) .build(); p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [WARNING] foo@0.5.0: foo [WARNING] foo@0.5.0: bar [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn errors_and_warnings_emitted_and_build_failed() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::warning=foo"); println!("cargo::warning=bar"); println!("cargo::error=foo err"); println!("cargo::error=bar err"); } "#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [WARNING] foo@0.5.0: foo [WARNING] foo@0.5.0: bar [ERROR] foo@0.5.0: foo err [ERROR] foo@0.5.0: bar err [ERROR] build script logged errors "#]]) .run(); } #[cargo_test] fn warnings_emitted_from_path_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = { path = "a" } "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("a/src/lib.rs", "") .file( "a/build.rs", r#" fn main() { println!("cargo::warning=foo"); println!("cargo::warning=bar"); } "#, ) .build(); p.cargo("build") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] a v0.5.0 ([ROOT]/foo/a) [WARNING] a@0.5.0: foo [WARNING] a@0.5.0: bar [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn warnings_emitted_when_build_script_panics() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::warning=foo"); println!("cargo::warning=bar"); panic!("our crate panicked"); } "#, ) .build(); p.cargo("build") .with_status(101) .with_stdout_data("") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [WARNING] foo@0.5.0: foo [WARNING] foo@0.5.0: bar [ERROR] failed to run custom build command for `foo v0.5.0 ([ROOT]/foo)` Caused by: process didn't exit successfully: `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` ([EXIT_STATUS]: 101) --- stdout cargo::warning=foo cargo::warning=bar --- stderr ... [..]our crate panicked[..] ... "#]]) .run(); } #[cargo_test] fn warnings_emitted_when_dependency_panics() { Package::new("published", "0.1.0") .file( "build.rs", r#" fn main() { println!("cargo::warning=foo"); println!("cargo::warning=bar"); panic!("dependency panicked"); } "#, ) .file( "Cargo.toml", r#" [package] name = "published" version = "0.1.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] published = "*" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] published v0.1.0 (registry `dummy-registry`) [COMPILING] published v0.1.0 [WARNING] published@0.1.0: foo [WARNING] published@0.1.0: bar [ERROR] failed to run custom build command for `published v0.1.0` Caused by: process didn't exit successfully: `[ROOT]/foo/target/debug/build/published-[HASH]/build-script-build` ([EXIT_STATUS]: 101) --- stdout cargo::warning=foo cargo::warning=bar --- stderr ... [..]dependency panicked[..] ... "#]]) .run(); } #[cargo_test] fn log_messages_emitted_when_dependency_logs_errors() { Package::new("published", "0.1.0") .file( "build.rs", r#" fn main() { println!("cargo::warning=foo"); println!("cargo::warning=bar"); println!("cargo::error=foo err"); println!("cargo::error=bar err"); } "#, ) .file( "Cargo.toml", r#" [package] name = "published" version = "0.1.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] published = "*" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] published v0.1.0 (registry `dummy-registry`) [COMPILING] published v0.1.0 [WARNING] published@0.1.0: foo [WARNING] published@0.1.0: bar [ERROR] published@0.1.0: foo err [ERROR] published@0.1.0: bar err [ERROR] build script logged errors "#]]) .run(); } #[cargo_test] fn warnings_hidden_for_upstream() { Package::new("bar", "0.1.0") .file( "build.rs", r#" fn main() { println!("cargo::warning=foo"); println!("cargo::warning=bar"); } "#, ) .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [COMPILING] bar v0.1.0 [RUNNING] `rustc --crate-name build_script_build [..]` [RUNNING] `[ROOT]/foo/target/debug/build/bar-[HASH]/build-script-build` [RUNNING] `rustc --crate-name bar [..]` [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn warnings_printed_on_vv() { Package::new("bar", "0.1.0") .file( "build.rs", r#" fn main() { println!("cargo::warning=foo"); println!("cargo::warning=bar"); } "#, ) .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -vv") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [COMPILING] bar v0.1.0 [RUNNING] `[..] rustc --crate-name build_script_build [..]` [RUNNING] `[..] [ROOT]/foo/target/debug/build/bar-[HASH]/build-script-build` [WARNING] bar@0.1.0: foo [WARNING] bar@0.1.0: bar [RUNNING] `[..] rustc --crate-name bar [..]` [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn output_shows_on_vv() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" use std::io::prelude::*; fn main() { std::io::stderr().write_all(b"stderr\n").unwrap(); std::io::stdout().write_all(b"stdout\n").unwrap(); } "#, ) .build(); p.cargo("build -vv") .with_stdout_data(str![[r#" [foo 0.5.0] stdout "#]]) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name build_script_build [..]` [RUNNING] `[..] [ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [foo 0.5.0] stderr [RUNNING] `[..] rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn links_with_dots() { let target = rustc_host(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" links = "a.b" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::rustc-link-search=bar") } "#, ) .file( ".cargo/config.toml", &format!( r#" [target.{}.'a.b'] rustc-link-search = ["foo"] "#, target ), ) .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -L foo` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rustc_and_rustdoc_set_correctly() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" use std::env; fn main() { assert_eq!(env::var("RUSTC").unwrap(), "rustc"); assert_eq!(env::var("RUSTDOC").unwrap(), "rustdoc"); } "#, ) .build(); p.cargo("bench").run(); } #[cargo_test] fn cfg_env_vars_available() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" use std::env; fn main() { let fam = env::var("CARGO_CFG_TARGET_FAMILY").unwrap(); if cfg!(unix) { assert_eq!(fam, "unix"); } else { assert_eq!(fam, "windows"); } } "#, ) .build(); p.cargo("bench").run(); } #[cargo_test] fn switch_features_rerun() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" [features] foo = [] "#, ) .file( "src/main.rs", r#" fn main() { println!(include_str!(concat!(env!("OUT_DIR"), "/output"))); } "#, ) .file( "build.rs", r#" use std::env; use std::fs; use std::path::Path; fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); let output = Path::new(&out_dir).join("output"); if env::var_os("CARGO_FEATURE_FOO").is_some() { fs::write(output, "foo").unwrap(); } else { fs::write(output, "bar").unwrap(); } } "#, ) .build(); p.cargo("build -v --features=foo").run(); p.rename_run("foo", "with_foo") .with_stdout_data(str![[r#" foo "#]]) .run(); p.cargo("build -v").run(); p.rename_run("foo", "without_foo") .with_stdout_data(str![[r#" bar "#]]) .run(); p.cargo("build -v --features=foo").run(); p.rename_run("foo", "with_foo2") .with_stdout_data(str![[r#" foo "#]]) .run(); } #[cargo_test] fn assume_build_script_when_build_rs_present() { let p = project() .file( "src/main.rs", r#" fn main() { if ! cfg!(foo) { panic!("the build script was not run"); } } "#, ) .file( "build.rs", r#" fn main() { println!("cargo::rustc-cfg=foo"); } "#, ) .build(); p.cargo("run -v").run(); } #[cargo_test] fn if_build_set_to_false_dont_treat_build_rs_as_build_script() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = false "#, ) .file( "src/main.rs", r#" fn main() { if cfg!(foo) { panic!("the build script was run"); } } "#, ) .file( "build.rs", r#" fn main() { println!("cargo::rustc-cfg=foo"); } "#, ) .build(); p.cargo("run -v").run(); } #[cargo_test] fn deterministic_rustc_dependency_flags() { // This bug is non-deterministic hence the large number of dependencies // in the hopes it will have a much higher chance of triggering it. Package::new("dep1", "0.1.0") .file( "Cargo.toml", r#" [package] name = "dep1" version = "0.1.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "build.rs", r#" fn main() { println!("cargo::rustc-flags=-L native=test1"); } "#, ) .file("src/lib.rs", "") .publish(); Package::new("dep2", "0.1.0") .file( "Cargo.toml", r#" [package] name = "dep2" version = "0.1.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "build.rs", r#" fn main() { println!("cargo::rustc-flags=-L native=test2"); } "#, ) .file("src/lib.rs", "") .publish(); Package::new("dep3", "0.1.0") .file( "Cargo.toml", r#" [package] name = "dep3" version = "0.1.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "build.rs", r#" fn main() { println!("cargo::rustc-flags=-L native=test3"); } "#, ) .file("src/lib.rs", "") .publish(); Package::new("dep4", "0.1.0") .file( "Cargo.toml", r#" [package] name = "dep4" version = "0.1.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "build.rs", r#" fn main() { println!("cargo::rustc-flags=-L native=test4"); } "#, ) .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] dep1 = "*" dep2 = "*" dep3 = "*" dep4 = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v").with_stderr_data(str![[r#" ... [RUNNING] `rustc --crate-name foo [..] -L native=test1 -L native=test2 -L native=test3 -L native=test4` ... "#]]).run(); } #[cargo_test] fn links_duplicates_with_cycle() { // this tests that the links_duplicates are caught at resolver time let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] links = "a" build = "build.rs" [dependencies.a] path = "a" [dev-dependencies] b = { path = "b" } "#, ) .file("src/lib.rs", "") .file("build.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] links = "a" build = "build.rs" "#, ) .file("a/src/lib.rs", "") .file("a/build.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.5.0" edition = "2015" authors = [] [dependencies] foo = { path = ".." } "#, ) .file("b/src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to select a version for `a`. ... required by package `foo v0.5.0 ([ROOT]/foo)` versions that meet the requirements `*` are: 0.5.0 the package `a` links to the native library `a`, but it conflicts with a previous package which links to `a` as well: package `foo v0.5.0 ([ROOT]/foo)` Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the `links = "a"` value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links. failed to select a version for `a` which could resolve this conflict "#]]) .run(); } #[cargo_test] fn rename_with_link_search_path() { _rename_with_link_search_path( false, str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/bar[EXE]` "#]], ); } #[cargo_test] #[cfg_attr( target_os = "macos", ignore = "don't have a cdylib cross target on macos" )] fn rename_with_link_search_path_cross() { if cross_compile::disabled() { return; } _rename_with_link_search_path( true, str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/[ALT_TARGET]/debug/bar[EXE]` "#]], ); } fn _rename_with_link_search_path(cross: bool, expected: impl IntoData) { let target_arg = if cross { format!(" --target={}", cross_compile::alternate()) } else { "".to_string() }; let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [lib] crate-type = ["cdylib"] "#, ) .file( "src/lib.rs", "#[no_mangle] pub extern fn cargo_test_foo() {}", ); let p = p.build(); p.cargo(&format!("build{}", target_arg)).run(); let p2 = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file( "build.rs", r#" use std::env; use std::fs; use std::path::PathBuf; fn main() { // Move the `libfoo.so` from the root of our project into the // build directory. This way Cargo should automatically manage // `LD_LIBRARY_PATH` and such. let root = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); let file = format!("{}foo{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX); let src = root.join(&file); let dst_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let dst = dst_dir.join(&file); fs::copy(&src, &dst).unwrap(); // handle windows, like below drop(fs::copy(root.join("foo.dll.lib"), dst_dir.join("foo.dll.lib"))); println!("cargo::rerun-if-changed=build.rs"); if cfg!(target_env = "msvc") { println!("cargo::rustc-link-lib=foo.dll"); } else { println!("cargo::rustc-link-lib=foo"); } println!("cargo::rustc-link-search=all={}", dst.parent().unwrap().display()); } "#, ) .file( "src/main.rs", r#" extern { #[link_name = "cargo_test_foo"] fn foo(); } fn main() { unsafe { foo(); } } "#, ); let p2 = p2.build(); // Move the output `libfoo.so` into the directory of `p2`, and then delete // the `p` project. On macOS, the `libfoo.dylib` artifact references the // original path in `p` so we want to make sure that it can't find it (hence // the deletion). let root = if cross { p.root() .join("target") .join(cross_compile::alternate()) .join("debug") .join("deps") } else { p.root().join("target").join("debug").join("deps") }; let file = format!("{}foo{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX); let src = root.join(&file); let dst = p2.root().join(&file); fs::copy(&src, &dst).unwrap(); // copy the import library for windows, if it exists drop(fs::copy( &root.join("foo.dll.lib"), p2.root().join("foo.dll.lib"), )); remove_dir_all(p.root()).unwrap(); // Everything should work the first time p2.cargo(&format!("run{}", target_arg)).run(); // Now rename the root directory and rerun `cargo run`. Not only should we // not build anything but we also shouldn't crash. let mut new = p2.root(); new.pop(); new.push("bar2"); // For whatever reason on Windows right after we execute a binary it's very // unlikely that we're able to successfully delete or rename that binary. // It's not really clear why this is the case or if it's a bug in Cargo // holding a handle open too long. In an effort to reduce the flakiness of // this test though we throw this in a loop // // For some more information see #5481 and rust-lang/rust#48775 let mut i = 0; loop { let error = match fs::rename(p2.root(), &new) { Ok(()) => break, Err(e) => e, }; i += 1; if !cfg!(windows) || error.kind() != io::ErrorKind::PermissionDenied || i > 10 { panic!("failed to rename: {}", error); } println!("assuming {} is spurious, waiting to try again", error); thread::sleep(slow_cpu_multiplier(100)); } p2.cargo(&format!("run{}", target_arg)) .cwd(&new) .with_stderr_data(expected) .run(); } #[cargo_test] fn optional_build_script_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] bar = { path = "bar", optional = true } [build-dependencies] bar = { path = "bar", optional = true } "#, ) .file( "build.rs", r#" #[cfg(feature = "bar")] extern crate bar; fn main() { #[cfg(feature = "bar")] { println!("cargo::rustc-env=FOO={}", bar::bar()); return } println!("cargo::rustc-env=FOO=0"); } "#, ) .file( "src/main.rs", r#" #[cfg(feature = "bar")] extern crate bar; fn main() { println!("{}", env!("FOO")); } "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("bar/src/lib.rs", "pub fn bar() -> u32 { 1 }"); let p = p.build(); p.cargo("run") .with_stdout_data(str![[r#" 0 "#]]) .run(); p.cargo("run --features bar") .with_stdout_data(str![[r#" 1 "#]]) .run(); } #[cargo_test] fn optional_build_dep_and_required_normal_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = { path = "./bar", optional = true } [build-dependencies] bar = { path = "./bar" } "#, ) .file("build.rs", "extern crate bar; fn main() { bar::bar(); }") .file( "src/main.rs", r#" #[cfg(feature = "bar")] extern crate bar; fn main() { #[cfg(feature = "bar")] { println!("{}", bar::bar()); } #[cfg(not(feature = "bar"))] { println!("0"); } } "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("bar/src/lib.rs", "pub fn bar() -> u32 { 1 }"); let p = p.build(); p.cargo("run") .with_stdout_data(str![[r#" 0 "#]]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); p.cargo("run --all-features") .with_stdout_data(str![[r#" 1 "#]]) .with_stderr_data(str![[r#" [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); } #[cargo_test] fn using_rerun_if_changed_does_not_rebuild() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] "#, ) .file( "build.rs", r#" fn main() { println!("cargo::rerun-if-changed=build.rs"); } "#, ) .file("src/lib.rs", "") .build(); p.cargo("build").run(); p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn links_interrupted_can_restart() { // Test for a `links` dependent build script getting canceled and then // restarted. Steps: // 1. Build to establish fingerprints. // 2. Change something (an env var in this case) that triggers the // dependent build script to run again. Kill the top-level build script // while it is running (such as hitting Ctrl-C). // 3. Run the build again, it should re-run the build script. let bar = project() .at("bar") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] links = "foo" build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::rerun-if-env-changed=SOMEVAR"); } "#, ) .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" [dependencies.bar] path = '{}' "#, bar.root().display() ), ) .file("src/lib.rs", "") .file( "build.rs", r#" use std::env; fn main() { println!("cargo::metadata=rebuild-if-changed=build.rs"); if std::path::Path::new("abort").exists() { panic!("Crash!"); } } "#, ) .build(); p.cargo("build").run(); // Simulate the user hitting Ctrl-C during a build. p.change_file("abort", ""); // Set SOMEVAR to trigger a rebuild. p.cargo("build") .env("SOMEVAR", "1") .with_stderr_data(str![[r#" ... Crash! ... "#]]) .with_status(101) .run(); fs::remove_file(p.root().join("abort")).unwrap(); // Try again without aborting the script. // ***This is currently broken, the script does not re-run. p.cargo("build -v") .env("SOMEVAR", "1") .with_stderr_data(str![[r#" ... [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` ... "#]]) .run(); } #[cargo_test] fn dev_dep_with_links() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] links = "x" [dev-dependencies] bar = { path = "./bar" } "#, ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] links = "y" [dependencies] foo = { path = ".." } "#, ) .file("bar/build.rs", "fn main() {}") .file("bar/src/lib.rs", "") .build(); p.cargo("check --tests").run(); } #[cargo_test] fn rerun_if_directory() { if !symlink_supported() { return; } // rerun-if-changed of a directory should rerun if any file in the directory changes. let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::rerun-if-changed=somedir"); } "#, ) .build(); let dirty = |expected| { p.cargo("check -v").with_stderr_data(expected).run(); }; let fresh = || { p.cargo("check") .with_stderr_data( "\ [FINISHED] [..] ", ) .run(); }; // Start with a missing directory. dirty(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build[..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); // Because the directory doesn't exist, it will trigger a rebuild every time. // https://github.com/rust-lang/cargo/issues/6003 dirty(str![[r#" [DIRTY] foo v0.1.0 ([ROOT]/foo): the file `somedir` is missing [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); if is_coarse_mtime() { sleep_ms(1000); } // Empty directory. fs::create_dir(p.root().join("somedir")).unwrap(); dirty(str![[r#" [DIRTY] foo v0.1.0 ([ROOT]/foo): the file `somedir` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); fresh(); if is_coarse_mtime() { sleep_ms(1000); } // Add a file. p.change_file("somedir/foo", ""); p.change_file("somedir/bar", ""); dirty(str![[r#" [DIRTY] foo v0.1.0 ([ROOT]/foo): the file `somedir` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); fresh(); if is_coarse_mtime() { sleep_ms(1000); } // Add a symlink. p.symlink("foo", "somedir/link"); dirty(str![[r#" [DIRTY] foo v0.1.0 ([ROOT]/foo): the file `somedir` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); fresh(); if is_coarse_mtime() { sleep_ms(1000); } // Move the symlink. fs::remove_file(p.root().join("somedir/link")).unwrap(); p.symlink("bar", "somedir/link"); dirty(str![[r#" [DIRTY] foo v0.1.0 ([ROOT]/foo): the file `somedir` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); fresh(); if is_coarse_mtime() { sleep_ms(1000); } // Remove a file. fs::remove_file(p.root().join("somedir/foo")).unwrap(); dirty(str![[r#" [DIRTY] foo v0.1.0 ([ROOT]/foo): the file `somedir` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); fresh(); } #[cargo_test] fn rerun_if_published_directory() { // build script of a dependency contains a `rerun-if-changed` pointing to a directory Package::new("mylib-sys", "1.0.0") .file("mylib/balrog.c", "") .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { // Changing to mylib/balrog.c will not trigger a rebuild println!("cargo::rerun-if-changed=mylib"); } "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] mylib-sys = "1.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check").run(); // Delete regitry src to make directories being recreated with the latest timestamp. cargo_home().join("registry/src").rm_rf(); p.cargo("check --verbose") .with_stderr_data(str![[r#" [FRESH] mylib-sys v1.0.0 [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Upgrade of a package should still trigger a rebuild Package::new("mylib-sys", "1.0.1") .file("mylib/balrog.c", "") .file("mylib/balrog.h", "") .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::rerun-if-changed=mylib"); } "#, ) .publish(); p.cargo("update").run(); p.cargo("fetch").run(); p.cargo("check -v") .with_stderr_data(str![[r#" [COMPILING] mylib-sys v1.0.1 [RUNNING] `rustc --crate-name build_script_build [..]` [RUNNING] `[ROOT]/foo/target/debug/build/mylib-sys-[HASH]/build-script-build` [RUNNING] `rustc --crate-name mylib_sys [..]` [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn test_with_dep_metadata() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = 'bar' } "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { assert_eq!(std::env::var("DEP_BAR_FOO").unwrap(), "bar"); } "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" links = 'bar' "#, ) .file("bar/src/lib.rs", "") .file( "bar/build.rs", r#" fn main() { println!("cargo::metadata=foo=bar"); } "#, ) .build(); p.cargo("test --lib").run(); } #[cargo_test] fn duplicate_script_with_extra_env() { // Test where a build script is run twice, that emits different rustc-env // and rustc-cfg values. In this case, one is run for host, the other for // target. if !cross_compile::can_run_on_host() { return; } let target = cross_compile::alternate(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo", "pm"] "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] pm = { path = "../pm" } "#, ) .file( "foo/src/lib.rs", &r#" //! ```rust //! #[cfg(not(mycfg="{target}"))] //! compile_error!{"expected mycfg set"} //! assert_eq!(env!("CRATE_TARGET"), "{target}"); //! assert_eq!(std::env::var("CRATE_TARGET").unwrap(), "{target}"); //! ``` #[test] fn check_target() { #[cfg(not(mycfg="{target}"))] compile_error!{"expected mycfg set"} // Compile-time assertion. assert_eq!(env!("CRATE_TARGET"), "{target}"); // Run-time assertion. assert_eq!(std::env::var("CRATE_TARGET").unwrap(), "{target}"); } "# .replace("{target}", target), ) .file( "foo/build.rs", r#" fn main() { println!("cargo::rustc-env=CRATE_TARGET={}", std::env::var("TARGET").unwrap()); println!("cargo::rustc-cfg=mycfg=\"{}\"", std::env::var("TARGET").unwrap()); } "#, ) .file( "pm/Cargo.toml", r#" [package] name = "pm" version = "0.1.0" edition = "2015" [lib] proc-macro = true # This is just here to speed things up. doctest = false [dev-dependencies] foo = { path = "../foo" } "#, ) .file("pm/src/lib.rs", "") .build(); p.cargo("test --workspace --target") .arg(&target) .with_stdout_data(str![[r#" ... test check_target ... ok ... "#]]) .run(); if cargo_test_support::is_nightly() { p.cargo("test --workspace -Z doctest-xcompile --doc --target") .arg(&target) .masquerade_as_nightly_cargo(&["doctest-xcompile"]) .with_stdout_data(str![[r#" ... test foo/src/lib.rs - (line 2) ... ok ... "#]]) .run(); } } #[cargo_test] fn wrong_output() { let p = project() .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::example"); } "#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [ERROR] invalid output in build script of `foo v0.0.1 ([ROOT]/foo)`: `cargo::example` Expected a line with `cargo::KEY=VALUE` with an `=` character, but none was found. See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script for more information about build script outputs. "#]]) .run(); } #[cargo_test] fn custom_build_closes_stdin() { // Ensure stdin is closed to prevent deadlock. // See https://github.com/rust-lang/cargo/issues/11196 let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" build = "build.rs" "#, ) .file("src/main.rs", "fn main() {}") .file( "build.rs", r#"fn main() { let mut line = String::new(); std::io::stdin().read_line(&mut line).unwrap(); }"#, ) .build(); p.cargo("build").run(); } #[cargo_test] fn test_old_syntax() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "src/main.rs", r#" const FOO: &'static str = env!("FOO"); fn main() { println!("{}", FOO); } "#, ) .file( "build.rs", r#"fn main() { println!("cargo:rustc-env=FOO=foo"); println!("cargo:foo=foo"); }"#, ) .build(); p.cargo("build -v").run(); p.cargo("run -v") .with_stdout_data(str![[r#" foo "#]]) .run(); } #[cargo_test] fn test_invalid_old_syntax() { // Unexpected metadata value. let p = project() .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo:foo"); } "#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [ERROR] invalid output in build script of `foo v0.0.1 ([ROOT]/foo)`: `cargo:foo` Expected a line with `cargo:KEY=VALUE` with an `=` character, but none was found. See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script for more information about build script outputs. "#]]) .run(); } #[cargo_test] fn test_invalid_new_syntax() { // Unexpected metadata value. let p = project() .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::metadata=foo"); } "#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [ERROR] invalid output in build script of `foo v0.0.1 ([ROOT]/foo)`: `cargo::metadata=foo` Expected a line with `cargo::metadata=KEY=VALUE` with an `=` character, but none was found. See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script for more information about build script outputs. "#]]) .run(); // `cargo::` can not be used with the unknown key. let p = project() .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::foo=bar"); } "#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [ERROR] invalid output in build script of `foo v0.0.1 ([ROOT]/foo)`: `cargo::foo=bar` Unknown key: `foo`. See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script for more information about build script outputs. "#]]) .run(); } #[cargo_test] fn test_new_syntax_with_old_msrv() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" rust-version = "1.60.0" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::metadata=foo=bar"); } "#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [ERROR] the `cargo::` syntax for build script output instructions was added in Rust 1.77.0, but the minimum supported Rust version of `foo v0.5.0 ([ROOT]/foo)` is 1.60.0. Switch to the old `cargo:foo=bar` syntax instead of `cargo::metadata=foo=bar` (note the single colon). See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script for more information about build script outputs. "#]]) .run(); } #[cargo_test] fn test_new_syntax_with_old_msrv_and_reserved_prefix() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" rust-version = "1.60.0" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::rustc-check-cfg=cfg(foo)"); } "#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [ERROR] the `cargo::` syntax for build script output instructions was added in Rust 1.77.0, but the minimum supported Rust version of `foo v0.5.0 ([ROOT]/foo)` is 1.60.0. Switch to the old `cargo:rustc-check-cfg=cfg(foo)` syntax (note the single colon). See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script for more information about build script outputs. "#]]) .run(); } #[cargo_test] fn test_new_syntax_with_old_msrv_and_unknown_prefix() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" rust-version = "1.60.0" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::foo=bar"); } "#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [ERROR] the `cargo::` syntax for build script output instructions was added in Rust 1.77.0, but the minimum supported Rust version of `foo v0.5.0 ([ROOT]/foo)` is 1.60.0. See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script for more information about build script outputs. "#]]) .run(); } #[cargo_test] fn test_new_syntax_with_compatible_partial_msrv() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" edition = "2015" build = "build.rs" rust-version = "1.77" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::metadata=foo=bar"); } "#, ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn test_old_syntax_with_old_msrv() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" rust-version = "1.60.0" "#, ) .file( "src/main.rs", r#" const FOO: &'static str = env!("FOO"); fn main() { println!("{}", FOO); } "#, ) .file( "build.rs", r#"fn main() { println!("cargo:rustc-env=FOO=foo"); println!("cargo:foo=foo"); }"#, ) .build(); p.cargo("build -v").run(); p.cargo("run -v") .with_stdout_data(str![[r#" foo "#]]) .run(); } #[cargo_test] fn build_script_rerun_when_target_rustflags_change() { let target = rustc_host(); let p = project() .file( "src/main.rs", r#" fn main() { #[cfg(enable)] println!("hello"); } "#, ) .file( "build.rs", r#" use std::env; fn main() { println!("cargo::rustc-check-cfg=cfg(enable)"); if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") { if !rustflags.is_empty() { println!("cargo::rustc-cfg=enable"); } } } "#, ) .build(); p.cargo("run --target") .arg(&target) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/[HOST_TARGET]/debug/foo[EXE]` "#]]) .run(); p.cargo("run --target") .arg(&target) .env("RUSTFLAGS", "-C opt-level=3") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/[HOST_TARGET]/debug/foo[EXE]` "#]]) .with_stdout_data(str![[r#" hello "#]]) .run(); } #[cargo_test] fn links_overrides_with_target_applies_to_host() { let p = project() .file( "Cargo.toml", r#" [package] name = "mylib-sys" edition = "2021" version = "0.0.1" authors = [] links = "mylib" "#, ) .file("src/lib.rs", "") .file("build.rs", "bad file") .build(); p.cargo("build -v") .masquerade_as_nightly_cargo(&["target-applies-to-host"]) .args(&[ "-Ztarget-applies-to-host", "--config", "target-applies-to-host=false", ]) .args(&[ "--config", &format!(r#"target.{}.mylib.rustc-link-search=["foo"]"#, rustc_host()), ]) .with_stderr_data(str![[r#" [COMPILING] mylib-sys v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name mylib_sys [..] -L foo` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn directory_with_leading_underscore() { let p: cargo_test_support::Project = git::new("foo", |p| { p.no_manifest() .file( "_foo/foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2021" build = "build.rs" "#, ) .file("_foo/foo/src/main.rs", "fn main() {}") .file("_foo/foo/build.rs", "fn main() { }") }); p.cargo("build --manifest-path=_foo/foo/Cargo.toml -v") .with_status(0) .run(); } cargo-0.86.0/tests/testsuite/build_script_env.rs000064400000000000000000000267141046102023000201200ustar 00000000000000//! Tests for build.rs rerun-if-env-changed and rustc-env use cargo_test_support::basic_manifest; use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::sleep_ms; use cargo_test_support::str; #[cargo_test] fn rerun_if_env_changes() { let p = project() .file("src/main.rs", "fn main() {}") .file( "build.rs", r#" fn main() { println!("cargo::rerun-if-env-changed=FOO"); } "#, ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .env("FOO", "bar") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .env("FOO", "baz") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .env("FOO", "baz") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rerun_if_env_or_file_changes() { let p = project() .file("src/main.rs", "fn main() {}") .file( "build.rs", r#" fn main() { println!("cargo::rerun-if-env-changed=FOO"); println!("cargo::rerun-if-changed=foo"); } "#, ) .file("foo", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .env("FOO", "bar") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .env("FOO", "bar") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); sleep_ms(1000); p.change_file("foo", "// modified"); p.cargo("check") .env("FOO", "bar") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rustc_bootstrap() { let build_rs = r#" fn main() { println!("cargo::rustc-env=RUSTC_BOOTSTRAP=1"); } "#; let p = project() .file("Cargo.toml", &basic_manifest("has-dashes", "0.0.1")) .file( "src/lib.rs", "#![allow(internal_features)] #![feature(rustc_attrs)]", ) .file("build.rs", build_rs) .build(); // RUSTC_BOOTSTRAP unset on stable should error p.cargo("check") .with_stderr_data(str![[r#" [COMPILING] has-dashes v0.0.1 ([ROOT]/foo) [ERROR] Cannot set `RUSTC_BOOTSTRAP=1` from build script of `has-dashes v0.0.1 ([ROOT]/foo)`. [NOTE] Crates cannot set `RUSTC_BOOTSTRAP` themselves, as doing so would subvert the stability guarantees of Rust for your project. [HELP] If you're sure you want to do this in your project, set the environment variable `RUSTC_BOOTSTRAP=has_dashes` before running cargo instead. "#]]) .with_status(101) .run(); // nightly should warn whether or not RUSTC_BOOTSTRAP is set p.cargo("check") .masquerade_as_nightly_cargo(&["RUSTC_BOOTSTRAP"]) // NOTE: uses RUSTC_BOOTSTRAP so it will be propagated to rustc // (this matters when tests are being run with a beta or stable cargo) .env("RUSTC_BOOTSTRAP", "1") .with_stderr_data(str![[r#" [COMPILING] has-dashes v0.0.1 ([ROOT]/foo) [WARNING] has-dashes@0.0.1: Cannot set `RUSTC_BOOTSTRAP=1` from build script of `has-dashes v0.0.1 ([ROOT]/foo)`. [NOTE] Crates cannot set `RUSTC_BOOTSTRAP` themselves, as doing so would subvert the stability guarantees of Rust for your project. [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // RUSTC_BOOTSTRAP set to the name of the library should warn p.cargo("check") .env("RUSTC_BOOTSTRAP", "has_dashes") .with_stderr_data(str![[r#" [WARNING] has-dashes@0.0.1: Cannot set `RUSTC_BOOTSTRAP=1` from build script of `has-dashes v0.0.1 ([ROOT]/foo)`. [NOTE] Crates cannot set `RUSTC_BOOTSTRAP` themselves, as doing so would subvert the stability guarantees of Rust for your project. [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // RUSTC_BOOTSTRAP set to some random value should error p.cargo("check") .env("RUSTC_BOOTSTRAP", "bar") .with_stderr_data(str![[r#" [ERROR] Cannot set `RUSTC_BOOTSTRAP=1` from build script of `has-dashes v0.0.1 ([ROOT]/foo)`. [NOTE] Crates cannot set `RUSTC_BOOTSTRAP` themselves, as doing so would subvert the stability guarantees of Rust for your project. [HELP] If you're sure you want to do this in your project, set the environment variable `RUSTC_BOOTSTRAP=has_dashes` before running cargo instead. "#]]) .with_status(101) .run(); // Tests for binaries instead of libraries let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.0.1")) .file( "src/main.rs", "#![allow(internal_features)] #![feature(rustc_attrs)] fn main() {}", ) .file("build.rs", build_rs) .build(); // nightly should warn when there's no library whether or not RUSTC_BOOTSTRAP is set p.cargo("check") .masquerade_as_nightly_cargo(&["RUSTC_BOOTSTRAP"]) // NOTE: uses RUSTC_BOOTSTRAP so it will be propagated to rustc // (this matters when tests are being run with a beta or stable cargo) .env("RUSTC_BOOTSTRAP", "1") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [WARNING] foo@0.0.1: Cannot set `RUSTC_BOOTSTRAP=1` from build script of `foo v0.0.1 ([ROOT]/foo)`. [NOTE] Crates cannot set `RUSTC_BOOTSTRAP` themselves, as doing so would subvert the stability guarantees of Rust for your project. [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // RUSTC_BOOTSTRAP conditionally set when there's no library should error (regardless of the value) p.cargo("check") .env("RUSTC_BOOTSTRAP", "foo") .with_stderr_data(str![[r#" [ERROR] Cannot set `RUSTC_BOOTSTRAP=1` from build script of `foo v0.0.1 ([ROOT]/foo)`. [NOTE] Crates cannot set `RUSTC_BOOTSTRAP` themselves, as doing so would subvert the stability guarantees of Rust for your project. [HELP] If you're sure you want to do this in your project, set the environment variable `RUSTC_BOOTSTRAP=1` before running cargo instead. "#]]) .with_status(101) .run(); } #[cargo_test] fn build_script_env_verbose() { let build_rs = r#" fn main() {} "#; let p = project() .file("Cargo.toml", &basic_manifest("verbose-build", "0.0.1")) .file("src/lib.rs", "") .file("build.rs", build_rs) .build(); p.cargo("check -vv") .with_stderr_data( "\ ... [RUNNING] `[..]CARGO=[..]build-script-build` ...", ) .run(); } #[cargo_test] #[cfg(target_arch = "x86_64")] fn build_script_sees_cfg_target_feature() { let build_rs = r#" fn main() { let cfg = std::env::var("CARGO_CFG_TARGET_FEATURE").unwrap(); eprintln!("CARGO_CFG_TARGET_FEATURE={cfg}"); } "#; let configs = [ r#" [build] rustflags = ["-Ctarget-feature=+sse4.1,+sse4.2"] "#, r#" [target.'cfg(target_arch = "x86_64")'] rustflags = ["-Ctarget-feature=+sse4.1,+sse4.2"] "#, ]; for config in configs { let p = project() .file(".cargo/config.toml", config) .file("src/lib.rs", r#""#) .file("build.rs", build_rs) .build(); p.cargo("check -vv") .with_stderr_data( "\ ... [foo 0.0.1] CARGO_CFG_TARGET_FEATURE=[..]sse4.2[..] ... [..]-Ctarget-feature=[..]+sse4.2[..] ...", ) .run(); } } /// In this test, the cfg is self-contradictory. There's no *right* answer as to /// what the value of `RUSTFLAGS` should be in this case. We chose to give a /// warning. However, no matter what we do, it's important that build scripts /// and rustc see a consistent picture #[cargo_test] fn cfg_paradox() { let build_rs = r#" fn main() { let cfg = std::env::var("CARGO_CFG_BERTRAND").is_ok(); eprintln!("cfg!(bertrand)={cfg}"); } "#; let config = r#" [target.'cfg(not(bertrand))'] rustflags = ["--cfg=bertrand"] "#; let p = project() .file(".cargo/config.toml", config) .file("src/lib.rs", r#""#) .file("build.rs", build_rs) .build(); p.cargo("check -vv") .with_stderr_data( "\ [WARNING] non-trivial mutual dependency between target-specific configuration and RUSTFLAGS ... [foo 0.0.1] cfg!(bertrand)=true ... [..]--cfg=bertrand[..] ...", ) .run(); } /// This test checks how Cargo handles rustc cfgs which are defined both with /// and without a value. The expected behavior is that the environment variable /// is going to contain all the values. /// /// For example, this configuration: /// ``` /// target_has_atomic /// target_has_atomic="16" /// target_has_atomic="32" /// target_has_atomic="64" /// target_has_atomic="8" /// target_has_atomic="ptr" /// ``` /// /// Should result in the following environment variable: /// /// ``` /// CARGO_CFG_TARGET_HAS_ATOMIC=16,32,64,8,ptr /// ``` /// /// On the other hand, configuration symbols without any value should result in /// an empty string. /// /// For example, this configuration: /// /// ``` /// target_thread_local /// ``` /// /// Should result in the following environment variable: /// /// ``` /// CARGO_CFG_TARGET_THREAD_LOCAL= /// ``` #[cargo_test(nightly, reason = "affected rustc cfg is unstable")] #[cfg(target_arch = "x86_64")] fn rustc_cfg_with_and_without_value() { let build_rs = r#" fn main() { let cfg = std::env::var("CARGO_CFG_TARGET_HAS_ATOMIC"); eprintln!("CARGO_CFG_TARGET_HAS_ATOMIC={cfg:?}"); let cfg = std::env::var("CARGO_CFG_WINDOWS"); eprintln!("CARGO_CFG_WINDOWS={cfg:?}"); let cfg = std::env::var("CARGO_CFG_UNIX"); eprintln!("CARGO_CFG_UNIX={cfg:?}"); } "#; let p = project() .file("src/lib.rs", r#""#) .file("build.rs", build_rs) .build(); let mut check = p.cargo("check -vv"); #[cfg(target_has_atomic = "64")] check.with_stderr_data( "\ ... [foo 0.0.1] CARGO_CFG_TARGET_HAS_ATOMIC=Ok(\"[..]64[..]\") ...", ); #[cfg(windows)] check.with_stderr_data( "\ ... [foo 0.0.1] CARGO_CFG_WINDOWS=Ok(\"\") ...", ); #[cfg(unix)] check.with_stderr_data( "\ ... [foo 0.0.1] CARGO_CFG_UNIX=Ok(\"\") ...", ); check.run(); } cargo-0.86.0/tests/testsuite/build_script_extra_link_arg.rs000064400000000000000000000257471046102023000223260ustar 00000000000000//! Tests for additional link arguments. // NOTE: Many of these tests use `without_status()` when passing bogus flags // because MSVC link.exe just gives a warning on unknown flags (how helpful!), // and other linkers will return an error. use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::{basic_bin_manifest, basic_lib_manifest, basic_manifest, project}; #[cargo_test] fn build_script_extra_link_arg_bin() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( "build.rs", r#" fn main() { println!("cargo::rustc-link-arg-bins=--this-is-a-bogus-flag"); } "#, ) .build(); p.cargo("build -v") .without_status() .with_stderr_data( "\ ... [RUNNING] `rustc --crate-name foo [..]-C link-arg=--this-is-a-bogus-flag[..] ...", ) .run(); } #[cargo_test] fn build_script_extra_link_arg_bin_single() { let p = project() .file( "Cargo.toml", r#" [package] name = "foobar" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [[bin]] name = "foo" [[bin]] name = "bar" "#, ) .file("src/main.rs", "fn main() {}") .file( "build.rs", r#" fn main() { println!("cargo::rustc-link-arg-bins=--bogus-flag-all"); println!("cargo::rustc-link-arg-bin=foo=--bogus-flag-foo"); println!("cargo::rustc-link-arg-bin=bar=--bogus-flag-bar"); } "#, ) .build(); p.cargo("build -v") .without_status() .with_stderr_data( "\ ... [RUNNING] `rustc --crate-name foo [..]-C link-arg=--bogus-flag-all -C link-arg=--bogus-flag-foo[..] ...", ) .with_stderr_data( "\ ... [RUNNING] `rustc --crate-name bar [..]-C link-arg=--bogus-flag-all -C link-arg=--bogus-flag-bar[..] ...", ) .run(); } #[cargo_test] fn build_script_extra_link_arg() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( "build.rs", r#" fn main() { println!("cargo::rustc-link-arg=--this-is-a-bogus-flag"); } "#, ) .build(); p.cargo("build -v") .without_status() .with_stderr_data( "\ ... [RUNNING] `rustc --crate-name foo [..]-C link-arg=--this-is-a-bogus-flag[..] ...", ) .run(); } #[cargo_test] fn link_arg_missing_target() { // Errors when a given target doesn't exist. let p = project() .file("src/lib.rs", "") .file( "build.rs", r#"fn main() { println!("cargo::rustc-link-arg-cdylib=--bogus"); }"#, ) .build(); // TODO: Uncomment this if cdylib restriction is re-added (see // cdylib_link_arg_transitive below). // p.cargo("check") // .with_status(101) // .with_stderr("\ // [COMPILING] foo [..] // error: invalid instruction `cargo::rustc-link-arg-cdylib` from build script of `foo v0.0.1 ([ROOT]/foo)` // The package foo v0.0.1 ([ROOT]/foo) does not have a cdylib target. // ") // .run(); p.change_file( "build.rs", r#"fn main() { println!("cargo::rustc-link-arg-bins=--bogus"); }"#, ); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [ERROR] invalid instruction `cargo::rustc-link-arg-bins` from build script of `foo v0.0.1 ([ROOT]/foo)` The package foo v0.0.1 ([ROOT]/foo) does not have a bin target. "#]]) .run(); p.change_file( "build.rs", r#"fn main() { println!("cargo::rustc-link-arg-bin=abc=--bogus"); }"#, ); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [ERROR] invalid instruction `cargo::rustc-link-arg-bin` from build script of `foo v0.0.1 ([ROOT]/foo)` The package foo v0.0.1 ([ROOT]/foo) does not have a bin target with the name `abc`. "#]]) .run(); p.change_file( "build.rs", r#"fn main() { println!("cargo::rustc-link-arg-bin=abc"); }"#, ); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [ERROR] invalid instruction `cargo::rustc-link-arg-bin=abc` from build script of `foo v0.0.1 ([ROOT]/foo)` The instruction should have the form cargo::rustc-link-arg-bin=BIN=ARG "#]]) .run(); } #[cargo_test] fn cdylib_link_arg_transitive() { // There was an unintended regression in 1.50 where rustc-link-arg-cdylib // arguments from dependencies were being applied in the parent package. // Previously it was silently ignored. // See https://github.com/rust-lang/cargo/issues/9562 let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] crate-type = ["cdylib"] [dependencies] bar = {path="bar"} "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "1.0.0")) .file("bar/src/lib.rs", "") .file( "bar/build.rs", r#" fn main() { println!("cargo::rustc-link-arg-cdylib=--bogus"); } "#, ) .build(); p.cargo("build -v") .without_status() .with_stderr_data( "\ ... [COMPILING] bar v1.0.0 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name build_script_build --edition=2015 bar/build.rs [..] [RUNNING] `[ROOT]/foo/target/debug/build/bar-[HASH]/build-script-build` [WARNING] bar@1.0.0: cargo::rustc-link-arg-cdylib was specified in the build script of bar v1.0.0 \ ([ROOT]/foo/bar), but that package does not contain a cdylib target Allowing this was an unintended change in the 1.50 release, and may become an error in \ the future. For more information, see . [RUNNING] `rustc --crate-name bar --edition=2015 bar/src/lib.rs [..] [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]-C link-arg=--bogus[..]` ...", ) .run(); } #[cargo_test] fn link_arg_transitive_not_allowed() { // Verify that transitive dependencies don't pass link args. // // Note that rustc-link-arg doesn't have any errors or warnings when it is // unused. Perhaps that could be more aggressive, but it is difficult // since it could be used for test binaries. Package::new("bar", "1.0.0") .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::rustc-link-arg=--bogus"); } "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] crate-type = ["cdylib"] [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [COMPILING] bar v1.0.0 [RUNNING] `rustc --crate-name build_script_build [..] [RUNNING] `[ROOT]/foo/target/debug/build/bar-[HASH]/build-script-build` [RUNNING] `rustc --crate-name bar [..] [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stderr_does_not_contain("--bogus") .run(); } #[cargo_test] fn link_arg_with_doctest() { let p = project() .file( "src/lib.rs", r#" //! ``` //! let x = 5; //! assert_eq!(x, 5); //! ``` "#, ) .file( "build.rs", r#" fn main() { println!("cargo::rustc-link-arg=--this-is-a-bogus-flag"); } "#, ) .build(); p.cargo("test --doc -v") .without_status() .with_stderr_data( "\ ... [RUNNING] `rustdoc [..]--crate-name foo [..]-C link-arg=--this-is-a-bogus-flag[..] ...", ) .run(); } #[cargo_test] fn build_script_extra_link_arg_tests() { let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .file("tests/test_foo.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::rustc-link-arg-tests=--this-is-a-bogus-flag"); } "#, ) .build(); p.cargo("test -v") .without_status() .with_stderr_data( "\ ... [RUNNING] `rustc --crate-name test_foo [..]-C link-arg=--this-is-a-bogus-flag[..] ...", ) .run(); } #[cargo_test] fn build_script_extra_link_arg_benches() { let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .file("benches/bench_foo.rs", "") .file( "build.rs", r#" fn main() { println!("cargo::rustc-link-arg-benches=--this-is-a-bogus-flag"); } "#, ) .build(); p.cargo("bench -v") .without_status() .with_stderr_data( "\ ... [RUNNING] `rustc --crate-name bench_foo [..]-C link-arg=--this-is-a-bogus-flag[..] ...", ) .run(); } #[cargo_test] fn build_script_extra_link_arg_examples() { let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .file("examples/example_foo.rs", "fn main() {}") .file( "build.rs", r#" fn main() { println!("cargo::rustc-link-arg-examples=--this-is-a-bogus-flag"); } "#, ) .build(); p.cargo("build -v --examples") .without_status() .with_stderr_data( "\ ... [RUNNING] `rustc --crate-name example_foo [..]-C link-arg=--this-is-a-bogus-flag[..] ...", ) .run(); } cargo-0.86.0/tests/testsuite/cache_lock.rs000064400000000000000000000234641046102023000166370ustar 00000000000000//! Tests for `CacheLock`. use std::thread::JoinHandle; use cargo::util::cache_lock::{CacheLockMode, CacheLocker}; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::{retry, thread_wait_timeout, threaded_timeout}; use crate::config::GlobalContextBuilder; /// Helper to verify that it is OK to acquire the given lock (it shouldn't block). fn verify_lock_is_ok(mode: CacheLockMode) { let root = paths::root(); threaded_timeout(10, move || { let gctx = GlobalContextBuilder::new().root(root).build(); let locker = CacheLocker::new(); // This would block if it is held. let _lock = locker.lock(&gctx, mode).unwrap(); assert!(locker.is_locked(mode)); }); } /// Helper to acquire two locks from the same locker. fn a_b_nested(a: CacheLockMode, b: CacheLockMode) { let gctx = GlobalContextBuilder::new().build(); let locker = CacheLocker::new(); let lock1 = locker.lock(&gctx, a).unwrap(); assert!(locker.is_locked(a)); let lock2 = locker.lock(&gctx, b).unwrap(); assert!(locker.is_locked(b)); drop(lock2); drop(lock1); // Verify locks were unlocked. verify_lock_is_ok(CacheLockMode::Shared); verify_lock_is_ok(CacheLockMode::DownloadExclusive); verify_lock_is_ok(CacheLockMode::MutateExclusive); } /// Helper to acquire two locks from separate lockers, verifying that they /// don't block each other. fn a_then_b_separate_not_blocked(a: CacheLockMode, b: CacheLockMode, verify: CacheLockMode) { let gctx = GlobalContextBuilder::new().build(); let locker1 = CacheLocker::new(); let lock1 = locker1.lock(&gctx, a).unwrap(); assert!(locker1.is_locked(a)); let locker2 = CacheLocker::new(); let lock2 = locker2.lock(&gctx, b).unwrap(); assert!(locker2.is_locked(b)); let thread = verify_lock_would_block(verify); // Unblock the thread. drop(lock1); drop(lock2); // Verify the thread is unblocked. thread_wait_timeout::<()>(100, thread); } /// Helper to acquire two locks from separate lockers, verifying that the /// second one blocks. fn a_then_b_separate_blocked(a: CacheLockMode, b: CacheLockMode) { let gctx = GlobalContextBuilder::new().build(); let locker = CacheLocker::new(); let lock = locker.lock(&gctx, a).unwrap(); assert!(locker.is_locked(a)); let thread = verify_lock_would_block(b); // Unblock the thread. drop(lock); // Verify the thread is unblocked. thread_wait_timeout::<()>(100, thread); } /// Helper to verify that acquiring the given mode would block. /// /// Always call `thread_wait_timeout` on the result. #[must_use] fn verify_lock_would_block(mode: CacheLockMode) -> JoinHandle<()> { let root = paths::root(); // Spawn a thread that will block on the lock. let thread = std::thread::spawn(move || { let gctx = GlobalContextBuilder::new().root(root).build(); let locker2 = CacheLocker::new(); let lock2 = locker2.lock(&gctx, mode).unwrap(); assert!(locker2.is_locked(mode)); drop(lock2); }); // Verify that it blocked. retry(100, || { if let Ok(s) = std::fs::read_to_string(paths::root().join("shell.out")) { if s.trim().starts_with("Blocking waiting for file lock on") { return Some(()); } else { eprintln!("unexpected output: {s}"); // Try again, it might have been partially written. } } None }); thread } #[test] fn new_is_unlocked() { let locker = CacheLocker::new(); assert!(!locker.is_locked(CacheLockMode::Shared)); assert!(!locker.is_locked(CacheLockMode::DownloadExclusive)); assert!(!locker.is_locked(CacheLockMode::MutateExclusive)); } #[cargo_test] fn multiple_shared() { // Test that two nested shared locks from the same locker are safe to acquire. a_b_nested(CacheLockMode::Shared, CacheLockMode::Shared); } #[cargo_test] fn multiple_shared_separate() { // Test that two independent shared locks are safe to acquire at the same time. a_then_b_separate_not_blocked( CacheLockMode::Shared, CacheLockMode::Shared, CacheLockMode::MutateExclusive, ); } #[cargo_test] fn multiple_download() { // That that two nested download locks from the same locker are safe to acquire. a_b_nested( CacheLockMode::DownloadExclusive, CacheLockMode::DownloadExclusive, ); } #[cargo_test] fn multiple_mutate() { // That that two nested mutate locks from the same locker are safe to acquire. a_b_nested( CacheLockMode::MutateExclusive, CacheLockMode::MutateExclusive, ); } #[cargo_test] #[should_panic(expected = "lock is not allowed")] fn download_then_shared() { // This sequence is not supported. a_b_nested(CacheLockMode::DownloadExclusive, CacheLockMode::Shared); } #[cargo_test] #[should_panic(expected = "lock upgrade from shared to exclusive not supported")] fn shared_then_mutate() { // This sequence is not supported. a_b_nested(CacheLockMode::Shared, CacheLockMode::MutateExclusive); } #[cargo_test] fn shared_then_download() { a_b_nested(CacheLockMode::Shared, CacheLockMode::DownloadExclusive); // Verify drop actually unlocked. verify_lock_is_ok(CacheLockMode::DownloadExclusive); verify_lock_is_ok(CacheLockMode::MutateExclusive); } #[cargo_test] fn mutate_then_shared() { a_b_nested(CacheLockMode::MutateExclusive, CacheLockMode::Shared); // Verify drop actually unlocked. verify_lock_is_ok(CacheLockMode::MutateExclusive); } #[cargo_test] fn download_then_mutate() { a_b_nested( CacheLockMode::DownloadExclusive, CacheLockMode::MutateExclusive, ); // Verify drop actually unlocked. verify_lock_is_ok(CacheLockMode::DownloadExclusive); verify_lock_is_ok(CacheLockMode::MutateExclusive); } #[cargo_test] fn mutate_then_download() { a_b_nested( CacheLockMode::MutateExclusive, CacheLockMode::DownloadExclusive, ); // Verify drop actually unlocked. verify_lock_is_ok(CacheLockMode::MutateExclusive); verify_lock_is_ok(CacheLockMode::DownloadExclusive); } #[cargo_test] fn readonly() { // In a permission denied situation, it should still allow a lock. It just // silently behaves as-if it was locked. let cargo_home = paths::home().join(".cargo"); std::fs::create_dir_all(&cargo_home).unwrap(); let mut perms = std::fs::metadata(&cargo_home).unwrap().permissions(); perms.set_readonly(true); std::fs::set_permissions(&cargo_home, perms).unwrap(); let gctx = GlobalContextBuilder::new().build(); let locker = CacheLocker::new(); for mode in [ CacheLockMode::Shared, CacheLockMode::DownloadExclusive, CacheLockMode::MutateExclusive, ] { let _lock1 = locker.lock(&gctx, mode).unwrap(); // Make sure it can recursively acquire the lock, too. let _lock2 = locker.lock(&gctx, mode).unwrap(); } } #[cargo_test] fn download_then_shared_separate() { a_then_b_separate_not_blocked( CacheLockMode::DownloadExclusive, CacheLockMode::Shared, CacheLockMode::MutateExclusive, ); } #[cargo_test] fn shared_then_download_separate() { a_then_b_separate_not_blocked( CacheLockMode::Shared, CacheLockMode::DownloadExclusive, CacheLockMode::MutateExclusive, ); } #[cargo_test] fn multiple_download_separate() { // Test that with two independent download locks, the second blocks until // the first is released. a_then_b_separate_blocked( CacheLockMode::DownloadExclusive, CacheLockMode::DownloadExclusive, ); } #[cargo_test] fn multiple_mutate_separate() { // Test that with two independent mutate locks, the second blocks until // the first is released. a_then_b_separate_blocked( CacheLockMode::MutateExclusive, CacheLockMode::MutateExclusive, ); } #[cargo_test] fn shared_then_mutate_separate() { a_then_b_separate_blocked(CacheLockMode::Shared, CacheLockMode::MutateExclusive); } #[cargo_test] fn download_then_mutate_separate() { a_then_b_separate_blocked( CacheLockMode::DownloadExclusive, CacheLockMode::MutateExclusive, ); } #[cargo_test] fn mutate_then_download_separate() { a_then_b_separate_blocked( CacheLockMode::MutateExclusive, CacheLockMode::DownloadExclusive, ); } #[cargo_test] fn mutate_then_shared_separate() { a_then_b_separate_blocked(CacheLockMode::MutateExclusive, CacheLockMode::Shared); } #[cargo_test(ignore_windows = "no method to prevent creating or locking a file")] fn mutate_err_is_atomic() { // Verifies that when getting a mutate lock, that if the first lock // succeeds, but the second one fails, that the first lock is released. let gctx = GlobalContextBuilder::new().build(); let locker = CacheLocker::new(); let cargo_home = gctx.home().as_path_unlocked(); let cache_path = cargo_home.join(".package-cache"); // This is a hacky way to force an error acquiring the download lock. By // making it a directory, it is unable to open it. // TODO: Unfortunately this doesn't work on Windows. I don't have any // ideas on how to simulate an error on Windows. cache_path.mkdir_p(); match locker.lock(&gctx, CacheLockMode::MutateExclusive) { Ok(_) => panic!("did not expect lock to succeed"), Err(e) => { let msg = format!("{e:?}"); assert!(msg.contains("failed to open:"), "{msg}"); } } assert!(!locker.is_locked(CacheLockMode::MutateExclusive)); assert!(!locker.is_locked(CacheLockMode::DownloadExclusive)); assert!(!locker.is_locked(CacheLockMode::Shared)); cache_path.rm_rf(); verify_lock_is_ok(CacheLockMode::DownloadExclusive); verify_lock_is_ok(CacheLockMode::Shared); verify_lock_is_ok(CacheLockMode::MutateExclusive); } cargo-0.86.0/tests/testsuite/cache_messages.rs000064400000000000000000000353641046102023000175200ustar 00000000000000//! Tests for caching compiler diagnostics. use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::tools; use cargo_test_support::{basic_manifest, is_coarse_mtime, project, registry::Package, sleep_ms}; use super::messages::raw_rustc_output; fn as_str(bytes: &[u8]) -> &str { std::str::from_utf8(bytes).expect("valid utf-8") } #[cargo_test] fn simple() { // A simple example that generates two warnings (unused functions). let p = project() .file( "src/lib.rs", " fn a() {} fn b() {} ", ) .build(); // Capture what rustc actually emits. This is done to avoid relying on the // exact message formatting in rustc. let rustc_output = raw_rustc_output(&p, "src/lib.rs", &[]); // -q so the output is the same as rustc (no "Compiling" or "Finished"). let cargo_output1 = p.cargo("check -q --color=never").run(); assert_eq!(rustc_output, as_str(&cargo_output1.stderr)); assert!(cargo_output1.stdout.is_empty()); // Check that the cached version is exactly the same. let cargo_output2 = p.cargo("check -q").run(); assert_eq!(rustc_output, as_str(&cargo_output2.stderr)); assert!(cargo_output2.stdout.is_empty()); } // same as `simple`, except everything is using the short format #[cargo_test] fn simple_short() { let p = project() .file( "src/lib.rs", " fn a() {} fn b() {} ", ) .build(); let rustc_output = raw_rustc_output(&p, "src/lib.rs", &["--error-format=short"]); let cargo_output1 = p .cargo("check -q --color=never --message-format=short") .run(); assert_eq!(rustc_output, as_str(&cargo_output1.stderr)); // assert!(cargo_output1.stdout.is_empty()); let cargo_output2 = p.cargo("check -q --message-format=short").run(); println!("{}", String::from_utf8_lossy(&cargo_output2.stdout)); assert_eq!(rustc_output, as_str(&cargo_output2.stderr)); assert!(cargo_output2.stdout.is_empty()); } #[cargo_test] fn color() { // Check enabling/disabling color. let p = project().file("src/lib.rs", "fn a() {}").build(); // Hack for issue in fwdansi 1.1. It is squashing multiple resets // into a single reset. // https://github.com/kennytm/fwdansi/issues/2 fn normalize(s: &str) -> String { #[cfg(windows)] return s.replace("\x1b[0m\x1b[0m", "\x1b[0m"); #[cfg(not(windows))] return s.to_string(); } let compare = |a, b| { assert_eq!(normalize(a), normalize(b)); }; // Capture the original color output. let rustc_color = raw_rustc_output(&p, "src/lib.rs", &["--color=always"]); assert!(rustc_color.contains("\x1b[")); // Capture the original non-color output. let rustc_nocolor = raw_rustc_output(&p, "src/lib.rs", &[]); assert!(!rustc_nocolor.contains("\x1b[")); // First pass, non-cached, with color, should be the same. let cargo_output1 = p.cargo("check -q --color=always").run(); compare(&rustc_color, as_str(&cargo_output1.stderr)); // Replay cached, with color. let cargo_output2 = p.cargo("check -q --color=always").run(); compare(&rustc_color, as_str(&cargo_output2.stderr)); // Replay cached, no color. let cargo_output_nocolor = p.cargo("check -q --color=never").run(); compare(&rustc_nocolor, as_str(&cargo_output_nocolor.stderr)); } #[cargo_test] fn cached_as_json() { // Check that cached JSON output is the same. let p = project().file("src/lib.rs", "fn a() {}").build(); // Grab the non-cached output, feature disabled. // NOTE: When stabilizing, this will need to be redone. let cargo_output = p.cargo("check --message-format=json").run(); let orig_cargo_out = as_str(&cargo_output.stdout); assert!(orig_cargo_out.contains("compiler-message")); p.cargo("clean").run(); // Check JSON output, not fresh. let cargo_output1 = p.cargo("check --message-format=json").run(); assert_eq!(as_str(&cargo_output1.stdout), orig_cargo_out); // Check JSON output, fresh. let cargo_output2 = p.cargo("check --message-format=json").run(); // The only difference should be this field. let fix_fresh = as_str(&cargo_output2.stdout).replace("\"fresh\":true", "\"fresh\":false"); assert_eq!(fix_fresh, orig_cargo_out); } #[cargo_test] fn clears_cache_after_fix() { // Make sure the cache is invalidated when there is no output. let p = project().file("src/lib.rs", "fn asdf() {}").build(); // Fill the cache. p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [WARNING] function `asdf` is never used ... [WARNING] `foo` (lib) generated 1 warning [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let cpath = p .glob("target/debug/.fingerprint/foo-*/output-*") .next() .unwrap() .unwrap(); assert!(std::fs::read_to_string(cpath).unwrap().contains("asdf")); // Fix it. if is_coarse_mtime() { sleep_ms(1000); } p.change_file("src/lib.rs", ""); p.cargo("check") .with_stdout_data("") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert_eq!( p.glob("target/debug/.fingerprint/foo-*/output-*").count(), 0 ); // And again, check the cache is correct. p.cargo("check") .with_stdout_data("") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rustdoc() { // Create a warning in rustdoc. let p = project() .file( "src/lib.rs", " #![warn(missing_docs)] pub fn f() {} ", ) .build(); let rustdoc_output = p.cargo("doc -q --color=always").run(); let rustdoc_stderr = as_str(&rustdoc_output.stderr); assert!(rustdoc_stderr.contains("missing")); assert!(rustdoc_stderr.contains("\x1b[")); assert_eq!( p.glob("target/debug/.fingerprint/foo-*/output-*").count(), 1 ); // Check the cached output. let rustdoc_output = p.cargo("doc -q --color=always").run(); assert_eq!(as_str(&rustdoc_output.stderr), rustdoc_stderr); } #[cargo_test] fn fix() { // Make sure `fix` is not broken by caching. let p = project().file("src/lib.rs", "pub fn try() {}").build(); p.cargo("fix --edition --allow-no-vcs").run(); assert_eq!(p.read_file("src/lib.rs"), "pub fn r#try() {}"); } #[cargo_test] fn very_verbose() { // Handle cap-lints in dependencies. Package::new("bar", "1.0.0") .file("src/lib.rs", "fn not_used() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -vv") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [CHECKING] bar v1.0.0 [RUNNING] [..] [WARNING] function `not_used` is never used ... [CHECKING] foo v0.1.0 ([ROOT]/foo) [RUNNING] [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check -vv") .with_stderr_data(str![[r#" [FRESH] bar v1.0.0 [WARNING] function `not_used` is never used ... [WARNING] `bar` (lib) generated 1 warning [FRESH] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn doesnt_create_extra_files() { // Ensure it doesn't create `output` files when not needed. Package::new("dep", "1.0.0") .file("src/lib.rs", "fn unused() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] dep = "1.0" "#, ) .file("src/lib.rs", "") .file("src/main.rs", "fn main() {}") .build(); p.cargo("check").run(); assert_eq!( p.glob("target/debug/.fingerprint/foo-*/output-*").count(), 0 ); assert_eq!( p.glob("target/debug/.fingerprint/dep-*/output-*").count(), 0 ); if is_coarse_mtime() { sleep_ms(1000); } p.change_file("src/lib.rs", "fn unused() {}"); p.cargo("check").run(); assert_eq!( p.glob("target/debug/.fingerprint/foo-*/output-*").count(), 1 ); } #[cargo_test] fn replay_non_json() { // Handles non-json output. let rustc = project() .at("rustc") .file("Cargo.toml", &basic_manifest("rustc_alt", "1.0.0")) .file( "src/main.rs", r#" fn main() { eprintln!("line 1"); eprintln!("line 2"); let r = std::process::Command::new("rustc") .args(std::env::args_os().skip(1)) .status(); std::process::exit(r.unwrap().code().unwrap_or(2)); } "#, ) .build(); rustc.cargo("build").run(); let p = project().file("src/lib.rs", "").build(); p.cargo("check") .env("RUSTC", rustc.bin("rustc_alt")) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) line 1 line 2 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .env("RUSTC", rustc.bin("rustc_alt")) .with_stderr_data(str![[r#" line 1 line 2 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn caching_large_output() { // Handles large number of messages. // This is an arbitrary amount that is greater than the 100 used in // job_queue. This is here to check for deadlocks or any other problems. const COUNT: usize = 250; let rustc = project() .at("rustc") .file("Cargo.toml", &basic_manifest("rustc_alt", "1.0.0")) .file( "src/main.rs", &format!( r#" fn main() {{ for i in 0..{} {{ eprintln!("{{{{\"message\": \"test message {{}}\", \"level\": \"warning\", \ \"spans\": [], \"children\": [], \"rendered\": \"test message {{}}\"}}}}", i, i); }} let r = std::process::Command::new("rustc") .args(std::env::args_os().skip(1)) .status(); std::process::exit(r.unwrap().code().unwrap_or(2)); }} "#, COUNT ), ) .build(); let mut expected = String::new(); for i in 0..COUNT { expected.push_str(&format!("test message {}\n", i)); } rustc.cargo("build").run(); let p = project().file("src/lib.rs", "").build(); p.cargo("check") .env("RUSTC", rustc.bin("rustc_alt")) .with_stderr_data(&format!( "\ [CHECKING] foo v0.0.1 ([ROOT]/foo) {}[WARNING] `foo` (lib) generated 250 warnings [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s ", expected )) .run(); p.cargo("check") .env("RUSTC", rustc.bin("rustc_alt")) .with_stderr_data(&format!( "\ {}[WARNING] `foo` (lib) generated 250 warnings [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s ", expected )) .run(); } #[cargo_test] fn rustc_workspace_wrapper() { let p = project() .file( "src/lib.rs", "pub fn f() { assert!(true); }\n\ fn unused_func() {}", ) .build(); p.cargo("check -v") .env("RUSTC_WORKSPACE_WRAPPER", tools::echo_wrapper()) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] [..]/rustc-echo-wrapper[EXE] rustc --crate-name foo [..] WRAPPER CALLED: rustc --crate-name foo --edition=2015 src/lib.rs [..] [WARNING] function `unused_func` is never used ... [WARNING] `foo` (lib) generated 1 warning [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Check without a wrapper should rebuild p.cargo("check -v") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc[..]` [WARNING] function `unused_func` is never used ... [WARNING] `foo` (lib) generated 1 warning [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); // Again, reading from the cache. p.cargo("check -v") .env("RUSTC_WORKSPACE_WRAPPER", tools::echo_wrapper()) .with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) WRAPPER CALLED: rustc [..] ... [WARNING] `foo` (lib) generated 1 warning [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); // And `check` should also be fresh, reading from cache. p.cargo("check -v") .with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [WARNING] function `unused_func` is never used ... [WARNING] `foo` (lib) generated 1 warning [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); } #[cargo_test] fn wacky_hashless_fingerprint() { // On Windows, executables don't have hashes. This checks for a bad // assumption that caused bad caching. let p = project() .file("src/bin/a.rs", "fn main() { let unused = 1; }") .file("src/bin/b.rs", "fn main() {}") .build(); p.cargo("check --bin b") .with_stderr_does_not_contain("[..]unused[..]") .run(); p.cargo("check --bin a") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [WARNING] unused variable: `unused` ... [WARNING] `foo` (bin "a") generated 1 warning [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // This should not pick up the cache from `a`. p.cargo("check --bin b") .with_stderr_does_not_contain("[..]unused[..]") .run(); } cargo-0.86.0/tests/testsuite/cargo/help/mod.rs000064400000000000000000000004511046102023000173550ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo/help/stdout.term.svg000064400000000000000000000202751046102023000212470ustar 00000000000000 Rust's package manager Usage: cargo [..][OPTIONS] [COMMAND] cargo [..][OPTIONS] -Zscript <MANIFEST_RS> [ARGS]... Options: -V, --version Print version info and exit --list List installed commands --explain <CODE> Provide a detailed explanation of a rustc error message -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never -C <DIRECTORY> Change to DIRECTORY before doing anything (nightly-only) --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Commands: build, b Compile the current package check, c Analyze the current package and report errors, but don't build object files clean Remove the target directory doc, d Build this package's and its dependencies' documentation new Create a new cargo package init Create a new cargo package in an existing directory add Add dependencies to a manifest file remove Remove dependencies from a manifest file run, r Run a binary or example of the local package test, t Run the tests bench Run the benchmarks update Update dependencies listed in Cargo.lock search Search registry for crates publish Package and upload this package to the registry install Install a Rust binary uninstall Uninstall a Rust binary ... See all commands with --list See 'cargo help <command>' for more information on a specific command. cargo-0.86.0/tests/testsuite/cargo/mod.rs000064400000000000000000000000261046102023000164230ustar 00000000000000mod help; mod z_help; cargo-0.86.0/tests/testsuite/cargo/z_help/mod.rs000064400000000000000000000005431046102023000177100ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .masquerade_as_nightly_cargo(&["-Z help"]) .args(["-Z", "help"]) .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo/z_help/stdout.term.svg000064400000000000000000000137631046102023000216040ustar 00000000000000 Available unstable (nightly-only) flags: -Z allow-features Allow *only* the listed unstable features -Z asymmetric-token Allows authenticating with asymmetric tokens -Z avoid-dev-deps Avoid installing dev-dependencies if possible -Z binary-dep-depinfo Track changes to dependency artifacts -Z bindeps Allow Cargo packages to depend on bin, cdylib, and staticlib crates, and use the artifacts built by those crates -Z build-std Enable Cargo to compile the standard library itself as part of a crate graph compilation -Z build-std-features Configure features enabled for the standard library itself when building the standard library -Z cargo-lints Enable the `[lints.cargo]` table -Z checksum-freshness Use a checksum to determine if output is fresh rather than filesystem mtime -Z codegen-backend Enable the `codegen-backend` option in profiles in .cargo/config.toml file -Z config-include Enable the `include` key in config files -Z direct-minimal-versions Resolve minimal dependency versions instead of maximum (direct dependencies only) -Z doctest-xcompile Compile and run doctests for non-host target using runner config -Z dual-proc-macros Build proc-macros for both the host and the target -Z gc Track cache usage and "garbage collect" unused files -Z git Enable support for shallow git fetch operations -Z gitoxide Use gitoxide for the given git interactions, or all of them if no argument is given -Z host-config Enable the `[host]` section in the .cargo/config.toml file -Z minimal-versions Resolve minimal dependency versions instead of maximum -Z msrv-policy Enable rust-version aware policy within cargo -Z mtime-on-use Configure Cargo to update the mtime of used files -Z no-index-update Do not update the registry index even if the cache is outdated -Z package-workspace Handle intra-workspace dependencies when packaging -Z panic-abort-tests Enable support to run tests with -Cpanic=abort -Z profile-rustflags Enable the `rustflags` option in profiles in .cargo/config.toml file -Z public-dependency Respect a dependency's `public` field in Cargo.toml to control public/private dependencies -Z publish-timeout Enable the `publish.timeout` key in .cargo/config.toml file -Z root-dir Set the root directory relative to which paths are printed (defaults to workspace root) -Z rustdoc-map Allow passing external documentation mappings to rustdoc -Z rustdoc-scrape-examples Allows Rustdoc to scrape code examples from reverse-dependencies -Z script Enable support for single-file, `.rs` packages -Z target-applies-to-host Enable the `target-applies-to-host` key in the .cargo/config.toml file -Z trim-paths Enable the `trim-paths` option in profiles -Z unstable-options Allow the usage of unstable options -Z warnings Allow use of the build.warnings config key Run with `cargo -Z [FLAG] [COMMAND]` See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html for more information about these flags. cargo-0.86.0/tests/testsuite/cargo_add/add_basic/mod.rs000064400000000000000000000020301046102023000211210ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/add_basic/stderr.term.svg000064400000000000000000000017641046102023000230030ustar 00000000000000 Updating `dummy-registry` index Adding my-package v99999.0.0 to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/add_multiple/mod.rs000064400000000000000000000022001046102023000216720ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package1 my-package2") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/add_multiple/stderr.term.svg000064400000000000000000000022071046102023000235460ustar 00000000000000 Updating `dummy-registry` index Adding my-package1 v99999.0.0 to dependencies Adding my-package2 v99999.0.0 to dependencies Locking 2 packages to latest compatible versions cargo-0.86.0/tests/testsuite/cargo_add/add_no_vendored_package_with_alter_registry/mod.rs000064400000000000000000000021361046102023000301760ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::alt_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", &[]) .alternative(true) .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("linked_hash_map --registry alternative") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/add_no_vendored_package_with_alter_registry/stderr.term.svg000064400000000000000000000042661046102023000320510ustar 00000000000000 Updating `alternative` index warning: translating `linked_hash_map` to `linked-hash-map` Adding linked-hash-map v0.5.4 to dependencies Features: - clippy - heapsize - heapsize_impl - nightly - serde - serde_impl - serde_test Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/add_no_vendored_package_with_vendor/mod.rs000064400000000000000000000012461046102023000264350ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cbindgen") .current_dir(cwd) .assert() .failure() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/add_no_vendored_package_with_vendor/stderr.term.svg000064400000000000000000000014171046102023000303020ustar 00000000000000 error: the crate `cbindgen` could not be found in registry index. cargo-0.86.0/tests/testsuite/cargo_add/add_toolchain/mod.rs000064400000000000000000000012461046102023000220300ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("+nightly") .current_dir(cwd) .assert() .failure() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/add_toolchain/stderr.term.svg000064400000000000000000000016101046102023000236700ustar 00000000000000 error: invalid character `+` in dependency name: `+nightly` Use `cargo +nightly add` if you meant to use the `nightly` toolchain. cargo-0.86.0/tests/testsuite/cargo_add/build/mod.rs000064400000000000000000000022401046102023000203320ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("--build my-build-package1 my-build-package2") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/build/stderr.term.svg000064400000000000000000000022371046102023000222050ustar 00000000000000 Updating `dummy-registry` index Adding my-build-package1 v99999.0.0 to build-dependencies Adding my-build-package2 v99999.0.0 to build-dependencies Locking 2 packages to latest compatible versions cargo-0.86.0/tests/testsuite/cargo_add/build_prefer_existing_version/mod.rs000064400000000000000000000022001046102023000253500ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo-list-test-fixture-dependency --build") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/build_prefer_existing_version/stderr.term.svg000064400000000000000000000023621046102023000272260ustar 00000000000000 Adding cargo-list-test-fixture-dependency (local) to build-dependencies Features: - one - two Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/change_rename_target/mod.rs000064400000000000000000000022121046102023000233540ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package2 --rename some-package") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/change_rename_target/stderr.term.svg000064400000000000000000000021761046102023000252320ustar 00000000000000 Updating `dummy-registry` index Adding my-package2 v99999.0.0 to optional dependencies Adding feature `some-package` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/cyclic_features/mod.rs000064400000000000000000000017421046102023000224050ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("test_cyclic_features") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/cyclic_features/stderr.term.svg000064400000000000000000000025221046102023000242470ustar 00000000000000 Updating `dummy-registry` index Adding test_cyclic_features v0.1.1 to dependencies Features: + feature-one + feature-two Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/default_features/mod.rs000064400000000000000000000022311046102023000225550ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package1 my-package2@0.4.1 --default-features") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/default_features/stderr.term.svg000064400000000000000000000026211046102023000244250ustar 00000000000000 Updating `dummy-registry` index Adding my-package1 v99999.0.0 to dependencies Adding my-package2 v0.4.1 to dependencies Locking 2 packages to latest compatible versions Adding my-package2 v0.4.1+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/deprecated_default_features/mod.rs000064400000000000000000000020311046102023000247330ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package") .current_dir(&cwd) .assert() .failure() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/deprecated_default_features/stderr.term.svg000064400000000000000000000014621046102023000266070ustar 00000000000000 error: Use of `default_features` in `my-package` is unsupported, please switch to `default-features` cargo-0.86.0/tests/testsuite/cargo_add/deprecated_section/mod.rs000064400000000000000000000020311046102023000230550ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package") .current_dir(&cwd) .assert() .failure() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/deprecated_section/stderr.term.svg000064400000000000000000000014511046102023000247270ustar 00000000000000 error: Deprecated dependency sections are unsupported: dev_dependencies, build_dependencies cargo-0.86.0/tests/testsuite/cargo_add/detect_workspace_inherit/mod.rs000064400000000000000000000013271046102023000243100ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["foo", "-p", "bar"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/detect_workspace_inherit/stderr.term.svg000064400000000000000000000013421046102023000261520ustar 00000000000000 Adding foo (workspace) to dependencies cargo-0.86.0/tests/testsuite/cargo_add/detect_workspace_inherit_features/mod.rs000064400000000000000000000013551046102023000262070ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["foo", "-p", "bar", "--features", "test"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/detect_workspace_inherit_features/stderr.term.svg000064400000000000000000000035731046102023000300600ustar 00000000000000 Adding foo (workspace) to dependencies Features as of v0.0.0: + default-base + default-merge-base + default-test-base + merge + merge-base + test + test-base - unrelated cargo-0.86.0/tests/testsuite/cargo_add/detect_workspace_inherit_optional/mod.rs000064400000000000000000000013451046102023000262150ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["foo", "-p", "bar", "--optional"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/detect_workspace_inherit_optional/stderr.term.svg000064400000000000000000000015401046102023000300570ustar 00000000000000 Adding foo (workspace) to optional dependencies Adding feature `foo` cargo-0.86.0/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/mod.rs000064400000000000000000000014141046102023000263130ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["foo", "-p", "bar"]) .current_dir(cwd) .masquerade_as_nightly_cargo(&["path-base"]) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/detect_workspace_inherit_path_base/stderr.term.svg000064400000000000000000000013421046102023000301600ustar 00000000000000 Adding foo (workspace) to dependencies cargo-0.86.0/tests/testsuite/cargo_add/detect_workspace_inherit_public/mod.rs000064400000000000000000000014401046102023000256420ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["foo", "-p", "bar", "--public"]) .masquerade_as_nightly_cargo(&["public-dependency"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/detect_workspace_inherit_public/stderr.term.svg000064400000000000000000000013511046102023000275100ustar 00000000000000 Adding foo (workspace) to public dependencies cargo-0.86.0/tests/testsuite/cargo_add/dev/mod.rs000064400000000000000000000022261046102023000200150ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("--dev my-dev-package1 my-dev-package2") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/dev/stderr.term.svg000064400000000000000000000022271046102023000216630ustar 00000000000000 Updating `dummy-registry` index Adding my-dev-package1 v99999.0.0 to dev-dependencies Adding my-dev-package2 v99999.0.0 to dev-dependencies Locking 2 packages to latest compatible versions cargo-0.86.0/tests/testsuite/cargo_add/dev_build_conflict/mod.rs000064400000000000000000000020441046102023000230530ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --dev --build") .current_dir(cwd) .assert() .code(1) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/dev_build_conflict/stderr.term.svg000064400000000000000000000041141046102023000247200ustar 00000000000000 error: the argument '--dev' cannot be used with '--build' Usage: cargo add [OPTIONS] <DEP>[@<VERSION>] ... cargo add [OPTIONS] --path <PATH> ... cargo add [OPTIONS] --git <URL> ... For more information, try '--help'. cargo-0.86.0/tests/testsuite/cargo_add/dev_existing_path_base/in/.cargo/config.toml000064400000000000000000000000331046102023000265230ustar 00000000000000[path-bases] my_base = "." cargo-0.86.0/tests/testsuite/cargo_add/dev_existing_path_base/mod.rs000064400000000000000000000014131046102023000237320ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo-list-test-fixture-dependency --dev") .current_dir(&cwd) .masquerade_as_nightly_cargo(&["path-base"]) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/dev_existing_path_base/stderr.term.svg000064400000000000000000000016171046102023000256050ustar 00000000000000 Adding cargo-list-test-fixture-dependency (local) to dev-dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/dev_prefer_existing_version/mod.rs000064400000000000000000000021761046102023000250430ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo-list-test-fixture-dependency --dev") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/dev_prefer_existing_version/stderr.term.svg000064400000000000000000000023751046102023000267110ustar 00000000000000 Adding cargo-list-test-fixture-dependency (local) to dev-dependencies Features as of v0.0.0: - one - two Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/dry_run/mod.rs000064400000000000000000000020421046102023000207150ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --dry-run") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/dry_run/stderr.term.svg000064400000000000000000000020431046102023000225630ustar 00000000000000 Updating `dummy-registry` index Adding my-package v99999.0.0 to dependencies warning: aborting add due to dry run cargo-0.86.0/tests/testsuite/cargo_add/empty_dep_name/mod.rs000064400000000000000000000013161046102023000222240ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("@1.2.3") .current_dir(cwd) .assert() .failure() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/empty_dep_name/stderr.term.svg000064400000000000000000000013611046102023000240710ustar 00000000000000 error: package name cannot be empty cargo-0.86.0/tests/testsuite/cargo_add/features/mod.rs000064400000000000000000000017031046102023000210540ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("your-face --features eyes") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/features/stderr.term.svg000064400000000000000000000031221046102023000227160ustar 00000000000000 Updating `dummy-registry` index Adding your-face v99999.0.0 to dependencies Features: + eyes - ears - mouth - nose Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/features_activated_over_limit/mod.rs000064400000000000000000000023361046102023000253340ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; use itertools::Itertools; #[cargo_test] fn case() { const MANY_FEATURES_COUNT: usize = 200; const ACTIVATED_FEATURES_COUNT: usize = 100; cargo_test_support::registry::init(); let mut test_package = cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package"); for i in 0..MANY_FEATURES_COUNT { test_package.feature(format!("eyes{i:03}").as_str(), &[]); } test_package.publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let features = (0..ACTIVATED_FEATURES_COUNT) .map(|i| format!("eyes{i:03}")) .join(","); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line(format!("your-face --features {features}").as_str()) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/features_activated_over_limit/stderr.term.svg000064400000000000000000000023671046102023000272050ustar 00000000000000 Updating `dummy-registry` index Adding your-face v99999.0.0 to dependencies Features: 100 activated features 100 deactivated features Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/features_deactivated_over_limit/mod.rs000064400000000000000000000023351046102023000256440ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; use itertools::Itertools; #[cargo_test] fn case() { const MANY_FEATURES_COUNT: usize = 200; const ACTIVATED_FEATURES_COUNT: usize = 30; cargo_test_support::registry::init(); let mut test_package = cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package"); for i in 0..MANY_FEATURES_COUNT { test_package.feature(format!("eyes{i:03}").as_str(), &[]); } test_package.publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let features = (0..ACTIVATED_FEATURES_COUNT) .map(|i| format!("eyes{i:03}")) .join(","); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line(format!("your-face --features {features}").as_str()) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/features_deactivated_over_limit/stderr.term.svg000064400000000000000000000116731046102023000275160ustar 00000000000000 Updating `dummy-registry` index Adding your-face v99999.0.0 to dependencies Features: + eyes000 + eyes001 + eyes002 + eyes003 + eyes004 + eyes005 + eyes006 + eyes007 + eyes008 + eyes009 + eyes010 + eyes011 + eyes012 + eyes013 + eyes014 + eyes015 + eyes016 + eyes017 + eyes018 + eyes019 + eyes020 + eyes021 + eyes022 + eyes023 + eyes024 + eyes025 + eyes026 + eyes027 + eyes028 + eyes029 170 deactivated features Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/features_empty/mod.rs000064400000000000000000000017011046102023000222700ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("your-face --features ''") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/features_empty/stderr.term.svg000064400000000000000000000031201046102023000241320ustar 00000000000000 Updating `dummy-registry` index Adding your-face v99999.0.0 to dependencies Features: - ears - eyes - mouth - nose Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/features_multiple_occurrences/mod.rs000064400000000000000000000017231046102023000253640ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("your-face --features eyes --features nose") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/features_multiple_occurrences/stderr.term.svg000064400000000000000000000031241046102023000272260ustar 00000000000000 Updating `dummy-registry` index Adding your-face v99999.0.0 to dependencies Features: + eyes + nose - ears - mouth Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/features_preserve/mod.rs000064400000000000000000000016631046102023000227740ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("your-face") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/features_preserve/stderr.term.svg000064400000000000000000000031221046102023000246310ustar 00000000000000 Updating `dummy-registry` index Adding your-face v99999.0.0 to dependencies Features: + eyes - ears - mouth - nose Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/features_spaced_values/mod.rs000064400000000000000000000017101046102023000237500ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("your-face --features eyes,nose") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/features_spaced_values/stderr.term.svg000064400000000000000000000031241046102023000256160ustar 00000000000000 Updating `dummy-registry` index Adding your-face v99999.0.0 to dependencies Features: + eyes + nose - ears - mouth Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/features_unknown/mod.rs000064400000000000000000000017031046102023000226330ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("your-face --features noze") .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/features_unknown/stderr.term.svg000064400000000000000000000023111046102023000244740ustar 00000000000000 Updating `dummy-registry` index Adding your-face v99999.0.0 to dependencies error: unrecognized feature for crate your-face: noze disabled features: ears, eyes, mouth, nose cargo-0.86.0/tests/testsuite/cargo_add/features_unknown_no_features/mod.rs000064400000000000000000000020501046102023000252210ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --features noze") .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/features_unknown_no_features/stderr.term.svg000064400000000000000000000022211046102023000270660ustar 00000000000000 Updating `dummy-registry` index Adding my-package v99999.0.0 to dependencies error: unrecognized feature for crate my-package: noze no features available for crate my-package cargo-0.86.0/tests/testsuite/cargo_add/git/mod.rs000064400000000000000000000020601046102023000200160ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let git_dep = cargo_test_support::git::new("git-package", |project| { project .file( "Cargo.toml", &cargo_test_support::basic_manifest("git-package", "0.3.0+git-package"), ) .file("src/lib.rs", "") }); let git_url = git_dep.url().to_string(); snapbox::cmd::Command::cargo_ui() .arg("add") .args(["git-package", "--git", &git_url]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/git/stderr.term.svg000064400000000000000000000022201046102023000216610ustar 00000000000000 Updating git repository `[ROOTURL]/git-package` Adding git-package (git) to dependencies Updating git repository `[ROOTURL]/git-package` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/git_branch/mod.rs000064400000000000000000000023651046102023000213430ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let (git_dep, git_repo) = cargo_test_support::git::new_repo("git-package", |project| { project .file( "Cargo.toml", &cargo_test_support::basic_manifest("git-package", "0.3.0+git-package"), ) .file("src/lib.rs", "") }); let branch = "dev"; let find_head = || (git_repo.head().unwrap().peel_to_commit().unwrap()); git_repo.branch(branch, &find_head(), false).unwrap(); let git_url = git_dep.url().to_string(); snapbox::cmd::Command::cargo_ui() .arg("add") .args(["git-package", "--git", &git_url, "--branch", branch]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/git_branch/stderr.term.svg000064400000000000000000000022201046102023000231760ustar 00000000000000 Updating git repository `[ROOTURL]/git-package` Adding git-package (git) to dependencies Updating git repository `[ROOTURL]/git-package` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/git_conflicts_namever/mod.rs000064400000000000000000000021721046102023000236030ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args([ "my-package@0.4.3", "--git", "https://github.com/dcjanus/invalid", ]) .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/git_conflicts_namever/stderr.term.svg000064400000000000000000000014561046102023000254540ustar 00000000000000 error: cannot specify a git URL (`https://github.com/dcjanus/invalid`) with a version (`0.4.3`). cargo-0.86.0/tests/testsuite/cargo_add/git_dev/mod.rs000064400000000000000000000020711046102023000206560ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let git_dep = cargo_test_support::git::new("git-package", |project| { project .file( "Cargo.toml", &cargo_test_support::basic_manifest("git-package", "0.3.0+git-package"), ) .file("src/lib.rs", "") }); let git_url = git_dep.url().to_string(); snapbox::cmd::Command::cargo_ui() .arg("add") .args(["git-package", "--git", &git_url, "--dev"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/git_dev/stderr.term.svg000064400000000000000000000022241046102023000225230ustar 00000000000000 Updating git repository `[ROOTURL]/git-package` Adding git-package (git) to dev-dependencies Updating git repository `[ROOTURL]/git-package` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/git_inferred_name/mod.rs000064400000000000000000000020411046102023000226730ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let git_dep = cargo_test_support::git::new("git-package", |project| { project .file( "Cargo.toml", &cargo_test_support::basic_manifest("git-package", "0.3.0+git-package"), ) .file("src/lib.rs", "") }); let git_url = git_dep.url().to_string(); snapbox::cmd::Command::cargo_ui() .arg("add") .args(["--git", &git_url]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/git_inferred_name/stderr.term.svg000064400000000000000000000024371046102023000245510ustar 00000000000000 Updating git repository `[ROOTURL]/git-package` Updating git repository `[ROOTURL]/git-package` Adding git-package (git) to dependencies Updating git repository `[ROOTURL]/git-package` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/git_inferred_name_multiple/mod.rs000064400000000000000000000050671046102023000246210ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let git_dep = cargo_test_support::git::new("git-package", |project| { project .file( "p1/Cargo.toml", &cargo_test_support::basic_manifest("my-package1", "0.3.0+my-package1"), ) .file("p1/src/lib.rs", "") .file( "p2/Cargo.toml", &cargo_test_support::basic_manifest("my-package2", "0.3.0+my-package2"), ) .file("p2/src/lib.rs", "") .file( "p3/Cargo.toml", &cargo_test_support::basic_manifest("my-package3", "0.3.0+my-package2"), ) .file("p3/src/lib.rs", "") .file( "p4/Cargo.toml", &cargo_test_support::basic_manifest("my-package4", "0.3.0+my-package2"), ) .file("p4/src/lib.rs", "") .file( "p5/Cargo.toml", &cargo_test_support::basic_manifest("my-package5", "0.3.0+my-package2"), ) .file("p5/src/lib.rs", "") .file( "p6/Cargo.toml", &cargo_test_support::basic_manifest("my-package6", "0.3.0+my-package2"), ) .file("p6/src/lib.rs", "") .file( "p7/Cargo.toml", &cargo_test_support::basic_manifest("my-package7", "0.3.0+my-package2"), ) .file("p7/src/lib.rs", "") .file( "p8/Cargo.toml", &cargo_test_support::basic_manifest("my-package8", "0.3.0+my-package2"), ) .file("p8/src/lib.rs", "") .file( "p9/Cargo.toml", &cargo_test_support::basic_manifest("my-package9", "0.3.0+my-package2"), ) .file("p9/src/lib.rs", "") }); let git_url = git_dep.url().to_string(); snapbox::cmd::Command::cargo_ui() .arg("add") .args(["--git", &git_url]) .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/git_inferred_name_multiple/stderr.term.svg000064400000000000000000000024411046102023000264570ustar 00000000000000 Updating git repository `[ROOTURL]/git-package` error: multiple packages found at `[ROOTURL]/git-package`: my-package1, my-package2, my-package3, my-package4, my-package5, my-package6 my-package7, my-package8, my-package9 To disambiguate, run `cargo add --git [ROOTURL]/git-package <package>` cargo-0.86.0/tests/testsuite/cargo_add/git_multiple_names/mod.rs000064400000000000000000000032471046102023000231240ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let git_dep = cargo_test_support::git::new("git-package", |project| { project .file( "p1/Cargo.toml", &cargo_test_support::basic_manifest("my-package1", "0.3.0+my-package1"), ) .file("p1/src/lib.rs", "") .file( "p2/Cargo.toml", &cargo_test_support::basic_manifest("my-package2", "0.3.0+my-package2"), ) .file("p2/src/lib.rs", "") }); let git_url = git_dep.url().to_string(); snapbox::cmd::Command::cargo_ui() .arg("add") .args(["my-package1", "my-package2", "--git", &git_url]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/git_multiple_names/stderr.term.svg000064400000000000000000000024341046102023000247660ustar 00000000000000 Updating git repository `[ROOTURL]/git-package` Adding my-package1 (git) to dependencies Adding my-package2 (git) to dependencies Updating git repository `[ROOTURL]/git-package` Locking 2 packages to latest compatible versions cargo-0.86.0/tests/testsuite/cargo_add/git_multiple_packages_features/mod.rs000064400000000000000000000034521046102023000254730ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let main_manifest = r#" [package] name = "main-package" version = "0.1.1+main-package" authors = [] [workspace] members = ["package-wo-feature", "package-with-feature"] "#; let manifest_feature = r#" [package] name = "package-with-feature" version = "0.1.3+package-with-feature" [features] target_feature = [] "#; let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let git_dep = cargo_test_support::git::new("git-package", |project| { project .file("Cargo.toml", &main_manifest) .file( "package-wo-feature/Cargo.toml", &cargo_test_support::basic_manifest( "package-wo-feature", "0.1.1+package-wo-feature", ), ) .file("package-wo-feature/src/lib.rs", "") .file("package-with-feature/Cargo.toml", &manifest_feature) .file("package-with-feature/src/lib.rs", "") }); let git_url = git_dep.url().to_string(); snapbox::cmd::Command::cargo_ui() .arg("add") .args([ "--git", &git_url, "package-with-feature", "--features=target_feature", ]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/git_multiple_packages_features/stderr.term.svg000064400000000000000000000025561046102023000273440ustar 00000000000000 Updating git repository `[ROOTURL]/git-package` Adding package-with-feature (git) to dependencies Features: + target_feature Updating git repository `[ROOTURL]/git-package` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/git_registry/mod.rs000064400000000000000000000030501046102023000217460ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let git_dep = cargo_test_support::git::new("versioned-package", |project| { project .file( "Cargo.toml", &cargo_test_support::basic_manifest("versioned-package", "0.3.0+versioned-package"), ) .file("src/lib.rs", "") }); let git_url = git_dep.url().to_string(); snapbox::cmd::Command::cargo_ui() .arg("add") .args([ "versioned-package", "--git", &git_url, "--registry", "alternative", ]) .current_dir(cwd) .assert() .failure() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/git_registry/stderr.term.svg000064400000000000000000000025251046102023000236210ustar 00000000000000 Updating git repository `[ROOTURL]/versioned-package` Adding versioned-package (git) to dependencies error: failed to parse manifest at `[ROOT]/case/Cargo.toml` Caused by: dependency (versioned-package) specification is ambiguous. Only one of `git` or `registry` is allowed. cargo-0.86.0/tests/testsuite/cargo_add/git_rev/mod.rs000064400000000000000000000023131046102023000206730ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let (git_dep, git_repo) = cargo_test_support::git::new_repo("git-package", |project| { project .file( "Cargo.toml", &cargo_test_support::basic_manifest("git-package", "0.3.0+git-package"), ) .file("src/lib.rs", "") }); let find_head = || (git_repo.head().unwrap().peel_to_commit().unwrap()); let head = find_head().id().to_string(); let git_url = git_dep.url().to_string(); snapbox::cmd::Command::cargo_ui() .arg("add") .args(["git-package", "--git", &git_url, "--rev", &head]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/git_rev/stderr.term.svg000064400000000000000000000022201046102023000225350ustar 00000000000000 Updating git repository `[ROOTURL]/git-package` Adding git-package (git) to dependencies Updating git repository `[ROOTURL]/git-package` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/git_tag/mod.rs000064400000000000000000000022311046102023000206510ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let (git_dep, git_repo) = cargo_test_support::git::new_repo("git-package", |project| { project .file( "Cargo.toml", &cargo_test_support::basic_manifest("git-package", "0.3.0+git-package"), ) .file("src/lib.rs", "") }); let tag = "v1.0.0"; cargo_test_support::git::tag(&git_repo, tag); let git_url = git_dep.url().to_string(); snapbox::cmd::Command::cargo_ui() .arg("add") .args(["git-package", "--git", &git_url, "--tag", tag]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/git_tag/stderr.term.svg000064400000000000000000000022201046102023000225140ustar 00000000000000 Updating git repository `[ROOTURL]/git-package` Adding git-package (git) to dependencies Updating git repository `[ROOTURL]/git-package` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/help/mod.rs000064400000000000000000000004751046102023000201730ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("add") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_add/help/stdout.term.svg000064400000000000000000000356021046102023000220570ustar 00000000000000 Add dependencies to a Cargo.toml manifest file Usage: cargo add [OPTIONS] <DEP>[@<VERSION>] ... cargo add [OPTIONS] --path <PATH> ... cargo add [OPTIONS] --git <URL> ... Arguments: [DEP_ID]... Reference to a package to add as a dependency You can reference a package by: - `<name>`, like `cargo add serde` (latest version will be used) - `<name>@<version-req>`, like `cargo add serde@1` or `cargo add serde@=1.0.38` Options: --no-default-features Disable the default features --default-features Re-enable the default features -F, --features <FEATURES> Space or comma separated list of features to activate --optional Mark the dependency as optional The package name will be exposed as feature of your crate. --no-optional Mark the dependency as required The package will be removed from your features. --public Mark the dependency as public (unstable) The dependency can be referenced in your library's public API. --no-public Mark the dependency as private (unstable) While you can use the crate in your implementation, it cannot be referenced in your public API. --rename <NAME> Rename the dependency Example uses: - Depending on multiple versions of a crate - Depend on crates with the same name from different registries -n, --dry-run Don't actually write the manifest -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help (see a summary with '-h') Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --ignore-rust-version Ignore `rust-version` specification in packages --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Package Selection: -p, --package [<SPEC>] Package to modify Source: --path <PATH> Filesystem path to local crate to add --base <BASE> The path base to use when adding from a local crate (unstable). --git <URI> Git repository location Without any other information, cargo will use latest commit on the main branch. --branch <BRANCH> Git branch to download the crate from --tag <TAG> Git tag to download the crate from --rev <REV> Git reference to download the crate from This is the catch all, handling hashes to named references in remote repositories. --registry <NAME> Package registry for this dependency Section: --dev Add as development dependency Dev-dependencies are not used when compiling a package for building, but are used for compiling tests, examples, and benchmarks. These dependencies are not propagated to other packages which depend on this package. --build Add as build dependency Build-dependencies are the only dependencies available for use by build scripts (`build.rs` files). --target <TARGET> Add as dependency to the given target platform Run `cargo help add` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_add/infer_prerelease/mod.rs000064400000000000000000000014661046102023000225560ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("prerelease_only", "0.2.0-alpha.1").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("prerelease_only") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/infer_prerelease/stderr.term.svg000064400000000000000000000017751046102023000244260ustar 00000000000000 Updating `dummy-registry` index Adding prerelease_only v0.2.0-alpha.1 to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/invalid_arg/mod.rs000064400000000000000000000020351046102023000215140ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --flag") .current_dir(cwd) .assert() .code(1) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/invalid_arg/stderr.term.svg000064400000000000000000000043651046102023000233710ustar 00000000000000 error: unexpected argument '--flag' found tip: a similar argument exists: '--tag' Usage: cargo add [OPTIONS] <DEP>[@<VERSION>] ... cargo add [OPTIONS] --path <PATH> ... cargo add [OPTIONS] --git <URL> ... For more information, try '--help'. cargo-0.86.0/tests/testsuite/cargo_add/invalid_git_name/mod.rs000064400000000000000000000020571046102023000225320ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let git_dep = cargo_test_support::git::new("git-package", |project| { project .file( "Cargo.toml", &cargo_test_support::basic_manifest("git-package", "0.3.0+git-package"), ) .file("src/lib.rs", "") }); let git_url = git_dep.url().to_string(); snapbox::cmd::Command::cargo_ui() .arg("add") .args(["not-in-git", "--git", &git_url]) .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/invalid_git_name/stderr.term.svg000064400000000000000000000017361046102023000244020ustar 00000000000000 Updating git repository `[ROOTURL]/git-package` error: the crate `not-in-git@[ROOTURL]/git-package` could not be found at `[ROOTURL]/git-package` cargo-0.86.0/tests/testsuite/cargo_add/invalid_key_inherit_dependency/mod.rs000064400000000000000000000013021046102023000254470ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["foo", "--default-features", "-p", "bar"]) .current_dir(cwd) .assert() .failure() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/invalid_key_inherit_dependency/stderr.term.svg000064400000000000000000000016201046102023000273170ustar 00000000000000 error: cannot override workspace dependency with `--default-features`, either change `workspace.dependencies.foo.default-features` or define the dependency exclusively in the package's manifest cargo-0.86.0/tests/testsuite/cargo_add/invalid_key_overwrite_inherit_dependency/mod.rs000064400000000000000000000013021046102023000275550ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["foo", "--default-features", "-p", "bar"]) .current_dir(cwd) .assert() .failure() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/invalid_key_overwrite_inherit_dependency/stderr.term.svg000064400000000000000000000016201046102023000314250ustar 00000000000000 error: cannot override workspace dependency with `--default-features`, either change `workspace.dependencies.foo.default-features` or define the dependency exclusively in the package's manifest cargo-0.86.0/tests/testsuite/cargo_add/invalid_key_rename_inherit_dependency/mod.rs000064400000000000000000000013031046102023000267770ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["--rename", "foo", "foo-alt", "-p", "bar"]) .current_dir(cwd) .assert() .failure() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/invalid_key_rename_inherit_dependency/stderr.term.svg000064400000000000000000000015751046102023000306570ustar 00000000000000 error: cannot override workspace dependency with `--rename`, either change `workspace.dependencies.foo.package` or define the dependency exclusively in the package's manifest cargo-0.86.0/tests/testsuite/cargo_add/invalid_manifest/mod.rs000064400000000000000000000020301046102023000225440ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package") .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/invalid_manifest/stderr.term.svg000064400000000000000000000026371046102023000244260ustar 00000000000000 error: invalid string expected `"`, `'` --> Cargo.toml:9:7 | 9 | key = invalid-value | ^ | cargo-0.86.0/tests/testsuite/cargo_add/invalid_name_external/mod.rs000064400000000000000000000013631046102023000235700ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("lets_hope_nobody_ever_publishes_this_crate") .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/invalid_name_external/stderr.term.svg000064400000000000000000000017171046102023000254400ustar 00000000000000 Updating `dummy-registry` index error: the crate `lets_hope_nobody_ever_publishes_this_crate` could not be found in registry index. cargo-0.86.0/tests/testsuite/cargo_add/invalid_path/mod.rs000064400000000000000000000013761046102023000217060ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo-list-test-fixture --path ./tests/fixtures/local") .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/invalid_path/stderr.term.svg000064400000000000000000000025511046102023000235470ustar 00000000000000 error: failed to load source for dependency `cargo-list-test-fixture` Caused by: Unable to update [ROOT]/case/tests/fixtures/local Caused by: failed to read `[ROOT]/case/tests/fixtures/local/Cargo.toml` Caused by: [..] cargo-0.86.0/tests/testsuite/cargo_add/invalid_path_name/mod.rs000064400000000000000000000021431046102023000226770ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("not-at-path --path ../dependency") .current_dir(&cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/invalid_path_name/stderr.term.svg000064400000000000000000000014631046102023000245500ustar 00000000000000 error: the crate `not-at-path@[ROOT]/case/dependency` could not be found at `[ROOT]/case/dependency` cargo-0.86.0/tests/testsuite/cargo_add/invalid_path_self/mod.rs000064400000000000000000000013511046102023000227100ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo-list-test-fixture --path .") .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/invalid_path_self/stderr.term.svg000064400000000000000000000017121046102023000245560ustar 00000000000000 Adding cargo-list-test-fixture (local) to dependencies error: cannot add `cargo-list-test-fixture` as a dependency to itself cargo-0.86.0/tests/testsuite/cargo_add/invalid_target_empty/mod.rs000064400000000000000000000020421046102023000234450ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --target ''") .current_dir(cwd) .assert() .code(1) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/invalid_target_empty/stderr.term.svg000064400000000000000000000020501046102023000253110ustar 00000000000000 error: a value is required for '--target <TARGET>' but none was supplied For more information, try '--help'. cargo-0.86.0/tests/testsuite/cargo_add/invalid_vers/mod.rs000064400000000000000000000020571046102023000217260ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package@invalid-version-string") .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/invalid_vers/stderr.term.svg000064400000000000000000000017451046102023000235760ustar 00000000000000 error: invalid version requirement `invalid-version-string` Caused by: unexpected character 'i' while parsing major version number cargo-0.86.0/tests/testsuite/cargo_add/list_features/mod.rs000064400000000000000000000016611046102023000221120ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["your-face"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/list_features/stderr.term.svg000064400000000000000000000031201046102023000237470ustar 00000000000000 Updating `dummy-registry` index Adding your-face v99999.0.0 to dependencies Features: - ears - eyes - mouth - nose Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/list_features_path/mod.rs000064400000000000000000000024351046102023000231260ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("your-face --path ../dependency") .current_dir(&cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/list_features_path/stderr.term.svg000064400000000000000000000035551046102023000247770ustar 00000000000000 Adding your-face (local) to dependencies Features: + mouth + nose - eyes - optional-dependency Updating `dummy-registry` index Locking 1 package to latest compatible version Adding my-package v0.1.1+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/list_features_path_no_default/mod.rs000064400000000000000000000025651046102023000253320ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .args([ "your-face", "--path", "../dependency", "--no-default-features", ]) .current_dir(&cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/list_features_path_no_default/stderr.term.svg000064400000000000000000000035511046102023000271730ustar 00000000000000 Adding your-face (local) to dependencies Features: - eyes - mouth - nose - optional-dependency Updating `dummy-registry` index Locking 1 package to latest compatible version Adding my-package v0.1.1+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/locked_changed/mod.rs000064400000000000000000000020411046102023000221440ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --locked") .current_dir(cwd) .assert() .failure() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/locked_changed/stderr.term.svg000064400000000000000000000021451046102023000240160ustar 00000000000000 Updating `dummy-registry` index Adding my-package v99999.0.0 to dependencies error: the manifest file [ROOT]/case/Cargo.toml needs to be updated but --locked was passed to prevent this cargo-0.86.0/tests/testsuite/cargo_add/locked_unchanged/mod.rs000064400000000000000000000020411046102023000225070ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --locked") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/locked_unchanged/stderr.term.svg000064400000000000000000000015461046102023000243650ustar 00000000000000 Updating `dummy-registry` index Adding my-package v99999.0.0 to dependencies cargo-0.86.0/tests/testsuite/cargo_add/lockfile_updated/mod.rs000064400000000000000000000021671046102023000225410ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/lockfile_updated/stderr.term.svg000064400000000000000000000022341046102023000244010ustar 00000000000000 Updating `dummy-registry` index Adding my-package v99999.0.0 to dependencies Locking 1 package to latest compatible version Adding my-package v99999.0.0+my-package cargo-0.86.0/tests/testsuite/cargo_add/manifest_path_package/mod.rs000064400000000000000000000023431046102023000235340ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args([ "--manifest-path", "Cargo.toml", "--package", "cargo-list-test-fixture", "cargo-list-test-fixture-dependency", ]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/manifest_path_package/stderr.term.svg000064400000000000000000000013751046102023000254050ustar 00000000000000 Adding cargo-list-test-fixture-dependency (local) to dependencies cargo-0.86.0/tests/testsuite/cargo_add/merge_activated_features/mod.rs000064400000000000000000000012541046102023000242600ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["foo", "-p", "bar"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/merge_activated_features/stderr.term.svg000064400000000000000000000035731046102023000261330ustar 00000000000000 Adding foo (workspace) to dependencies Features as of v0.0.0: + default-base + default-merge-base + default-test-base + merge + merge-base + test + test-base - unrelated cargo-0.86.0/tests/testsuite/cargo_add/mod.rs000064400000000000000000000076771046102023000172560ustar 00000000000000mod add_basic; mod add_multiple; mod add_no_vendored_package_with_alter_registry; mod add_no_vendored_package_with_vendor; mod add_toolchain; mod build; mod build_prefer_existing_version; mod change_rename_target; mod cyclic_features; mod default_features; mod deprecated_default_features; mod deprecated_section; mod detect_workspace_inherit; mod detect_workspace_inherit_features; mod detect_workspace_inherit_optional; mod detect_workspace_inherit_path_base; mod detect_workspace_inherit_public; mod dev; mod dev_build_conflict; mod dev_existing_path_base; mod dev_prefer_existing_version; mod dry_run; mod empty_dep_name; mod features; mod features_activated_over_limit; mod features_deactivated_over_limit; mod features_empty; mod features_multiple_occurrences; mod features_preserve; mod features_spaced_values; mod features_unknown; mod features_unknown_no_features; mod git; mod git_branch; mod git_conflicts_namever; mod git_dev; mod git_inferred_name; mod git_inferred_name_multiple; mod git_multiple_names; mod git_multiple_packages_features; mod git_registry; mod git_rev; mod git_tag; mod help; mod infer_prerelease; mod invalid_arg; mod invalid_git_name; mod invalid_key_inherit_dependency; mod invalid_key_overwrite_inherit_dependency; mod invalid_key_rename_inherit_dependency; mod invalid_manifest; mod invalid_name_external; mod invalid_path; mod invalid_path_name; mod invalid_path_self; mod invalid_target_empty; mod invalid_vers; mod list_features; mod list_features_path; mod list_features_path_no_default; mod locked_changed; mod locked_unchanged; mod lockfile_updated; mod manifest_path_package; mod merge_activated_features; mod multiple_conflicts_with_features; mod multiple_conflicts_with_rename; mod namever; mod no_args; mod no_default_features; mod no_optional; mod no_public; mod normalize_name_git; mod normalize_name_path; mod normalize_name_path_existing; mod normalize_name_registry; mod normalize_name_registry_existing; mod normalize_name_registry_yanked; mod normalize_name_workspace_dep; mod offline_empty_cache; mod optional; mod overwrite_default_features; mod overwrite_default_features_with_no_default_features; mod overwrite_features; mod overwrite_git_with_path; mod overwrite_inherit_features_noop; mod overwrite_inherit_noop; mod overwrite_inherit_optional_noop; mod overwrite_inline_features; mod overwrite_name_dev_noop; mod overwrite_name_noop; mod overwrite_no_default_features; mod overwrite_no_default_features_with_default_features; mod overwrite_no_optional; mod overwrite_no_optional_with_optional; mod overwrite_no_public; mod overwrite_no_public_with_public; mod overwrite_optional; mod overwrite_optional_with_no_optional; mod overwrite_optional_with_optional; mod overwrite_path_base_with_version; mod overwrite_path_noop; mod overwrite_path_with_version; mod overwrite_preserves_inline_table; mod overwrite_public; mod overwrite_public_with_no_public; mod overwrite_rename_with_no_rename; mod overwrite_rename_with_rename; mod overwrite_rename_with_rename_noop; mod overwrite_version_with_git; mod overwrite_version_with_path; mod overwrite_with_rename; mod overwrite_workspace_dep; mod overwrite_workspace_dep_features; mod path; mod path_base; mod path_base_inferred_name; mod path_base_missing_base_path; mod path_base_unstable; mod path_dev; mod path_inferred_name; mod path_inferred_name_conflicts_full_feature; mod preserve_dep_std_table; mod preserve_features_sorted; mod preserve_features_table; mod preserve_features_unsorted; mod preserve_sorted; mod preserve_unsorted; mod public; mod quiet; mod registry; mod rename; mod require_weak; mod rust_version_ignore; mod rust_version_incompatible; mod rust_version_latest; mod rust_version_older; mod rustc_ignore; mod rustc_incompatible; mod rustc_latest; mod rustc_older; mod script_bare; mod script_frontmatter; mod script_shebang; mod sorted_table_with_dotted_item; mod target; mod target_cfg; mod unknown_inherited_feature; mod vers; mod workspace_name; mod workspace_path; mod workspace_path_dev; mod yanked; cargo-0.86.0/tests/testsuite/cargo_add/multiple_conflicts_with_features/mod.rs000064400000000000000000000024251046102023000260700ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package1 your-face --features nose") .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/multiple_conflicts_with_features/stderr.term.svg000064400000000000000000000015141046102023000277330ustar 00000000000000 error: feature `nose` must be qualified by the dependency it's being activated for, like `my-package1/nose`, `your-face/nose` cargo-0.86.0/tests/testsuite/cargo_add/multiple_conflicts_with_rename/mod.rs000064400000000000000000000022211046102023000255130ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package1 my-package2 --rename renamed") .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/multiple_conflicts_with_rename/stderr.term.svg000064400000000000000000000014031046102023000273610ustar 00000000000000 error: cannot specify multiple crates with `--rename` cargo-0.86.0/tests/testsuite/cargo_add/namever/mod.rs000064400000000000000000000022471046102023000206770ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package1@>=0.1.1 my-package2@0.2.3 my-package") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/namever/stderr.term.svg000064400000000000000000000030371046102023000225420ustar 00000000000000 Updating `dummy-registry` index Adding my-package1 >=0.1.1 to dependencies Adding my-package2 v0.2.3 to dependencies Adding my-package v99999.0.0 to dependencies Locking 3 packages to latest compatible versions Adding my-package2 v0.2.3+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/no_args/mod.rs000064400000000000000000000012611046102023000206650ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .current_dir(cwd) .assert() .code(1) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/no_args/stderr.term.svg000064400000000000000000000041231046102023000225320ustar 00000000000000 error: the following required arguments were not provided: <DEP_ID|--path <PATH>|--git <URI>> Usage: cargo add [OPTIONS] <DEP>[@<VERSION>] ... cargo add [OPTIONS] --path <PATH> ... cargo add [OPTIONS] --git <URL> ... For more information, try '--help'. cargo-0.86.0/tests/testsuite/cargo_add/no_default_features/mod.rs000064400000000000000000000022341046102023000232540ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package1 my-package2@0.4.1 --no-default-features") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/no_default_features/stderr.term.svg000064400000000000000000000026211046102023000251210ustar 00000000000000 Updating `dummy-registry` index Adding my-package1 v99999.0.0 to dependencies Adding my-package2 v0.4.1 to dependencies Locking 2 packages to latest compatible versions Adding my-package2 v0.4.1+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/no_optional/mod.rs000064400000000000000000000014621046102023000215610ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-package", "0.1.0").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --no-optional") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/no_optional/stderr.term.svg000064400000000000000000000017601046102023000234270ustar 00000000000000 Updating `dummy-registry` index Adding my-package v0.1.0 to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/no_public/mod.rs000064400000000000000000000015541046102023000212140ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-package", "0.1.0").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --no-public") .current_dir(cwd) .masquerade_as_nightly_cargo(&["public-dependency"]) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/no_public/stderr.term.svg000064400000000000000000000017601046102023000230600ustar 00000000000000 Updating `dummy-registry` index Adding my-package v0.1.0 to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/normalize_name_git/mod.rs000064400000000000000000000021521046102023000231000ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let git_dep = cargo_test_support::git::new("git-package", |project| { project .file( "Cargo.toml", &cargo_test_support::basic_manifest("git-package", "0.3.0+git-package"), ) .file("src/lib.rs", "") }); let git_url = git_dep.url().to_string(); snapbox::cmd::Command::cargo_ui() .arg("add") .args(["git_package", "--git", &git_url]) .current_dir(cwd) .assert() .failure() // Fuzzy searching for paths isn't supported at this time .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/normalize_name_git/stderr.term.svg000064400000000000000000000017371046102023000247550ustar 00000000000000 Updating git repository `[ROOTURL]/git-package` error: the crate `git_package@[ROOTURL]/git-package` could not be found at `[ROOTURL]/git-package` cargo-0.86.0/tests/testsuite/cargo_add/normalize_name_path/mod.rs000064400000000000000000000022641046102023000232550ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo_list_test_fixture_dependency --path ../dependency") .current_dir(&cwd) .assert() .failure() // Fuzzy searching for paths isn't supported at this time .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/normalize_name_path/stderr.term.svg000064400000000000000000000015121046102023000251150ustar 00000000000000 error: the crate `cargo_list_test_fixture_dependency@[ROOT]/case/dependency` could not be found at `[ROOT]/case/dependency` cargo-0.86.0/tests/testsuite/cargo_add/normalize_name_path_existing/mod.rs000064400000000000000000000012631046102023000251650ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["fuzzy-name", "-p", "bar"]) .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/normalize_name_path_existing/stderr.term.svg000064400000000000000000000016501046102023000270320ustar 00000000000000 Updating crates.io index error: the crate `fuzzy-name` could not be found in registry index. cargo-0.86.0/tests/testsuite/cargo_add/normalize_name_registry/mod.rs000064400000000000000000000025351046102023000241720ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("linked_hash_map Inflector") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/normalize_name_registry/stderr.term.svg000064400000000000000000000061031046102023000260320ustar 00000000000000 Updating `dummy-registry` index warning: translating `linked_hash_map` to `linked-hash-map` warning: translating `Inflector` to `inflector` Adding linked-hash-map v0.5.4 to dependencies Features: - clippy - heapsize - heapsize_impl - nightly - serde - serde_impl - serde_test Adding inflector v0.11.4 to dependencies Features: + heavyweight + lazy_static + regex - unstable Locking 2 packages to latest compatible versions cargo-0.86.0/tests/testsuite/cargo_add/normalize_name_registry_existing/mod.rs000064400000000000000000000016631046102023000261050ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("your-face") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/normalize_name_registry_existing/stderr.term.svg000064400000000000000000000034331046102023000277470ustar 00000000000000 warning: translating `your-face` to `your_face` Updating `dummy-registry` index Adding your_face v99999.0.0 to dependencies Features: + eyes - ears - mouth - nose Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/normalize_name_registry_yanked/mod.rs000064400000000000000000000017711046102023000255260ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("linked-hash-map", "0.5.0").publish(); cargo_test_support::registry::Package::new("linked-hash-map", "0.5.4").publish(); cargo_test_support::registry::Package::new("linked-hash-map", "0.6.0") .yanked(true) .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("linked_hash_map") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/normalize_name_registry_yanked/stderr.term.svg000064400000000000000000000023131046102023000273640ustar 00000000000000 Updating `dummy-registry` index warning: translating `linked_hash_map` to `linked-hash-map` Adding linked-hash-map v0.5.4 to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/normalize_name_workspace_dep/mod.rs000064400000000000000000000015111046102023000251410ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); Package::new("fuzzy_dependency", "1.0.0").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["fuzzy-dependency", "-p", "bar"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/normalize_name_workspace_dep/stderr.term.svg000064400000000000000000000023231046102023000270100ustar 00000000000000 warning: translating `fuzzy-dependency` to `fuzzy_dependency` Updating `dummy-registry` index Adding fuzzy_dependency (workspace) to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/offline_empty_cache/mod.rs000064400000000000000000000020421046102023000232160ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("--offline my-package") .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/offline_empty_cache/stderr.term.svg000064400000000000000000000014211046102023000250630ustar 00000000000000 error: the crate `my-package` could not be found in registry index. cargo-0.86.0/tests/testsuite/cargo_add/optional/mod.rs000064400000000000000000000014571046102023000210710ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-package", "0.1.0").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --optional") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/optional/stderr.term.svg000064400000000000000000000021671046102023000227350ustar 00000000000000 Updating `dummy-registry` index Adding my-package v0.1.0 to optional dependencies Adding feature `my-package` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_default_features/mod.rs000064400000000000000000000022311046102023000246630ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package1 my-package2@0.4.1 --default-features") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_default_features/stderr.term.svg000064400000000000000000000026211046102023000265330ustar 00000000000000 Updating `dummy-registry` index Adding my-package1 v99999.0.0 to dependencies Adding my-package2 v0.4.1 to dependencies Locking 2 packages to latest compatible versions Adding my-package2 v0.4.1+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/overwrite_default_features_with_no_default_features/mod.rs000064400000000000000000000022341046102023000320170ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package1 my-package2@0.4.1 --no-default-features") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } ././@LongLink00006440000000000000000000000153000000000000007772Lustar cargo-0.86.0/tests/testsuite/cargo_add/overwrite_default_features_with_no_default_features/stderr.term.svgcargo-0.86.0/tests/testsuite/cargo_add/overwrite_default_features_with_no_default_features/stderr.te000064400000000000000000000026211046102023000325270ustar 00000000000000 Updating `dummy-registry` index Adding my-package1 v99999.0.0 to dependencies Adding my-package2 v0.4.1 to dependencies Locking 2 packages to latest compatible versions Adding my-package2 v0.4.1+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/overwrite_features/mod.rs000064400000000000000000000017031046102023000231620ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("your-face --features nose") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_features/stderr.term.svg000064400000000000000000000031241046102023000250260ustar 00000000000000 Updating `dummy-registry` index Adding your-face v99999.0.0 to dependencies Features: + eyes + nose - ears - mouth Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_git_with_path/mod.rs000064400000000000000000000021721046102023000241770ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo-list-test-fixture-dependency --path ../dependency") .current_dir(&cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_git_with_path/stderr.term.svg000064400000000000000000000020501046102023000260370ustar 00000000000000 Adding cargo-list-test-fixture-dependency (local) to optional dependencies Adding feature `cargo-list-test-fixture-dependency` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_inherit_features_noop/mod.rs000064400000000000000000000013271046102023000257410ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["foo", "-p", "bar"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_inherit_features_noop/stderr.term.svg000064400000000000000000000016701046102023000276070ustar 00000000000000 Adding foo (workspace) to dependencies Features as of v0.0.0: + test cargo-0.86.0/tests/testsuite/cargo_add/overwrite_inherit_noop/mod.rs000064400000000000000000000013271046102023000240430ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["foo", "-p", "bar"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_inherit_noop/stderr.term.svg000064400000000000000000000013421046102023000257050ustar 00000000000000 Adding foo (workspace) to dependencies cargo-0.86.0/tests/testsuite/cargo_add/overwrite_inherit_optional_noop/mod.rs000064400000000000000000000013271046102023000257500ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["foo", "-p", "bar"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_inherit_optional_noop/stderr.term.svg000064400000000000000000000015401046102023000276120ustar 00000000000000 Adding foo (workspace) to optional dependencies Adding feature `foo` cargo-0.86.0/tests/testsuite/cargo_add/overwrite_inline_features/mod.rs000064400000000000000000000025411046102023000245210ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line( "unrelateed-crate your-face --features your-face/nose,your-face/mouth -Fyour-face/ears", ) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_inline_features/stderr.term.svg000064400000000000000000000033201046102023000263620ustar 00000000000000 Updating `dummy-registry` index Adding unrelateed-crate v99999.0.0 to dependencies Adding your-face v99999.0.0 to dependencies Features: + ears + eyes + mouth + nose Locking 2 packages to latest compatible versions cargo-0.86.0/tests/testsuite/cargo_add/overwrite_name_dev_noop/mod.rs000064400000000000000000000017301046102023000241550ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("your-face --dev") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_name_dev_noop/stderr.term.svg000064400000000000000000000023001046102023000260140ustar 00000000000000 Adding your-face (local) to dev-dependencies Features: + mouth + nose Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_name_noop/mod.rs000064400000000000000000000017221046102023000233200ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("your-face") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_name_noop/stderr.term.svg000064400000000000000000000025011046102023000251610ustar 00000000000000 Adding your-face (local) to optional dependencies Features: + mouth + nose Adding feature `your-face` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_no_default_features/mod.rs000064400000000000000000000022341046102023000253620ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package1 my-package2@0.4.1 --no-default-features") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_no_default_features/stderr.term.svg000064400000000000000000000026211046102023000272270ustar 00000000000000 Updating `dummy-registry` index Adding my-package1 v99999.0.0 to dependencies Adding my-package2 v0.4.1 to dependencies Locking 2 packages to latest compatible versions Adding my-package2 v0.4.1+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/overwrite_no_default_features_with_default_features/mod.rs000064400000000000000000000022311046102023000320140ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package1 my-package2@0.4.1 --default-features") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } ././@LongLink00006440000000000000000000000153000000000000007772Lustar cargo-0.86.0/tests/testsuite/cargo_add/overwrite_no_default_features_with_default_features/stderr.term.svgcargo-0.86.0/tests/testsuite/cargo_add/overwrite_no_default_features_with_default_features/stderr.te000064400000000000000000000026211046102023000325270ustar 00000000000000 Updating `dummy-registry` index Adding my-package1 v99999.0.0 to dependencies Adding my-package2 v0.4.1 to dependencies Locking 2 packages to latest compatible versions Adding my-package2 v0.4.1+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/overwrite_no_optional/mod.rs000064400000000000000000000014621046102023000236670ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-package", "0.1.0").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --no-optional") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_no_optional/stderr.term.svg000064400000000000000000000017601046102023000255350ustar 00000000000000 Updating `dummy-registry` index Adding my-package v0.1.0 to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_no_optional_with_optional/mod.rs000064400000000000000000000014571046102023000266330ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-package", "0.1.0").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --optional") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_no_optional_with_optional/stderr.term.svg000064400000000000000000000021671046102023000304770ustar 00000000000000 Updating `dummy-registry` index Adding my-package v0.1.0 to optional dependencies Adding feature `my-package` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_no_public/mod.rs000064400000000000000000000015541046102023000233220ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-package", "0.1.0").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --no-public") .current_dir(cwd) .masquerade_as_nightly_cargo(&["public-dependency"]) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_no_public/stderr.term.svg000064400000000000000000000017601046102023000251660ustar 00000000000000 Updating `dummy-registry` index Adding my-package v0.1.0 to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_no_public_with_public/mod.rs000064400000000000000000000015511046102023000257100ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-package", "0.1.0").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --public") .current_dir(cwd) .masquerade_as_nightly_cargo(&["public-dependency"]) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_no_public_with_public/stderr.term.svg000064400000000000000000000017671046102023000275660ustar 00000000000000 Updating `dummy-registry` index Adding my-package v0.1.0 to public dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_optional/mod.rs000064400000000000000000000014571046102023000231770ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-package", "0.1.0").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --optional") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_optional/stderr.term.svg000064400000000000000000000021671046102023000250430ustar 00000000000000 Updating `dummy-registry` index Adding my-package v0.1.0 to optional dependencies Adding feature `my-package` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_optional_with_no_optional/mod.rs000064400000000000000000000017021046102023000266240ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[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(current_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_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_optional_with_no_optional/stderr.term.svg000064400000000000000000000031201046102023000304650ustar 00000000000000 Updating `dummy-registry` index Adding your-face v99999.0.0 to dependencies Features: - ears - eyes - mouth - nose Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_optional_with_optional/mod.rs000064400000000000000000000014651046102023000261360ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-package1", "99999.0.0").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package1 --optional") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_optional_with_optional/stderr.term.svg000064400000000000000000000017761046102023000300100ustar 00000000000000 Updating `dummy-registry` index Adding my-package1 v99999.0.0 to optional dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_path_base_with_version/in/.cargo/config.toml000064400000000000000000000000331046102023000306610ustar 00000000000000[path-bases] my_base = "." cargo-0.86.0/tests/testsuite/cargo_add/overwrite_path_base_with_version/mod.rs000064400000000000000000000016501046102023000260730ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("cargo-list-test-fixture-dependency", "20.0.0") .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo-list-test-fixture-dependency@20.0") .current_dir(&cwd) .masquerade_as_nightly_cargo(&["path-base"]) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_path_base_with_version/stderr.term.svg000064400000000000000000000023461046102023000277430ustar 00000000000000 Updating `dummy-registry` index Adding cargo-list-test-fixture-dependency v20.0 to optional dependencies Adding feature `cargo-list-test-fixture-dependency` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_path_noop/mod.rs000064400000000000000000000017461046102023000233420ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("your-face --path ./dependency") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_path_noop/stderr.term.svg000064400000000000000000000025011046102023000251750ustar 00000000000000 Adding your-face (local) to optional dependencies Features: + mouth + nose Adding feature `your-face` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_path_with_version/mod.rs000064400000000000000000000021521046102023000250770ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo-list-test-fixture-dependency@20.0") .current_dir(&cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_path_with_version/stderr.term.svg000064400000000000000000000027141046102023000267500ustar 00000000000000 Updating `dummy-registry` index Adding cargo-list-test-fixture-dependency v20.0 to optional dependencies Adding feature `cargo-list-test-fixture-dependency` Locking 1 package to latest compatible version Adding cargo-list-test-fixture-dependency v20.0.0+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/overwrite_preserves_inline_table/mod.rs000064400000000000000000000017031046102023000260670ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("your-face --features nose") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_preserves_inline_table/stderr.term.svg000064400000000000000000000031241046102023000277330ustar 00000000000000 Updating `dummy-registry` index Adding your-face v99999.0.0 to dependencies Features: + eyes + nose - ears - mouth Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_public/mod.rs000064400000000000000000000015511046102023000226230ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-package", "0.1.0").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --public") .current_dir(cwd) .masquerade_as_nightly_cargo(&["public-dependency"]) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_public/stderr.term.svg000064400000000000000000000017671046102023000245010ustar 00000000000000 Updating `dummy-registry` index Adding my-package v0.1.0 to public dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_public_with_no_public/mod.rs000064400000000000000000000015541046102023000257130ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-package", "0.1.0").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --no-public") .current_dir(cwd) .masquerade_as_nightly_cargo(&["public-dependency"]) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_public_with_no_public/stderr.term.svg000064400000000000000000000017601046102023000275570ustar 00000000000000 Updating `dummy-registry` index Adding my-package v0.1.0 to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_rename_with_no_rename/mod.rs000064400000000000000000000020461046102023000256720ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("versioned-package") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_rename_with_no_rename/stderr.term.svg000064400000000000000000000024221046102023000275350ustar 00000000000000 Updating `dummy-registry` index Adding versioned-package v99999.0.0 to dependencies Locking 2 packages to latest compatible versions Adding versioned-package v0.1.1+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/overwrite_rename_with_rename/mod.rs000064400000000000000000000020621046102023000251740ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("versioned-package --rename a2") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_rename_with_rename/stderr.term.svg000064400000000000000000000024221046102023000270410ustar 00000000000000 Updating `dummy-registry` index Adding versioned-package v99999.0.0 to dependencies Locking 2 packages to latest compatible versions Adding versioned-package v0.1.1+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/overwrite_rename_with_rename_noop/mod.rs000064400000000000000000000020621046102023000262270ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("versioned-package --rename a1") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_rename_with_rename_noop/stderr.term.svg000064400000000000000000000026121046102023000300750ustar 00000000000000 Updating `dummy-registry` index Adding versioned-package v0.1.1 to optional dependencies Adding feature `a1` Locking 1 package to latest compatible version Adding versioned-package v0.1.1+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/overwrite_version_with_git/mod.rs000064400000000000000000000026241046102023000247320ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let git_dep = cargo_test_support::git::new("versioned-package", |project| { project .file( "Cargo.toml", &cargo_test_support::basic_manifest("versioned-package", "0.3.0+versioned-package"), ) .file("src/lib.rs", "") }); let git_url = git_dep.url().to_string(); snapbox::cmd::Command::cargo_ui() .arg("add") .args(["versioned-package", "--git", &git_url]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_version_with_git/stderr.term.svg000064400000000000000000000024571046102023000266030ustar 00000000000000 Updating git repository `[ROOTURL]/versioned-package` Adding versioned-package (git) to optional dependencies Adding feature `versioned-package` Updating git repository `[ROOTURL]/versioned-package` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_version_with_path/mod.rs000064400000000000000000000021721046102023000251010ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo-list-test-fixture-dependency --path ../dependency") .current_dir(&cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_version_with_path/stderr.term.svg000064400000000000000000000020501046102023000267410ustar 00000000000000 Adding cargo-list-test-fixture-dependency (local) to optional dependencies Adding feature `cargo-list-test-fixture-dependency` Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/overwrite_with_rename/mod.rs000064400000000000000000000020671046102023000236520ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("versioned-package --rename renamed") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_with_rename/stderr.term.svg000064400000000000000000000024221046102023000255120ustar 00000000000000 Updating `dummy-registry` index Adding versioned-package v99999.0.0 to dependencies Locking 2 packages to latest compatible versions Adding versioned-package v0.1.1+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/overwrite_workspace_dep/mod.rs000064400000000000000000000013611046102023000241720ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["foo", "--path", "./dependency", "-p", "bar"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_workspace_dep/stderr.term.svg000064400000000000000000000013361046102023000260410ustar 00000000000000 Adding foo (local) to dependencies cargo-0.86.0/tests/testsuite/cargo_add/overwrite_workspace_dep_features/mod.rs000064400000000000000000000013611046102023000260700ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["foo", "--path", "./dependency", "-p", "bar"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/overwrite_workspace_dep_features/stderr.term.svg000064400000000000000000000035461046102023000277440ustar 00000000000000 Adding foo (local) to dependencies Features: + default-base + default-merge-base + default-test-base + test + test-base - merge - merge-base - unrelated cargo-0.86.0/tests/testsuite/cargo_add/path/mod.rs000064400000000000000000000021721046102023000201730ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo-list-test-fixture-dependency --path ../dependency") .current_dir(&cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/path/stderr.term.svg000064400000000000000000000016131046102023000220370ustar 00000000000000 Adding cargo-list-test-fixture-dependency (local) to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/path_base/in/.cargo/config.toml000064400000000000000000000000331046102023000237530ustar 00000000000000[path-bases] my_base = "." cargo-0.86.0/tests/testsuite/cargo_add/path_base/mod.rs000064400000000000000000000014511046102023000211640ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo-list-test-fixture-dependency --path ../dependency --base my_base") .current_dir(&cwd) .masquerade_as_nightly_cargo(&["path-base"]) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/path_base/stderr.term.svg000064400000000000000000000016131046102023000230310ustar 00000000000000 Adding cargo-list-test-fixture-dependency (local) to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/path_base_inferred_name/in/.cargo/config.toml000064400000000000000000000000331046102023000266310ustar 00000000000000[path-bases] my_base = "." cargo-0.86.0/tests/testsuite/cargo_add/path_base_inferred_name/mod.rs000064400000000000000000000014061046102023000240420ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("--path ../dependency --base my_base") .current_dir(&cwd) .masquerade_as_nightly_cargo(&["path-base"]) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/path_base_inferred_name/stderr.term.svg000064400000000000000000000016131046102023000257070ustar 00000000000000 Adding cargo-list-test-fixture-dependency (local) to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/path_base_missing_base_path/mod.rs000064400000000000000000000014041046102023000247210ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("--path dependency --base bad_base") .current_dir(&cwd) .masquerade_as_nightly_cargo(&["path-base"]) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/path_base_missing_base_path/stderr.term.svg000064400000000000000000000015131046102023000265670ustar 00000000000000 error: path base `bad_base` is undefined. You must add an entry for `bad_base` in the Cargo configuration [path-bases] table. cargo-0.86.0/tests/testsuite/cargo_add/path_base_unstable/mod.rs000064400000000000000000000013151046102023000230600ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("--path dependency --base mybase") .current_dir(&cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/path_base_unstable/stderr.term.svg000064400000000000000000000024741046102023000247340ustar 00000000000000 error: feature `path-bases` is required The package requires the Cargo feature called `path-bases`, but that feature is not stabilized in this version of Cargo ([..]). Consider trying a newer version of Cargo (this may require the nightly release). See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#path-bases for more information about the status of this feature. cargo-0.86.0/tests/testsuite/cargo_add/path_dev/mod.rs000064400000000000000000000022001046102023000210210ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo-list-test-fixture-dependency --path ../dependency --dev") .current_dir(&cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/path_dev/stderr.term.svg000064400000000000000000000016171046102023000227010ustar 00000000000000 Adding cargo-list-test-fixture-dependency (local) to dev-dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/path_inferred_name/mod.rs000064400000000000000000000021271046102023000230510ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("--path ../dependency") .current_dir(&cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/path_inferred_name/stderr.term.svg000064400000000000000000000016131046102023000247150ustar 00000000000000 Adding cargo-list-test-fixture-dependency (local) to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/path_inferred_name_conflicts_full_feature/mod.rs000064400000000000000000000014071046102023000276520ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("--path ../dependency --features your-face/nose") .current_dir(&cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/path_inferred_name_conflicts_full_feature/stderr.term.svg000064400000000000000000000014361046102023000315210ustar 00000000000000 error: `your-face/nose` is unsupported when inferring the crate name, use `nose` cargo-0.86.0/tests/testsuite/cargo_add/preserve_dep_std_table/mod.rs000064400000000000000000000017011046102023000237400ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[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(current_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_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/preserve_dep_std_table/stderr.term.svg000064400000000000000000000031201046102023000256020ustar 00000000000000 Updating `dummy-registry` index Adding your-face v99999.0.0 to dependencies Features: - ears - eyes - mouth - nose Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/preserve_features_sorted/mod.rs000064400000000000000000000017101046102023000243450ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-package", "99999.0.0+my-package") .feature("a", &[]) .feature("b", &[]) .feature("c", &[]) .feature("d", &[]) .feature("e", &[]) .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package -F d") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/preserve_features_sorted/stderr.term.svg000064400000000000000000000032511046102023000262140ustar 00000000000000 Updating `dummy-registry` index Adding my-package v99999.0.0 to dependencies Features: + a + b + c + d + e Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/preserve_features_table/mod.rs000064400000000000000000000017011046102023000241340ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[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(current_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_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/preserve_features_table/stderr.term.svg000064400000000000000000000031201046102023000257760ustar 00000000000000 Updating `dummy-registry` index Adding your-face v99999.0.0 to dependencies Features: - ears - eyes - mouth - nose Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/preserve_features_unsorted/mod.rs000064400000000000000000000017101046102023000247100ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-package", "99999.0.0+my-package") .feature("a", &[]) .feature("b", &[]) .feature("c", &[]) .feature("d", &[]) .feature("e", &[]) .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package -F e") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/preserve_features_unsorted/stderr.term.svg000064400000000000000000000032511046102023000265570ustar 00000000000000 Updating `dummy-registry` index Adding my-package v99999.0.0 to dependencies Features: + a + b + c + d + e Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/preserve_sorted/mod.rs000064400000000000000000000021721046102023000224520ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("toml") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/preserve_sorted/stderr.term.svg000064400000000000000000000027221046102023000243200ustar 00000000000000 Updating `dummy-registry` index Adding toml v99999.0.0 to dependencies Locking 3 packages to latest compatible versions Adding my-package v0.1.1+my-package (available: v99999.0.0+my-package) Adding versioned-package v0.1.1+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/preserve_unsorted/mod.rs000064400000000000000000000021721046102023000230150ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("toml") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/preserve_unsorted/stderr.term.svg000064400000000000000000000027221046102023000246630ustar 00000000000000 Updating `dummy-registry` index Adding toml v99999.0.0 to dependencies Locking 3 packages to latest compatible versions Adding my-package v0.1.1+my-package (available: v99999.0.0+my-package) Adding versioned-package v0.1.1+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/public/mod.rs000064400000000000000000000015511046102023000205150ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-package", "0.1.0").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --public") .current_dir(cwd) .masquerade_as_nightly_cargo(&["public-dependency"]) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/public/stderr.term.svg000064400000000000000000000017671046102023000223730ustar 00000000000000 Updating `dummy-registry` index Adding my-package v0.1.0 to public dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/quiet/mod.rs000064400000000000000000000016151046102023000203670ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("--quiet your-face") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(str![""]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/registry/mod.rs000064400000000000000000000023171046102023000211100ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package1 my-package2 --registry alternative") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/registry/stderr.term.svg000064400000000000000000000022041046102023000227500ustar 00000000000000 Updating `alternative` index Adding my-package1 v99999.0.0 to dependencies Adding my-package2 v99999.0.0 to dependencies Locking 2 packages to latest compatible versions cargo-0.86.0/tests/testsuite/cargo_add/rename/mod.rs000064400000000000000000000020511046102023000205020ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package --rename renamed") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/rename/stderr.term.svg000064400000000000000000000017641046102023000223610ustar 00000000000000 Updating `dummy-registry` index Adding my-package v99999.0.0 to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/require_weak/mod.rs000064400000000000000000000017011046102023000217170ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[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(current_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_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/require_weak/stderr.term.svg000064400000000000000000000031201046102023000235610ustar 00000000000000 Updating `dummy-registry` index Adding your-face v99999.0.0 to dependencies Features: - ears - eyes - mouth - nose Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/rust_version_ignore/mod.rs000064400000000000000000000021021046102023000233350ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") .rust_version("1.66") .publish(); cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") .rust_version("1.72") .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg("--ignore-rust-version") .arg_line("rust-version-user") .current_dir(cwd) .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .assert() .code(0) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/rust_version_ignore/stderr.term.svg000064400000000000000000000017671046102023000252220ustar 00000000000000 Updating `dummy-registry` index Adding rust-version-user v0.2.1 to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/rust_version_incompatible/mod.rs000064400000000000000000000022351046102023000245270ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") .rust_version("1.66") .publish(); cargo_test_support::registry::Package::new("rust-version-user", "0.1.1") .rust_version("1.66") .publish(); cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") .rust_version("1.72") .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("rust-version-user") .current_dir(cwd) .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .assert() .failure() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/rust_version_incompatible/stderr.term.svg000064400000000000000000000021521046102023000263720ustar 00000000000000 Updating `dummy-registry` index error: no version of crate `rust-version-user` can maintain cargo-list-test-fixture's rust-version of 1.56 help: pass `--ignore-rust-version` to select rust-version-user@0.2.1 which requires rustc 1.72 cargo-0.86.0/tests/testsuite/cargo_add/rust_version_latest/mod.rs000064400000000000000000000020361046102023000233540ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") .rust_version("1.66") .publish(); cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") .rust_version("1.72") .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("rust-version-user") .current_dir(cwd) .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/rust_version_latest/stderr.term.svg000064400000000000000000000020011046102023000252110ustar 00000000000000 Updating `dummy-registry` index Adding rust-version-user v0.2.1 to dependencies Locking 1 package to latest Rust 1.72 compatible version cargo-0.86.0/tests/testsuite/cargo_add/rust_version_older/mod.rs000064400000000000000000000020361046102023000231650ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") .rust_version("1.66") .publish(); cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") .rust_version("1.72") .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("rust-version-user") .current_dir(cwd) .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/rust_version_older/stderr.term.svg000064400000000000000000000027441046102023000250400ustar 00000000000000 Updating `dummy-registry` index warning: ignoring rust-version-user@0.2.1 (which requires rustc 1.72) to maintain cargo-list-test-fixture's rust-version of 1.70 Adding rust-version-user v0.1.0 to dependencies Locking 1 package to latest Rust 1.70 compatible version Adding rust-version-user v0.1.0 (available: v0.2.1, requires Rust 1.72) cargo-0.86.0/tests/testsuite/cargo_add/rustc_ignore/mod.rs000064400000000000000000000023031046102023000217360ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") .rust_version("1.30") .publish(); cargo_test_support::registry::Package::new("rust-version-user", "0.1.1") .rust_version("1.30") .publish(); cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") .rust_version("1.2345") .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg("--ignore-rust-version") .arg_line("rust-version-user") .current_dir(cwd) .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .assert() .code(0) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/rustc_ignore/stderr.term.svg000064400000000000000000000023571046102023000236140ustar 00000000000000 Updating `dummy-registry` index Adding rust-version-user v0.2.1 to dependencies Locking 1 package to latest compatible version Adding rust-version-user v0.2.1 (requires Rust 1.2345) cargo-0.86.0/tests/testsuite/cargo_add/rustc_incompatible/mod.rs000064400000000000000000000016411046102023000231250ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") .rust_version("1.2345") .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("rust-version-user") .current_dir(cwd) .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .assert() .failure() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/rustc_incompatible/stderr.term.svg000064400000000000000000000021161046102023000247700ustar 00000000000000 Updating `dummy-registry` index error: no version of crate `rust-version-user` is compatible with rustc [..] help: pass `--ignore-rust-version` to select rust-version-user@0.2.1 which requires rustc 1.2345 cargo-0.86.0/tests/testsuite/cargo_add/rustc_latest/mod.rs000064400000000000000000000022371046102023000217550ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") .rust_version("1.30") .publish(); cargo_test_support::registry::Package::new("rust-version-user", "0.1.1") .rust_version("1.30") .publish(); cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") .rust_version("1.2345") .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("rust-version-user") .current_dir(cwd) .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/rustc_latest/stderr.term.svg000064400000000000000000000027231046102023000236220ustar 00000000000000 Updating `dummy-registry` index warning: ignoring rust-version-user@0.2.1 (which requires rustc 1.2345) as it is incompatible with rustc [..] Adding rust-version-user v0.1.1 to dependencies Locking 1 package to latest Rust [..] compatible version Adding rust-version-user v0.1.1 (available: v0.2.1, requires Rust 1.2345) cargo-0.86.0/tests/testsuite/cargo_add/rustc_older/mod.rs000064400000000000000000000022371046102023000215660ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") .rust_version("1.30") .publish(); cargo_test_support::registry::Package::new("rust-version-user", "0.1.1") .rust_version("1.30") .publish(); cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") .rust_version("1.2345") .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("rust-version-user") .current_dir(cwd) .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/rustc_older/stderr.term.svg000064400000000000000000000027231046102023000234330ustar 00000000000000 Updating `dummy-registry` index warning: ignoring rust-version-user@0.2.1 (which requires rustc 1.2345) as it is incompatible with rustc [..] Adding rust-version-user v0.1.1 to dependencies Locking 1 package to latest Rust [..] compatible version Adding rust-version-user v0.1.1 (available: v0.2.1, requires Rust 1.2345) cargo-0.86.0/tests/testsuite/cargo_add/script_bare/in/cargo-test-fixture.rs000064400000000000000000000000151046102023000251110ustar 00000000000000fn main() {} cargo-0.86.0/tests/testsuite/cargo_add/script_bare/mod.rs000064400000000000000000000022111046102023000215260ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .masquerade_as_nightly_cargo(&["script"]) .arg("-Zscript") .arg("add") .arg_line("--manifest-path cargo-test-fixture.rs my-package") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/script_bare/out/cargo-test-fixture.rs000064400000000000000000000000761046102023000253210ustar 00000000000000--- [dependencies] my-package = "99999.0.0" --- fn main() {} cargo-0.86.0/tests/testsuite/cargo_add/script_bare/stderr.term.svg000064400000000000000000000026121046102023000234000ustar 00000000000000 warning: `package.edition` is unspecified, defaulting to `[..]` Updating `dummy-registry` index Adding my-package v99999.0.0 to dependencies warning: `package.edition` is unspecified, defaulting to `[..]` Locking 1 package to latest [..]compatible version cargo-0.86.0/tests/testsuite/cargo_add/script_frontmatter/in/cargo-test-fixture.rs000064400000000000000000000000621046102023000265470ustar 00000000000000--- [package] edition = "2015" --- fn main() { } cargo-0.86.0/tests/testsuite/cargo_add/script_frontmatter/mod.rs000064400000000000000000000022111046102023000231620ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .masquerade_as_nightly_cargo(&["script"]) .arg("-Zscript") .arg("add") .arg_line("--manifest-path cargo-test-fixture.rs my-package") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/script_frontmatter/out/cargo-test-fixture.rs000064400000000000000000000001331046102023000267470ustar 00000000000000--- [package] edition = "2015" [dependencies] my-package = "99999.0.0" --- fn main() { } cargo-0.86.0/tests/testsuite/cargo_add/script_frontmatter/stderr.term.svg000064400000000000000000000017701046102023000250400ustar 00000000000000 Updating `dummy-registry` index Adding my-package v99999.0.0 to dependencies Locking 1 package to latest [..]compatible version cargo-0.86.0/tests/testsuite/cargo_add/script_shebang/in/cargo-test-fixture.rs000064400000000000000000000000431046102023000256100ustar 00000000000000#!/usr/bin/env cargo fn main() {} cargo-0.86.0/tests/testsuite/cargo_add/script_shebang/mod.rs000064400000000000000000000022111046102023000222240ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .masquerade_as_nightly_cargo(&["script"]) .arg("-Zscript") .arg("add") .arg_line("--manifest-path cargo-test-fixture.rs my-package") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/script_shebang/out/cargo-test-fixture.rs000064400000000000000000000001231046102023000260100ustar 00000000000000#!/usr/bin/env cargo --- [dependencies] my-package = "99999.0.0" --- fn main() {} cargo-0.86.0/tests/testsuite/cargo_add/script_shebang/stderr.term.svg000064400000000000000000000026121046102023000240760ustar 00000000000000 warning: `package.edition` is unspecified, defaulting to `[..]` Updating `dummy-registry` index Adding my-package v99999.0.0 to dependencies warning: `package.edition` is unspecified, defaulting to `[..]` Locking 1 package to latest [..]compatible version cargo-0.86.0/tests/testsuite/cargo_add/sorted_table_with_dotted_item/mod.rs000064400000000000000000000023101046102023000253140ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("unrelateed-crate") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/sorted_table_with_dotted_item/stderr.term.svg000064400000000000000000000032541046102023000271710ustar 00000000000000 Updating `dummy-registry` index Adding unrelateed-crate v99999.0.0 to dependencies Locking 4 packages to latest compatible versions Adding my-build-package1 v0.1.1+my-package (available: v99999.0.0+my-package) Adding toml v0.1.1+my-package (available: v99999.0.0+my-package) Adding versioned-package v0.1.1+my-package (available: v99999.0.0+my-package) cargo-0.86.0/tests/testsuite/cargo_add/target/mod.rs000064400000000000000000000022401046102023000205210ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package1 my-package2 --target wasm32-unknown-unknown") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/target/stderr.term.svg000064400000000000000000000023171046102023000223730ustar 00000000000000 Updating `dummy-registry` index Adding my-package1 v99999.0.0 to dependencies for target `wasm32-unknown-unknown` Adding my-package2 v99999.0.0 to dependencies for target `wasm32-unknown-unknown` Locking 2 packages to latest compatible versions cargo-0.86.0/tests/testsuite/cargo_add/target_cfg/mod.rs000064400000000000000000000022441046102023000213440ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package1 my-package2 --target 'cfg(target_os=\"linux\")'") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/target_cfg/stderr.term.svg000064400000000000000000000023171046102023000232120ustar 00000000000000 Updating `dummy-registry` index Adding my-package1 v99999.0.0 to dependencies for target `cfg(target_os="linux")` Adding my-package2 v99999.0.0 to dependencies for target `cfg(target_os="linux")` Locking 2 packages to latest compatible versions cargo-0.86.0/tests/testsuite/cargo_add/unknown_inherited_feature/mod.rs000064400000000000000000000012541046102023000245040ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .args(["foo", "-p", "bar"]) .current_dir(cwd) .assert() .failure() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/unknown_inherited_feature/stderr.term.svg000064400000000000000000000025771046102023000263620ustar 00000000000000 Adding foo (workspace) to dependencies error: unrecognized feature for crate foo: not_recognized disabled features: merge, merge-base, unrelated enabled features: default-base, default-merge-base, default-test-base long-feature-name-because-of-formatting-reasons, test, test-base cargo-0.86.0/tests/testsuite/cargo_add/vers/mod.rs000064400000000000000000000020401046102023000202100ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("my-package@>=0.1.1") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/vers/stderr.term.svg000064400000000000000000000017641046102023000220710ustar 00000000000000 Updating `dummy-registry` index Adding my-package >=0.1.1 to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_add/workspace_name/mod.rs000064400000000000000000000021451046102023000222350ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo-list-test-fixture-dependency") .current_dir(&cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/workspace_name/stderr.term.svg000064400000000000000000000013751046102023000241060ustar 00000000000000 Adding cargo-list-test-fixture-dependency (local) to dependencies cargo-0.86.0/tests/testsuite/cargo_add/workspace_path/mod.rs000064400000000000000000000021721046102023000222510ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo-list-test-fixture-dependency --path ../dependency") .current_dir(&cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/workspace_path/stderr.term.svg000064400000000000000000000013751046102023000241220ustar 00000000000000 Adding cargo-list-test-fixture-dependency (local) to dependencies cargo-0.86.0/tests/testsuite/cargo_add/workspace_path_dev/mod.rs000064400000000000000000000022001046102023000230770ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = project_root.join("primary"); snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("cargo-list-test-fixture-dependency --path ../dependency --dev") .current_dir(&cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/workspace_path_dev/stderr.term.svg000064400000000000000000000014011046102023000247460ustar 00000000000000 Adding cargo-list-test-fixture-dependency (local) to dev-dependencies cargo-0.86.0/tests/testsuite/cargo_add/yanked/mod.rs000064400000000000000000000017711046102023000205160ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("linked-hash-map", "0.5.0").publish(); cargo_test_support::registry::Package::new("linked-hash-map", "0.5.4").publish(); cargo_test_support::registry::Package::new("linked-hash-map", "0.6.0") .yanked(true) .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("add") .arg_line("linked-hash-map") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_add/yanked/stderr.term.svg000064400000000000000000000017651046102023000223660ustar 00000000000000 Updating `dummy-registry` index Adding linked-hash-map v0.5.4 to dependencies Locking 1 package to latest compatible version cargo-0.86.0/tests/testsuite/cargo_alias_config.rs000064400000000000000000000314101046102023000203430ustar 00000000000000//! Tests for `[alias]` config command aliases. use std::env; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::tools::echo_subcommand; use cargo_test_support::{basic_bin_manifest, project}; #[cargo_test] fn alias_incorrect_config_type() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [alias] b-cargo-test = 5 "#, ) .build(); p.cargo("b-cargo-test -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid configuration for key `alias.b-cargo-test` expected a list, but found a integer for `alias.b-cargo-test` in [ROOT]/foo/.cargo/config.toml "#]]) .run(); } #[cargo_test] fn alias_malformed_config_string() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [alias] b-cargo-test = ` "#, ) .build(); p.cargo("b-cargo-test -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] could not load Cargo configuration Caused by: could not parse TOML configuration in `[ROOT]/foo/.cargo/config.toml` Caused by: TOML parse error at line 3, column 32 | 3 | b-cargo-test = ` | ^ invalid string expected `"`, `'` "#]]) .run(); } #[cargo_test] fn alias_malformed_config_list() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [alias] b-cargo-test = [1, 2] "#, ) .build(); p.cargo("b-cargo-test -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] could not load Cargo configuration Caused by: failed to load TOML configuration from `[ROOT]/foo/.cargo/config.toml` Caused by: failed to parse key `alias` Caused by: failed to parse key `b-cargo-test` Caused by: expected string but found integer in list "#]]) .run(); } #[cargo_test] fn alias_config() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [alias] b-cargo-test = "build" "#, ) .build(); p.cargo("b-cargo-test -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn dependent_alias() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [alias] b-cargo-test = "build" a-cargo-test = ["b-cargo-test", "-v"] "#, ) .build(); p.cargo("a-cargo-test") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn builtin_alias_shadowing_external_subcommand() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .executable("cargo-t", "") .build(); let mut paths: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect(); paths.push(p.root()); let path = env::join_paths(paths).unwrap(); p.cargo("t") .env("PATH", &path) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/main.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .run(); } #[cargo_test] fn alias_shadowing_external_subcommand() { let echo = echo_subcommand(); let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [alias] echo = "build" "#, ) .build(); let mut paths: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect(); paths.push(echo.target_debug_dir()); let path = env::join_paths(paths).unwrap(); p.cargo("echo") .env("PATH", &path) .with_stderr_data(str![[r#" [WARNING] user-defined alias `echo` is shadowing an external subcommand found at: `[ROOT]/cargo-echo/target/debug/cargo-echo[EXE]` This was previously accepted but is being phased out; it will become a hard error in a future release. For more information, see issue #10049 . [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn default_args_alias() { let echo = echo_subcommand(); let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [alias] echo = "echo --flag1 --flag2" test-1 = "echo" build = "build --verbose" "#, ) .build(); let mut paths: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect(); paths.push(echo.target_debug_dir()); let path = env::join_paths(paths).unwrap(); p.cargo("echo") .env("PATH", &path) .with_status(101) .with_stderr_data(str![[r#" [WARNING] user-defined alias `echo` is shadowing an external subcommand found at: `[ROOT]/cargo-echo/target/debug/cargo-echo[EXE]` This was previously accepted but is being phased out; it will become a hard error in a future release. For more information, see issue #10049 . [ERROR] alias echo has unresolvable recursive definition: echo -> echo "#]]) .run(); p.cargo("test-1") .env("PATH", &path) .with_status(101) .with_stderr_data(str![[r#" [WARNING] user-defined alias `echo` is shadowing an external subcommand found at: `[ROOT]/cargo-echo/target/debug/cargo-echo[EXE]` This was previously accepted but is being phased out; it will become a hard error in a future release. For more information, see issue #10049 . [ERROR] alias test-1 has unresolvable recursive definition: test-1 -> echo -> echo "#]]) .run(); // Builtins are not expanded by rule p.cargo("build") .with_stderr_data(str![[r#" [WARNING] user-defined alias `build` is ignored, because it is shadowed by a built-in command [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn corecursive_alias() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [alias] test-1 = "test-2 --flag1" test-2 = "test-3 --flag2" test-3 = "test-1 --flag3" "#, ) .build(); p.cargo("test-1") .with_status(101) .with_stderr_data(str![[r#" [ERROR] alias test-1 has unresolvable recursive definition: test-1 -> test-2 -> test-3 -> test-1 "#]]) .run(); p.cargo("test-2") .with_status(101) .with_stderr_data(str![[r#" [ERROR] alias test-2 has unresolvable recursive definition: test-2 -> test-3 -> test-1 -> test-2 "#]]) .run(); } #[cargo_test] fn alias_list_test() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [alias] b-cargo-test = ["build", "--release"] "#, ) .build(); p.cargo("b-cargo-test -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn alias_with_flags_config() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [alias] b-cargo-test = "build --release" "#, ) .build(); p.cargo("b-cargo-test -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn alias_cannot_shadow_builtin_command() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [alias] build = "fetch" "#, ) .build(); p.cargo("build") .with_stderr_data(str![[r#" [WARNING] user-defined alias `build` is ignored, because it is shadowed by a built-in command [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn alias_override_builtin_alias() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [alias] b = "run" "#, ) .build(); p.cargo("b") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); } #[cargo_test] fn builtin_alias_takes_options() { // #6381 let p = project() .file("src/lib.rs", "") .file( "examples/ex1.rs", r#"fn main() { println!("{}", std::env::args().skip(1).next().unwrap()) }"#, ) .build(); p.cargo("r --example ex1 -- asdf") .with_stdout_data(str![[r#" asdf "#]]) .run(); } #[cargo_test] fn global_options_with_alias() { // Check that global options are passed through. let p = project().file("src/lib.rs", "").build(); p.cargo("-v c") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn weird_check() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .build(); p.cargo("-- check --invalid_argument -some-other-argument") .with_status(101) .with_stderr_data(str![[r#" [ERROR] trailing arguments after built-in command `check` are unsupported: `--invalid_argument -some-other-argument` To pass the arguments to the subcommand, remove `--` "#]]) .run(); } #[cargo_test] fn empty_alias() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [alias] string = "" array = [] "#, ) .build(); p.cargo("string") .with_status(101) .with_stderr_data(str![[r#" [ERROR] subcommand is required, but `alias.string` is empty "#]]) .run(); p.cargo("array") .with_status(101) .with_stderr_data(str![[r#" [ERROR] subcommand is required, but `alias.array` is empty "#]]) .run(); } #[cargo_test] fn alias_no_subcommand() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [alias] a = "--locked" "#, ) .build(); p.cargo("a") .with_status(101) .with_stderr_data(str![[r#" [ERROR] subcommand is required, add a subcommand to the command alias `alias.a` "#]]) .run(); } cargo-0.86.0/tests/testsuite/cargo_bench/help/mod.rs000064400000000000000000000004771046102023000205240ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("bench") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_bench/help/stdout.term.svg000064400000000000000000000254741046102023000224140ustar 00000000000000 Execute all benchmarks of a local package Usage: cargo[EXE] bench [OPTIONS] [BENCHNAME] [-- [ARGS]...] Arguments: [BENCHNAME] If specified, only run benches containing this string in their names [ARGS]... Arguments for the bench binary Options: --no-run Compile, but don't run benchmarks --no-fail-fast Run all benchmarks regardless of failure --message-format <FMT> Error format -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -p, --package [<SPEC>] Package to run benchmarks for --workspace Benchmark all packages in the workspace --exclude <SPEC> Exclude packages from the benchmark --all Alias for --workspace (deprecated) Target Selection: --lib Benchmark only this package's library --bins Benchmark all binaries --bin [<NAME>] Benchmark only the specified binary --examples Benchmark all examples --example [<NAME>] Benchmark only the specified example --tests Benchmark all targets that have `test = true` set --test [<NAME>] Benchmark only the specified test target --benches Benchmark all targets that have `bench = true` set --bench [<NAME>] Benchmark only the specified bench target --all-targets Benchmark all targets Feature Selection: -F, --features <FEATURES> Space or comma separated list of features to activate --all-features Activate all available features --no-default-features Do not activate the `default` feature Compilation Options: -j, --jobs <N> Number of parallel jobs, defaults to # of CPUs. --profile <PROFILE-NAME> Build artifacts with the specified profile --target [<TRIPLE>] Build for the target triple --target-dir <DIRECTORY> Directory for all generated artifacts --unit-graph Output build graph in JSON (unstable) --timings[=<FMTS>] Timing output formats (unstable) (comma separated): html, json Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --ignore-rust-version Ignore `rust-version` specification in packages --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help bench` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_bench/mod.rs000064400000000000000000000000351046102023000175620ustar 00000000000000mod help; mod no_keep_going; cargo-0.86.0/tests/testsuite/cargo_bench/no_keep_going/mod.rs000064400000000000000000000011261046102023000223670ustar 00000000000000use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("bench") .arg("--keep-going") .current_dir(cwd) .assert() .code(1) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_bench/no_keep_going/stderr.term.svg000064400000000000000000000033231046102023000242350ustar 00000000000000 error: unexpected argument '--keep-going' found tip: use `--no-fail-fast` to run as many tests as possible regardless of failure Usage: cargo[EXE] bench [OPTIONS] [BENCHNAME] [-- [ARGS]...] For more information, try '--help'. cargo-0.86.0/tests/testsuite/cargo_build/help/mod.rs000064400000000000000000000004771046102023000205440ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("build") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_build/help/stdout.term.svg000064400000000000000000000255231046102023000224270ustar 00000000000000 Compile a local package and all of its dependencies Usage: cargo[EXE] build [OPTIONS] Options: --future-incompat-report Outputs a future incompatibility report at the end of the build --message-format <FMT> Error format -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -p, --package [<SPEC>] Package to build (see `cargo help pkgid`) --workspace Build all packages in the workspace --exclude <SPEC> Exclude packages from the build --all Alias for --workspace (deprecated) Target Selection: --lib Build only this package's library --bins Build all binaries --bin [<NAME>] Build only the specified binary --examples Build all examples --example [<NAME>] Build only the specified example --tests Build all targets that have `test = true` set --test [<NAME>] Build only the specified test target --benches Build all targets that have `bench = true` set --bench [<NAME>] Build only the specified bench target --all-targets Build all targets Feature Selection: -F, --features <FEATURES> Space or comma separated list of features to activate --all-features Activate all available features --no-default-features Do not activate the `default` feature Compilation Options: -r, --release Build artifacts in release mode, with optimizations --profile <PROFILE-NAME> Build artifacts with the specified profile -j, --jobs <N> Number of parallel jobs, defaults to # of CPUs. --keep-going Do not abort the build as soon as there is an error --target [<TRIPLE>] Build for the target triple --target-dir <DIRECTORY> Directory for all generated artifacts --artifact-dir <PATH> Copy final artifacts to this directory (unstable) --build-plan Output the build plan in JSON (unstable) --unit-graph Output build graph in JSON (unstable) --timings[=<FMTS>] Timing output formats (unstable) (comma separated): html, json Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --ignore-rust-version Ignore `rust-version` specification in packages --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help build` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_build/mod.rs000064400000000000000000000000121046102023000175750ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_check/help/mod.rs000064400000000000000000000004771046102023000205220ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("check") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_check/help/stdout.term.svg000064400000000000000000000246231046102023000224050ustar 00000000000000 Check a local package and all of its dependencies for errors Usage: cargo[EXE] check [OPTIONS] Options: --future-incompat-report Outputs a future incompatibility report at the end of the build --message-format <FMT> Error format -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -p, --package [<SPEC>] Package(s) to check --workspace Check all packages in the workspace --exclude <SPEC> Exclude packages from the check --all Alias for --workspace (deprecated) Target Selection: --lib Check only this package's library --bins Check all binaries --bin [<NAME>] Check only the specified binary --examples Check all examples --example [<NAME>] Check only the specified example --tests Check all targets that have `test = true` set --test [<NAME>] Check only the specified test target --benches Check all targets that have `bench = true` set --bench [<NAME>] Check only the specified bench target --all-targets Check all targets Feature Selection: -F, --features <FEATURES> Space or comma separated list of features to activate --all-features Activate all available features --no-default-features Do not activate the `default` feature Compilation Options: -j, --jobs <N> Number of parallel jobs, defaults to # of CPUs. --keep-going Do not abort the build as soon as there is an error -r, --release Check artifacts in release mode, with optimizations --profile <PROFILE-NAME> Check artifacts with the specified profile --target [<TRIPLE>] Check for the target triple --target-dir <DIRECTORY> Directory for all generated artifacts --unit-graph Output build graph in JSON (unstable) --timings[=<FMTS>] Timing output formats (unstable) (comma separated): html, json Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --ignore-rust-version Ignore `rust-version` specification in packages --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help check` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_check/mod.rs000064400000000000000000000000121046102023000175530ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_clean/help/mod.rs000064400000000000000000000004771046102023000205270ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("clean") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_clean/help/stdout.term.svg000064400000000000000000000135561046102023000224150ustar 00000000000000 Remove artifacts that cargo has generated in the past Usage: cargo[EXE] clean [OPTIONS] Options: --doc Whether or not to clean just the documentation directory -n, --dry-run Display what would be deleted without deleting anything -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -p, --package [<SPEC>] Package to clean artifacts for Compilation Options: -r, --release Whether or not to clean release artifacts --profile <PROFILE-NAME> Clean artifacts of the specified profile --target [<TRIPLE>] Target triple to clean output for --target-dir <DIRECTORY> Directory for all generated artifacts Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help clean` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_clean/mod.rs000064400000000000000000000000121046102023000175600ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_command.rs000064400000000000000000000346411046102023000173540ustar 00000000000000//! Tests for custom cargo commands and other global command features. use std::env; use std::fs; use std::io::Read; use std::path::{Path, PathBuf}; use std::process::Stdio; use std::str; use cargo_test_support::basic_manifest; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::tools::echo_subcommand; use cargo_test_support::{ basic_bin_manifest, cargo_exe, cargo_process, paths, project, project_in_home, }; use cargo_util::paths::join_paths; fn path() -> Vec { env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect() } #[cargo_test] fn list_commands_with_descriptions() { let p = project().build(); p.cargo("--list") .with_stdout_data( "\ ... b alias: build ... build Compile a local package and all of its dependencies ... c alias: check ... r alias: run ... read-manifest DEPRECATED: Print a JSON representation of a Cargo.toml manifest. ... t alias: test ... ", ) .run(); } #[cargo_test] fn list_custom_aliases_with_descriptions() { let p = project_in_home("proj") .file( &paths::home().join(".cargo").join("config"), r#" [alias] myaliasstr = "foo --bar" myaliasvec = ["foo", "--bar"] "#, ) .build(); p.cargo("--list") .with_stdout_data(str![[r#" ... myaliasstr alias: foo --bar myaliasvec alias: foo --bar ... "#]]) .run(); } #[cargo_test] fn list_dedupe() { let p = project() .executable(Path::new("path-test-1").join("cargo-dupe"), "") .executable(Path::new("path-test-2").join("cargo-dupe"), "") .build(); let mut path = path(); path.push(p.root().join("path-test-1")); path.push(p.root().join("path-test-2")); let path = env::join_paths(path.iter()).unwrap(); p.cargo("--list") .env("PATH", &path) .with_stdout_data(str![[r#" ... dupe ... "#]]) .run(); } #[cargo_test] fn list_command_looks_at_path() { let proj = project() .executable(Path::new("path-test").join("cargo-1"), "") .build(); let mut path = path(); path.push(proj.root().join("path-test")); let path = env::join_paths(path.iter()).unwrap(); let output = cargo_process("-v --list").env("PATH", &path).run(); let output = str::from_utf8(&output.stdout).unwrap(); assert!( output.contains("\n 1 "), "missing 1: {}", output ); } #[cfg(windows)] #[cargo_test] fn list_command_looks_at_path_case_mismatch() { let proj = project() .executable(Path::new("path-test").join("cargo-1"), "") .build(); let mut path = path(); path.push(proj.root().join("path-test")); let path = env::join_paths(path.iter()).unwrap(); // See issue #11814: Environment variable names are case-insensitive on Windows. // We need to check that having "Path" instead of "PATH" is okay. let output = cargo_process("-v --list") .env("Path", &path) .env_remove("PATH") .run(); let output = str::from_utf8(&output.stdout).unwrap(); assert!( output.contains("\n 1 "), "missing 1: {}", output ); } #[cargo_test] fn list_command_handles_known_external_commands() { let p = project() .executable(Path::new("path-test").join("cargo-fmt"), "") .build(); let fmt_desc = " fmt Formats all bin and lib files of the current crate using rustfmt."; // Without path - fmt isn't there p.cargo("--list") .env("PATH", "") .with_stdout_does_not_contain(fmt_desc) .run(); // With path - fmt is there with known description let mut path = path(); path.push(p.root().join("path-test")); let path = env::join_paths(path.iter()).unwrap(); p.cargo("--list") .env("PATH", &path) .with_stdout_data(str![[r#" ... fmt Formats all bin and lib files of the current crate using rustfmt. ..."#]]) .run(); } #[cargo_test] fn list_command_resolves_symlinks() { let proj = project() .symlink(cargo_exe(), Path::new("path-test").join("cargo-2")) .build(); let mut path = path(); path.push(proj.root().join("path-test")); let path = env::join_paths(path.iter()).unwrap(); let output = cargo_process("-v --list").env("PATH", &path).run(); let output = str::from_utf8(&output.stdout).unwrap(); assert!( output.contains("\n 2 "), "missing 2: {}", output ); } #[cargo_test] fn find_closest_capital_c_to_c() { cargo_process("C") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no such command: `C` Did you mean `c`? View all installed commands with `cargo --list` Find a package to install `C` with `cargo search cargo-C` "#]]) .run(); } #[cargo_test] fn find_closest_capital_b_to_b() { cargo_process("B") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no such command: `B` Did you mean `b`? View all installed commands with `cargo --list` Find a package to install `B` with `cargo search cargo-B` "#]]) .run(); } #[cargo_test] fn find_closest_biuld_to_build() { cargo_process("biuld") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no such command: `biuld` Did you mean `build`? View all installed commands with `cargo --list` Find a package to install `biuld` with `cargo search cargo-biuld` "#]]) .run(); // But, if we actually have `biuld`, it must work! // https://github.com/rust-lang/cargo/issues/5201 Package::new("cargo-biuld", "1.0.0") .file( "src/main.rs", r#" fn main() { println!("Similar, but not identical to, build"); } "#, ) .publish(); cargo_process("install cargo-biuld").run(); cargo_process("biuld") .with_stdout_data(str![[r#" Similar, but not identical to, build "#]]) .run(); cargo_process("--list") .with_stdout_data(str![[r#" ... biuld ... build Compile a local package and all of its dependencies ..."#]]) .run(); } #[cargo_test] fn find_closest_alias() { let root = paths::root(); let my_home = root.join("my_home"); fs::create_dir(&my_home).unwrap(); fs::write( &my_home.join("config.toml"), r#" [alias] myalias = "build" "#, ) .unwrap(); cargo_process("myalais") .env("CARGO_HOME", &my_home) .with_status(101) .with_stderr_data(str![[r#" [ERROR] no such command: `myalais` Did you mean `myalias`? View all installed commands with `cargo --list` Find a package to install `myalais` with `cargo search cargo-myalais` "#]]) .run(); // But, if no alias is defined, it must not suggest one! cargo_process("myalais") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no such command: `myalais` View all installed commands with `cargo --list` Find a package to install `myalais` with `cargo search cargo-myalais` "#]]) .run(); } // If a subcommand is more than an edit distance of 3 away, we don't make a suggestion. #[cargo_test] fn find_closest_dont_correct_nonsense() { cargo_process("there-is-no-way-that-there-is-a-command-close-to-this") .cwd(&paths::root()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] no such command: `there-is-no-way-that-there-is-a-command-close-to-this` View all installed commands with `cargo --list` Find a package to install `there-is-no-way-that-there-is-a-command-close-to-this` with `cargo search cargo-there-is-no-way-that-there-is-a-command-close-to-this` "#]]) .run(); } #[cargo_test] fn displays_subcommand_on_error() { cargo_process("invalid-command") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no such command: `invalid-command` View all installed commands with `cargo --list` Find a package to install `invalid-command` with `cargo search cargo-invalid-command` "#]]) .run(); } #[cargo_test] fn override_cargo_home() { let root = paths::root(); let my_home = root.join("my_home"); fs::create_dir(&my_home).unwrap(); fs::write( &my_home.join("config"), r#" [cargo-new] vcs = "none" "#, ) .unwrap(); cargo_process("new foo").env("CARGO_HOME", &my_home).run(); assert!(!paths::root().join("foo/.git").is_dir()); cargo_process("new foo2").run(); assert!(paths::root().join("foo2/.git").is_dir()); } #[cargo_test] fn cargo_subcommand_env() { let src = format!( r#" use std::env; fn main() {{ println!("{{}}", env::var("{}").unwrap()); }} "#, cargo::CARGO_ENV ); let p = project() .at("cargo-envtest") .file("Cargo.toml", &basic_bin_manifest("cargo-envtest")) .file("src/main.rs", &src) .build(); let target_dir = p.target_debug_dir(); p.cargo("build").run(); assert!(p.bin("cargo-envtest").is_file()); let cargo = cargo_exe().canonicalize().unwrap(); let mut path = path(); path.push(target_dir.clone()); let path = env::join_paths(path.iter()).unwrap(); cargo_process("envtest") .env("PATH", &path) .with_stdout_data(format!("{}\n", cargo.to_str().unwrap()).raw()) .run(); // Check that subcommands inherit an overridden $CARGO let envtest_bin = target_dir .join("cargo-envtest") .with_extension(std::env::consts::EXE_EXTENSION) .canonicalize() .unwrap(); let envtest_bin = envtest_bin.to_str().unwrap(); cargo_process("envtest") .env("PATH", &path) .env(cargo::CARGO_ENV, &envtest_bin) .with_stdout_data(format!("{}\n", envtest_bin).raw().raw()) .run(); } #[cargo_test] fn cargo_cmd_bins_vs_explicit_path() { // Set up `cargo-foo` binary in two places: inside `$HOME/.cargo/bin` and outside of it // // Return paths to both places fn set_up_cargo_foo() -> (PathBuf, PathBuf) { let p = project() .at("cargo-foo") .file("Cargo.toml", &basic_manifest("cargo-foo", "1.0.0")) .file( "src/bin/cargo-foo.rs", r#"fn main() { println!("INSIDE"); }"#, ) .file( "src/bin/cargo-foo2.rs", r#"fn main() { println!("OUTSIDE"); }"#, ) .build(); p.cargo("build").run(); let cargo_bin_dir = paths::home().join(".cargo/bin"); cargo_bin_dir.mkdir_p(); let root_bin_dir = paths::root().join("bin"); root_bin_dir.mkdir_p(); let exe_name = format!("cargo-foo{}", env::consts::EXE_SUFFIX); fs::rename(p.bin("cargo-foo"), cargo_bin_dir.join(&exe_name)).unwrap(); fs::rename(p.bin("cargo-foo2"), root_bin_dir.join(&exe_name)).unwrap(); (root_bin_dir, cargo_bin_dir) } let (outside_dir, inside_dir) = set_up_cargo_foo(); // If `$CARGO_HOME/bin` is not in a path, prefer it over anything in `$PATH`. // // This is the historical behavior we don't want to break. cargo_process("foo") .with_stdout_data(str![[r#" INSIDE "#]]) .run(); // When `$CARGO_HOME/bin` is in the `$PATH` // use only `$PATH` so the user-defined ordering is respected. { cargo_process("foo") .env( "PATH", join_paths(&[&inside_dir, &outside_dir], "PATH").unwrap(), ) .with_stdout_data(str![[r#" INSIDE "#]]) .run(); cargo_process("foo") // Note: trailing slash .env( "PATH", join_paths(&[inside_dir.join(""), outside_dir.join("")], "PATH").unwrap(), ) .with_stdout_data(str![[r#" INSIDE "#]]) .run(); cargo_process("foo") .env( "PATH", join_paths(&[&outside_dir, &inside_dir], "PATH").unwrap(), ) .with_stdout_data(str![[r#" OUTSIDE "#]]) .run(); cargo_process("foo") // Note: trailing slash .env( "PATH", join_paths(&[outside_dir.join(""), inside_dir.join("")], "PATH").unwrap(), ) .with_stdout_data(str![[r#" OUTSIDE "#]]) .run(); } } #[cargo_test] fn cargo_subcommand_args() { let p = echo_subcommand(); let cargo_foo_bin = p.bin("cargo-echo"); assert!(cargo_foo_bin.is_file()); let mut path = path(); path.push(p.target_debug_dir()); let path = env::join_paths(path.iter()).unwrap(); cargo_process("echo bar -v --help") .env("PATH", &path) .with_stdout_data(str![[r#" echo bar -v --help "#]]) .run(); } #[cargo_test] fn explain() { cargo_process("--explain E0001") .with_stdout_data(str![[r#" ... This error suggests that the expression arm corresponding to the noted pattern[..] ... "#]]) .run(); } #[cargo_test] fn closed_output_ok() { // Checks that closed output doesn't cause an error. let mut p = cargo_process("--list").build_command(); p.stdout(Stdio::piped()).stderr(Stdio::piped()); let mut child = p.spawn().unwrap(); // Close stdout drop(child.stdout.take()); // Read stderr let mut s = String::new(); child .stderr .as_mut() .unwrap() .read_to_string(&mut s) .unwrap(); let status = child.wait().unwrap(); assert!(status.success()); assert!(s.is_empty(), "{}", s); } #[cargo_test] fn subcommand_leading_plus_output_contains() { cargo_process("+nightly") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no such command: `+nightly` Cargo does not handle `+toolchain` directives. Did you mean to invoke `cargo` through `rustup` instead? "#]]) .run(); } #[cargo_test] fn full_did_you_mean() { cargo_process("bluid") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no such command: `bluid` Did you mean `build`? View all installed commands with `cargo --list` Find a package to install `bluid` with `cargo search cargo-bluid` "#]]) .run(); } cargo-0.86.0/tests/testsuite/cargo_config/help/mod.rs000064400000000000000000000005001046102023000206750ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("config") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_config/help/stdout.term.svg000064400000000000000000000067441046102023000226010ustar 00000000000000 Inspect configuration values Usage: cargo[EXE] config [OPTIONS] <COMMAND> Commands: get Options: -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline cargo-0.86.0/tests/testsuite/cargo_config/mod.rs000064400000000000000000000401641046102023000177570ustar 00000000000000//! Tests for the `cargo config` command. use super::config::write_config_at; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::str; use std::fs; use std::path::PathBuf; mod help; fn cargo_process(s: &str) -> cargo_test_support::Execs { let mut p = cargo_test_support::cargo_process(s); // Clear out some of the environment added by the default cargo_process so // the tests don't need to deal with it. p.env_remove("CARGO_PROFILE_DEV_SPLIT_DEBUGINFO") .env_remove("CARGO_PROFILE_TEST_SPLIT_DEBUGINFO") .env_remove("CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO") .env_remove("CARGO_PROFILE_BENCH_SPLIT_DEBUGINFO") .env_remove("CARGO_INCREMENTAL"); p } #[cargo_test] fn gated() { cargo_process("config get") .masquerade_as_nightly_cargo(&["cargo-config"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `cargo config` command is unstable, pass `-Z unstable-options` to enable it See https://github.com/rust-lang/cargo/issues/9301 for more information about the `cargo config` command. "#]]) .run(); } fn common_setup() -> PathBuf { write_config_at( paths::home().join(".cargo/config.toml"), " [alias] foo = \"abc --xyz\" [build] jobs = 99 rustflags = [\"--flag-global\"] [profile.dev] opt-level = 3 [profile.dev.package.foo] opt-level = 1 [target.'cfg(target_os = \"linux\")'] runner = \"runme\" # How unknown keys are handled. [extra-table] somekey = \"somevalue\" ", ); let sub_folder = paths::root().join("foo/.cargo"); write_config_at( sub_folder.join("config.toml"), " [alias] sub-example = [\"sub\", \"example\"] [build] rustflags = [\"--flag-directory\"] ", ); sub_folder } #[cargo_test] fn get_toml() { // Notes: // - The "extra-table" is shown without a warning. I'm not sure how that // should be handled, since displaying warnings could cause problems // with ingesting the output. // - Environment variables aren't loaded. :( let sub_folder = common_setup(); cargo_process("config get -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .env("CARGO_ALIAS_BAR", "cat dog") .env("CARGO_BUILD_JOBS", "100") // The weird forward slash in the linux line is due to testsuite normalization. .with_stdout_data(str![[r#" alias.foo = "abc --xyz" alias.sub-example = ["sub", "example"] build.jobs = 99 build.rustflags = ["--flag-global", "--flag-directory"] extra-table.somekey = "somevalue" profile.dev.opt-level = 3 profile.dev.package.foo.opt-level = 1 target.'cfg(target_os = "linux")'.runner = "runme" # The following environment variables may affect the loaded values. # CARGO_ALIAS_BAR=[..]cat dog[..] # CARGO_BUILD_JOBS=100 # CARGO_HOME=[ROOT]/home/.cargo "#]]) .with_stderr_data(str![[r#""#]]) .run(); // Env keys work if they are specific. cargo_process("config get build.jobs -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .env("CARGO_BUILD_JOBS", "100") .with_stdout_data(str![[r#" build.jobs = 100 "#]]) .with_stderr_data(str![[r#""#]]) .run(); // Array value. cargo_process("config get build.rustflags -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .with_stdout_data(str![[r#" build.rustflags = ["--flag-global", "--flag-directory"] "#]]) .with_stderr_data(str![[r#""#]]) .run(); // Sub-table cargo_process("config get profile -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .with_stdout_data(str![[r#" profile.dev.opt-level = 3 profile.dev.package.foo.opt-level = 1 "#]]) .with_stderr_data(str![[r#""#]]) .run(); // Specific profile entry. cargo_process("config get profile.dev.opt-level -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .with_stdout_data(str![[r#" profile.dev.opt-level = 3 "#]]) .with_stderr_data(str![[r#""#]]) .run(); // A key that isn't set. cargo_process("config get build.rustc -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .with_status(101) .with_stdout_data(str![[r#""#]]) .with_stderr_data(str![[r#" [ERROR] config value `build.rustc` is not set "#]]) .run(); // A key that is not part of Cargo's config schema. cargo_process("config get not.set -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .with_status(101) .with_stdout_data(str![[r#""#]]) .with_stderr_data(str![[r#" [ERROR] config value `not.set` is not set "#]]) .run(); } #[cargo_test] fn get_json() { let sub_folder = common_setup(); cargo_process("config get --format=json -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .env("CARGO_ALIAS_BAR", "cat dog") .env("CARGO_BUILD_JOBS", "100") .with_stdout_data( r#" { "alias": { "foo": "abc --xyz", "sub-example": [ "sub", "example" ] }, "build": { "jobs": 99, "rustflags": [ "--flag-global", "--flag-directory" ] }, "extra-table": { "somekey": "somevalue" }, "profile": { "dev": { "opt-level": 3, "package": { "foo": { "opt-level": 1 } } } }, "target": { "cfg(target_os = \"linux\")": { "runner": "runme" } } } "# .is_json(), ) .with_stderr_data(str![[r#" [NOTE] The following environment variables may affect the loaded values. CARGO_ALIAS_BAR=[..]cat dog[..] CARGO_BUILD_JOBS=100 CARGO_HOME=[ROOT]/home/.cargo "#]]) .run(); // json-value is the same for the entire root table cargo_process("config get --format=json-value -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .with_stdout_data( r#" { "alias": { "foo": "abc --xyz", "sub-example": [ "sub", "example" ] }, "build": { "jobs": 99, "rustflags": [ "--flag-global", "--flag-directory" ] }, "extra-table": { "somekey": "somevalue" }, "profile": { "dev": { "opt-level": 3, "package": { "foo": { "opt-level": 1 } } } }, "target": { "cfg(target_os = \"linux\")": { "runner": "runme" } } } "# .is_json(), ) .with_stderr_data(str![[r#" [NOTE] The following environment variables may affect the loaded values. CARGO_HOME=[ROOT]/home/.cargo "#]]) .run(); cargo_process("config get --format=json build.jobs -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .with_stdout_data(str![[r#" {"build":{"jobs":99}} "#]]) .with_stderr_data(str![[r#""#]]) .run(); cargo_process("config get --format=json-value build.jobs -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .with_stdout_data(str![[r#" 99 "#]]) .with_stderr_data(str![[r#""#]]) .run(); } #[cargo_test] fn show_origin_toml() { let sub_folder = common_setup(); cargo_process("config get --show-origin -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .with_stdout_data(str![[r#" alias.foo = "abc --xyz" # [ROOT]/home/.cargo/config.toml alias.sub-example = [ "sub", # [ROOT]/foo/.cargo/config.toml "example", # [ROOT]/foo/.cargo/config.toml ] build.jobs = 99 # [ROOT]/home/.cargo/config.toml build.rustflags = [ "--flag-global", # [ROOT]/home/.cargo/config.toml "--flag-directory", # [ROOT]/foo/.cargo/config.toml ] extra-table.somekey = "somevalue" # [ROOT]/home/.cargo/config.toml profile.dev.opt-level = 3 # [ROOT]/home/.cargo/config.toml profile.dev.package.foo.opt-level = 1 # [ROOT]/home/.cargo/config.toml target.'cfg(target_os = "linux")'.runner = "runme" # [ROOT]/home/.cargo/config.toml # The following environment variables may affect the loaded values. # CARGO_HOME=[ROOT]/home/.cargo "#]]) .with_stderr_data(str![[r#""#]]) .run(); cargo_process("config get --show-origin build.rustflags -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .env("CARGO_BUILD_RUSTFLAGS", "env1 env2") .with_stdout_data(str![[r#" build.rustflags = [ "--flag-global", # [ROOT]/home/.cargo/config.toml "--flag-directory", # [ROOT]/foo/.cargo/config.toml "env1", # environment variable `CARGO_BUILD_RUSTFLAGS` "env2", # environment variable `CARGO_BUILD_RUSTFLAGS` ] "#]]) .with_stderr_data(str![[r#""#]]) .run(); } #[cargo_test] fn show_origin_toml_cli() { let sub_folder = common_setup(); cargo_process("config get --show-origin build.jobs -Zunstable-options --config build.jobs=123") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .env("CARGO_BUILD_JOBS", "1") .with_stdout_data(str![[r#" build.jobs = 123 # --config cli option "#]]) .with_stderr_data(str![[r#""#]]) .run(); cargo_process("config get --show-origin build.rustflags -Zunstable-options --config") .arg("build.rustflags=[\"cli1\",\"cli2\"]") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .env("CARGO_BUILD_RUSTFLAGS", "env1 env2") .with_stdout_data(str![[r#" build.rustflags = [ "--flag-global", # [ROOT]/home/.cargo/config.toml "--flag-directory", # [ROOT]/foo/.cargo/config.toml "env1", # environment variable `CARGO_BUILD_RUSTFLAGS` "env2", # environment variable `CARGO_BUILD_RUSTFLAGS` "cli1", # --config cli option "cli2", # --config cli option ] "#]]) .with_stderr_data(str![[r#""#]]) .run(); } #[cargo_test] fn show_origin_json() { let sub_folder = common_setup(); cargo_process("config get --show-origin --format=json -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `json` format does not support --show-origin, try the `toml` format instead "#]]) .run(); } #[cargo_test] fn unmerged_toml() { let sub_folder = common_setup(); cargo_process("config get --merged=no -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .env("CARGO_ALIAS_BAR", "cat dog") .env("CARGO_BUILD_JOBS", "100") .with_stdout_data(str![[r#" # Environment variables # CARGO=[..] # CARGO_ALIAS_BAR=[..]cat dog[..] # CARGO_BUILD_JOBS=100 # CARGO_HOME=[ROOT]/home/.cargo # [ROOT]/foo/.cargo/config.toml alias.sub-example = ["sub", "example"] build.rustflags = ["--flag-directory"] # [ROOT]/home/.cargo/config.toml alias.foo = "abc --xyz" build.jobs = 99 build.rustflags = ["--flag-global"] extra-table.somekey = "somevalue" profile.dev.opt-level = 3 profile.dev.package.foo.opt-level = 1 target.'cfg(target_os = "linux")'.runner = "runme" "#]]) .with_stderr_data(str![[r#""#]]) .run(); cargo_process("config get --merged=no build.rustflags -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .env("CARGO_BUILD_RUSTFLAGS", "env1 env2") .with_stdout_data(str![[r#" # Environment variables # CARGO_BUILD_RUSTFLAGS=[..]env1 env2[..] # [ROOT]/foo/.cargo/config.toml build.rustflags = ["--flag-directory"] # [ROOT]/home/.cargo/config.toml build.rustflags = ["--flag-global"] "#]]) .with_stderr_data(str![[r#""#]]) .run(); cargo_process("config get --merged=no does.not.exist -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .with_stderr_data(str![[r#""#]]) .with_stderr_data(str![[r#""#]]) .run(); cargo_process("config get --merged=no build.rustflags.extra -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] expected table for configuration key `build.rustflags`, but found array in [ROOT]/foo/.cargo/config.toml "#]]) .run(); } #[cargo_test] fn unmerged_toml_cli() { let sub_folder = common_setup(); cargo_process("config get --merged=no build.rustflags -Zunstable-options --config") .arg("build.rustflags=[\"cli1\",\"cli2\"]") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .env("CARGO_BUILD_RUSTFLAGS", "env1 env2") .with_stdout_data(str![[r#" # --config cli option build.rustflags = ["cli1", "cli2"] # Environment variables # CARGO_BUILD_RUSTFLAGS=[..]env1 env2[..] # [ROOT]/foo/.cargo/config.toml build.rustflags = ["--flag-directory"] # [ROOT]/home/.cargo/config.toml build.rustflags = ["--flag-global"] "#]]) .with_stderr_data(str![[r#""#]]) .run(); } #[cargo_test] fn unmerged_json() { let sub_folder = common_setup(); cargo_process("config get --merged=no --format=json -Zunstable-options") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `json` format does not support --merged=no, try the `toml` format instead "#]]) .run(); } #[cargo_test] fn includes() { let sub_folder = common_setup(); fs::write( sub_folder.join("config.toml"), " include = 'other.toml' [build] rustflags = [\"--flag-directory\"] ", ) .unwrap(); fs::write( sub_folder.join("other.toml"), " [build] rustflags = [\"--flag-other\"] ", ) .unwrap(); cargo_process("config get build.rustflags -Zunstable-options -Zconfig-include") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config", "config-include"]) .with_stdout_data(str![[r#" build.rustflags = ["--flag-global", "--flag-other", "--flag-directory"] "#]]) .with_stderr_data(str![[r#""#]]) .run(); cargo_process("config get build.rustflags --show-origin -Zunstable-options -Zconfig-include") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config", "config-include"]) .with_stdout_data(str![[r#" build.rustflags = [ "--flag-global", # [ROOT]/home/.cargo/config.toml "--flag-other", # [ROOT]/foo/.cargo/other.toml "--flag-directory", # [ROOT]/foo/.cargo/config.toml ] "#]]) .with_stderr_data(str![[r#""#]]) .run(); cargo_process("config get --merged=no -Zunstable-options -Zconfig-include") .cwd(&sub_folder.parent().unwrap()) .masquerade_as_nightly_cargo(&["cargo-config", "config-include"]) .with_stdout_data(str![[r#" # Environment variables # CARGO=[..] # CARGO_HOME=[ROOT]/home/.cargo # [ROOT]/foo/.cargo/other.toml build.rustflags = ["--flag-other"] # [ROOT]/foo/.cargo/config.toml build.rustflags = ["--flag-directory"] include = "other.toml" # [ROOT]/home/.cargo/config.toml alias.foo = "abc --xyz" build.jobs = 99 build.rustflags = ["--flag-global"] extra-table.somekey = "somevalue" profile.dev.opt-level = 3 profile.dev.package.foo.opt-level = 1 target.'cfg(target_os = "linux")'.runner = "runme" "#]]) .with_stderr_data(str![[r#""#]]) .run(); } cargo-0.86.0/tests/testsuite/cargo_doc/help/mod.rs000064400000000000000000000004751046102023000202100ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("doc") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_doc/help/stdout.term.svg000064400000000000000000000232701046102023000220720ustar 00000000000000 Build a package's documentation Usage: cargo[EXE] doc [OPTIONS] Options: --open Opens the docs in a browser after the operation --no-deps Don't build documentation for dependencies --document-private-items Document private items --message-format <FMT> Error format -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -p, --package [<SPEC>] Package to document --workspace Document all packages in the workspace --exclude <SPEC> Exclude packages from the build --all Alias for --workspace (deprecated) Feature Selection: -F, --features <FEATURES> Space or comma separated list of features to activate --all-features Activate all available features --no-default-features Do not activate the `default` feature Target Selection: --lib Document only this package's library --bins Document all binaries --bin [<NAME>] Document only the specified binary --examples Document all examples --example [<NAME>] Document only the specified example Compilation Options: -j, --jobs <N> Number of parallel jobs, defaults to # of CPUs. --keep-going Do not abort the build as soon as there is an error -r, --release Build artifacts in release mode, with optimizations --profile <PROFILE-NAME> Build artifacts with the specified profile --target [<TRIPLE>] Build for the target triple --target-dir <DIRECTORY> Directory for all generated artifacts --unit-graph Output build graph in JSON (unstable) --timings[=<FMTS>] Timing output formats (unstable) (comma separated): html, json Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --ignore-rust-version Ignore `rust-version` specification in packages --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help doc` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_doc/mod.rs000064400000000000000000000000121046102023000172430ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_env_config.rs000064400000000000000000000260731046102023000200530ustar 00000000000000//! Tests for `[env]` config. use cargo_test_support::basic_manifest; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::{basic_bin_manifest, project}; #[cargo_test] fn env_basic() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" use std::env; fn main() { println!( "compile-time:{}", env!("ENV_TEST_1233") ); println!( "run-time:{}", env::var("ENV_TEST_1233").unwrap()); } "#, ) .file( ".cargo/config.toml", r#" [env] ENV_TEST_1233 = "Hello" "#, ) .build(); p.cargo("run") .with_stdout_data(str![[r#" compile-time:Hello run-time:Hello "#]]) .run(); } #[cargo_test] fn env_invalid() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" fn main() { } "#, ) .file( ".cargo/config.toml", r#" [env] ENV_TEST_BOOL = false "#, ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] error in [ROOT]/foo/.cargo/config.toml: could not load config key `env.ENV_TEST_BOOL` Caused by: error in [ROOT]/foo/.cargo/config.toml: could not load config key `env.ENV_TEST_BOOL` Caused by: invalid type: boolean `false`, expected a string or map "#]]) .run(); } #[cargo_test] fn env_no_disallowed() { // Checks for keys that are not allowed in the [env] table. let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/lib.rs", "") .build(); for disallowed in &["CARGO_HOME", "RUSTUP_HOME", "RUSTUP_TOOLCHAIN"] { p.change_file( ".cargo/config.toml", &format!( r#" [env] {disallowed} = "foo" "# ), ); p.cargo("check") .with_status(101) .with_stderr_data(format!( "\ [ERROR] setting the `{disallowed}` environment variable \ is not supported in the `[env]` configuration table " )) .run(); } } #[cargo_test] fn env_force() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" use std::env; fn main() { println!( "ENV_TEST_FORCED:{}", env!("ENV_TEST_FORCED") ); println!( "ENV_TEST_UNFORCED:{}", env!("ENV_TEST_UNFORCED") ); println!( "ENV_TEST_UNFORCED_DEFAULT:{}", env!("ENV_TEST_UNFORCED_DEFAULT") ); } "#, ) .file( ".cargo/config.toml", r#" [env] ENV_TEST_UNFORCED_DEFAULT = "from-config" ENV_TEST_UNFORCED = { value = "from-config", force = false } ENV_TEST_FORCED = { value = "from-config", force = true } "#, ) .build(); p.cargo("run") .env("ENV_TEST_FORCED", "from-env") .env("ENV_TEST_UNFORCED", "from-env") .env("ENV_TEST_UNFORCED_DEFAULT", "from-env") .with_stdout_data(str![[r#" ENV_TEST_FORCED:from-config ENV_TEST_UNFORCED:from-env ENV_TEST_UNFORCED_DEFAULT:from-env "#]]) .run(); } #[cargo_test] fn env_relative() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo2")) .file( "src/main.rs", r#" use std::env; use std::path::Path; fn main() { println!( "ENV_TEST_REGULAR:{}", env!("ENV_TEST_REGULAR") ); println!( "ENV_TEST_REGULAR_DEFAULT:{}", env!("ENV_TEST_REGULAR_DEFAULT") ); println!( "ENV_TEST_RELATIVE:{}", env!("ENV_TEST_RELATIVE") ); assert!( Path::new(env!("ENV_TEST_RELATIVE")).is_absolute() ); assert!( !Path::new(env!("ENV_TEST_REGULAR")).is_absolute() ); assert!( !Path::new(env!("ENV_TEST_REGULAR_DEFAULT")).is_absolute() ); } "#, ) .file( ".cargo/config.toml", r#" [env] ENV_TEST_REGULAR = { value = "Cargo.toml", relative = false } ENV_TEST_REGULAR_DEFAULT = "Cargo.toml" ENV_TEST_RELATIVE = { value = "Cargo.toml", relative = true } "#, ) .build(); p.cargo("run").run(); } #[cargo_test] fn env_no_override() { let p = project() .file("Cargo.toml", &basic_bin_manifest("unchanged")) .file( "src/main.rs", r#" use std::env; fn main() { println!( "CARGO_PKG_NAME:{}", env!("CARGO_PKG_NAME") ); } "#, ) .file( ".cargo/config.toml", r#" [env] CARGO_PKG_NAME = { value = "from-config", force = true } "#, ) .build(); p.cargo("run") .with_stdout_data(str![[r#" CARGO_PKG_NAME:unchanged "#]]) .run(); } #[cargo_test] fn env_applied_to_target_info_discovery_rustc() { let wrapper = project() .at("wrapper") .file("Cargo.toml", &basic_manifest("wrapper", "1.0.0")) .file( "src/main.rs", r#" fn main() { let mut cmd = std::env::args().skip(1).collect::>(); // This will be invoked twice (with `-vV` and with all the `--print`), // make sure the environment variable exists each time. let env_test = std::env::var("ENV_TEST").unwrap(); eprintln!("WRAPPER ENV_TEST:{env_test}"); let (prog, args) = cmd.split_first().unwrap(); let status = std::process::Command::new(prog) .args(args).status().unwrap(); std::process::exit(status.code().unwrap_or(1)); } "#, ) .build(); wrapper.cargo("build").run(); let wrapper = &wrapper.bin("wrapper"); let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" fn main() { eprintln!( "MAIN ENV_TEST:{}", std::env!("ENV_TEST") ); } "#, ) .file( ".cargo/config.toml", r#" [env] ENV_TEST = "from-config" "#, ) .build(); p.cargo("run") .env("RUSTC_WORKSPACE_WRAPPER", wrapper) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) WRAPPER ENV_TEST:from-config [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` MAIN ENV_TEST:from-config "#]]) .run(); // Ensure wrapper also maintains the same overridden priority for envs. p.cargo("clean").run(); p.cargo("run") .env("ENV_TEST", "from-env") .env("RUSTC_WORKSPACE_WRAPPER", wrapper) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) WRAPPER ENV_TEST:from-env [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` MAIN ENV_TEST:from-env "#]]) .run(); } #[cargo_test] fn env_changed_defined_in_config_toml() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" use std::env; fn main() { println!( "{}", env!("ENV_TEST") ); } "#, ) .file( ".cargo/config.toml", r#" [env] ENV_TEST = "from-config" "#, ) .build(); p.cargo("run") .with_stdout_data(str![[r#" from-config "#]]) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); p.cargo("run") .env("ENV_TEST", "from-env") .with_stdout_data(str![[r#" from-env "#]]) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); // This identical cargo invocation is to ensure no rebuild happen. p.cargo("run") .env("ENV_TEST", "from-env") .with_stdout_data(str![[r#" from-env "#]]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); } #[cargo_test] fn forced_env_changed_defined_in_config_toml() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" use std::env; fn main() { println!( "{}", env!("ENV_TEST") ); } "#, ) .file( ".cargo/config.toml", r#" [env] ENV_TEST = {value = "from-config", force = true} "#, ) .build(); p.cargo("run") .with_stdout_data(str![[r#" from-config "#]]) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); p.cargo("run") .env("ENV_TEST", "from-env") .with_stdout_data(str![[r#" from-config "#]]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); } #[cargo_test] fn env_changed_defined_in_config_args() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" use std::env; fn main() { println!( "{}", env!("ENV_TEST") ); } "#, ) .build(); p.cargo(r#"run --config 'env.ENV_TEST="one"'"#) .with_stdout_data(str![[r#" one "#]]) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); p.cargo(r#"run --config 'env.ENV_TEST="two"'"#) .with_stdout_data(str![[r#" two "#]]) .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); // This identical cargo invocation is to ensure no rebuild happen. p.cargo(r#"run --config 'env.ENV_TEST="two"'"#) .with_stdout_data(str![[r#" two "#]]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); } cargo-0.86.0/tests/testsuite/cargo_features.rs000064400000000000000000000471311046102023000175520ustar 00000000000000//! Tests for `cargo-features` definitions. use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::{project, registry}; #[cargo_test] fn feature_required() { let p = project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] im-a-teapot = true "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .masquerade_as_nightly_cargo(&["test-dummy-unstable"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: the `im-a-teapot` manifest key is unstable and may not work properly in England Caused by: feature `test-dummy-unstable` is required The package requires the Cargo feature called `test-dummy-unstable`, but that feature is not stabilized in this version of Cargo (1.[..]). Consider adding `cargo-features = ["test-dummy-unstable"]` to the top of Cargo.toml (above the [package] table) to tell Cargo you are opting in to use this unstable feature. See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html for more information about the status of this feature. "#]]) .run(); // Same, but stable. p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: the `im-a-teapot` manifest key is unstable and may not work properly in England Caused by: feature `test-dummy-unstable` is required The package requires the Cargo feature called `test-dummy-unstable`, but that feature is not stabilized in this version of Cargo (1.[..]). Consider trying a newer version of Cargo (this may require the nightly release). See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html for more information about the status of this feature. "#]]) .run(); } #[cargo_test] fn feature_required_dependency() { // The feature has been stabilized by a future version of Cargo, and // someone published something uses it, but this version of Cargo has not // yet stabilized it. Don't suggest editing Cargo.toml, since published // packages shouldn't be edited. Package::new("bar", "1.0.0") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" im-a-teapot = true "#, ) .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .masquerade_as_nightly_cargo(&["test-dummy-unstable"]) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [ERROR] failed to download replaced source registry `crates-io` Caused by: failed to parse manifest at `[ROOT]/home/.cargo/registry/src/-[HASH]/bar-1.0.0/Cargo.toml` Caused by: the `im-a-teapot` manifest key is unstable and may not work properly in England Caused by: feature `test-dummy-unstable` is required The package requires the Cargo feature called `test-dummy-unstable`, but that feature is not stabilized in this version of Cargo (1.[..]). Consider trying a more recent nightly release. See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html for more information about the status of this feature. "#]]) .run(); // Same, but stable. p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to download `bar v1.0.0` Caused by: unable to get packages from source Caused by: failed to download replaced source registry `crates-io` Caused by: failed to parse manifest at `[ROOT]/home/.cargo/registry/src/-[HASH]/bar-1.0.0/Cargo.toml` Caused by: the `im-a-teapot` manifest key is unstable and may not work properly in England Caused by: feature `test-dummy-unstable` is required The package requires the Cargo feature called `test-dummy-unstable`, but that feature is not stabilized in this version of Cargo (1.[..]). Consider trying a newer version of Cargo (this may require the nightly release). See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html for more information about the status of this feature. "#]]) .run(); } #[cargo_test] fn unknown_feature() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["foo"] [package] name = "a" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: unknown cargo feature `foo` "#]]) .run(); } #[cargo_test] fn stable_feature_warns() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["test-dummy-stable"] [package] name = "a" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] the cargo feature `test-dummy-stable` has been stabilized in the 1.0 release and is no longer necessary to be listed in the manifest See https://doc.rust-lang.org/cargo/ for more information about using this feature. [CHECKING] a v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "-Zallow-features is unstable")] fn allow_features() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "a" version = "0.0.1" edition = "2015" authors = [] im-a-teapot = true "#, ) .file("src/lib.rs", "") .build(); p.cargo("-Zallow-features=test-dummy-unstable check") .masquerade_as_nightly_cargo(&["allow-features", "test-dummy-unstable"]) .with_stderr_data(str![[r#" [CHECKING] a v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("-Zallow-features=test-dummy-unstable,print-im-a-teapot -Zprint-im-a-teapot check") .masquerade_as_nightly_cargo(&[ "allow-features", "test-dummy-unstable", "print-im-a-teapot", ]) .with_stdout_data(str![[r#" im-a-teapot = true "#]]) .run(); p.cargo("-Zallow-features=test-dummy-unstable -Zprint-im-a-teapot check") .masquerade_as_nightly_cargo(&[ "allow-features", "test-dummy-unstable", "print-im-a-teapot", ]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the feature `print-im-a-teapot` is not in the list of allowed features: [test-dummy-unstable] "#]]) .run(); p.cargo("-Zallow-features= check") .masquerade_as_nightly_cargo(&["allow-features", "test-dummy-unstable"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: the feature `test-dummy-unstable` is not in the list of allowed features: [] "#]]) .run(); } #[cargo_test(nightly, reason = "-Zallow-features is unstable")] fn allow_features_to_rustc() { let p = project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] "#, ) .file( "src/lib.rs", r#" #![allow(internal_features)] #![feature(rustc_attrs)] "#, ) .build(); p.cargo("-Zallow-features= check") .masquerade_as_nightly_cargo(&["allow-features"]) .with_status(101) .with_stderr_data(str![[r#" [CHECKING] a v0.0.1 ([ROOT]/foo) error[E0725]: the feature `rustc_attrs` is not in the list of allowed features ... "#]]) .run(); p.cargo("-Zallow-features=rustc_attrs check") .masquerade_as_nightly_cargo(&["allow-features"]) .with_stderr_data(str![[r#" [CHECKING] a v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "-Zallow-features is unstable")] fn allow_features_in_cfg() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "a" version = "0.0.1" edition = "2015" authors = [] im-a-teapot = true "#, ) .file( ".cargo/config.toml", r#" [unstable] allow-features = ["test-dummy-unstable", "print-im-a-teapot"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .masquerade_as_nightly_cargo(&[ "allow-features", "test-dummy-unstable", "print-im-a-teapot", ]) .with_stderr_data(str![[r#" [CHECKING] a v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("-Zprint-im-a-teapot check") .masquerade_as_nightly_cargo(&[ "allow-features", "test-dummy-unstable", "print-im-a-teapot", ]) .with_stdout_data(str![[r#" im-a-teapot = true "#]]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("-Zunstable-options check") .masquerade_as_nightly_cargo(&["allow-features", "test-dummy-unstable", "print-im-a-teapot"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the feature `unstable-options` is not in the list of allowed features: [print-im-a-teapot, test-dummy-unstable] "#]]) .run(); // -Zallow-features overrides .cargo/config.toml p.cargo("-Zallow-features=test-dummy-unstable -Zprint-im-a-teapot check") .masquerade_as_nightly_cargo(&[ "allow-features", "test-dummy-unstable", "print-im-a-teapot", ]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the feature `print-im-a-teapot` is not in the list of allowed features: [test-dummy-unstable] "#]]) .run(); p.cargo("-Zallow-features= check") .masquerade_as_nightly_cargo(&[ "allow-features", "test-dummy-unstable", "print-im-a-teapot", ]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: the feature `test-dummy-unstable` is not in the list of allowed features: [] "#]]) .run(); } #[cargo_test] fn nightly_feature_requires_nightly() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "a" version = "0.0.1" edition = "2015" authors = [] im-a-teapot = true "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .masquerade_as_nightly_cargo(&["test-dummy-unstable"]) .with_stderr_data(str![[r#" [CHECKING] a v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: the cargo feature `test-dummy-unstable` requires a nightly version of Cargo, but this is the `stable` channel ... "#]]) .run(); } #[cargo_test] fn nightly_feature_requires_nightly_in_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "b" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a" } "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "a" version = "0.0.1" edition = "2015" authors = [] im-a-teapot = true "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("check") .masquerade_as_nightly_cargo(&["test-dummy-unstable"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] a v0.0.1 ([ROOT]/foo/a) [CHECKING] b v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to get `a` as a dependency of package `b v0.0.1 ([ROOT]/foo)` Caused by: failed to load source for dependency `a` Caused by: Unable to update [ROOT]/foo/a Caused by: failed to parse manifest at `[ROOT]/foo/a/Cargo.toml` Caused by: the cargo feature `test-dummy-unstable` requires a nightly version of Cargo, but this is the `stable` channel ... "#]]) .run(); } #[cargo_test] fn cant_publish() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "a" version = "0.0.1" edition = "2015" authors = [] im-a-teapot = true "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .masquerade_as_nightly_cargo(&["test-dummy-unstable"]) .with_stderr_data(str![[r#" [CHECKING] a v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: the cargo feature `test-dummy-unstable` requires a nightly version of Cargo, but this is the `stable` channel ... "#]]) .run(); } #[cargo_test] fn z_flags_rejected() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "a" version = "0.0.1" edition = "2015" authors = [] im-a-teapot = true "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -Zprint-im-a-teapot") .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `-Z` flag is only accepted on the nightly channel of Cargo, but this is the `stable` channel See [..] "#]]) .run(); p.cargo("check -Zarg") .masquerade_as_nightly_cargo(&["test-dummy-unstable"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] unknown `-Z` flag specified: arg For available unstable features, see https://doc.rust-lang.org/nightly/cargo/reference/unstable.html If you intended to use an unstable rustc feature, try setting `RUSTFLAGS="-Zarg"` "#]]) .run(); p.cargo("check -Zprint-im-a-teapot") .masquerade_as_nightly_cargo(&["test-dummy-unstable"]) .with_stdout_data(str![[r#" im-a-teapot = true "#]]) .with_stderr_data(str![[r#" [CHECKING] a v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn publish_allowed() { let registry = registry::RegistryBuilder::new() .http_api() .http_index() .build(); let p = project() .file( "Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "a" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish") .replace_crates_io(registry.index_url()) .masquerade_as_nightly_cargo(&["test-dummy-unstable"]) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] a v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] a v0.0.1 ([ROOT]/foo) [COMPILING] a v0.0.1 ([ROOT]/foo/target/package/a-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] a v0.0.1 ([ROOT]/foo) [UPLOADED] a v0.0.1 to registry `crates-io` [NOTE] waiting for `a v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] a v0.0.1 at registry `crates-io` "#]]) .run(); } #[cargo_test] fn wrong_position() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" cargo-features = ["test-dummy-unstable"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .masquerade_as_nightly_cargo(&["test-dummy-unstable"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the field `cargo-features` should be set at the top of Cargo.toml before any tables --> Cargo.toml:6:34 | 6 | cargo-features = ["test-dummy-unstable"] | ^^^^^^^^^^^^^^^^^^^^^^^ | "#]]) .run(); } #[cargo_test] fn z_stabilized() { let p = project().file("src/lib.rs", "").build(); p.cargo("check -Z cache-messages") .masquerade_as_nightly_cargo(&["always_nightly"]) .with_stderr_data(str![[r#" [WARNING] flag `-Z cache-messages` has been stabilized in the 1.40 release, and is no longer necessary Message caching is now always enabled. [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check -Z offline") .masquerade_as_nightly_cargo(&["always_nightly"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] flag `-Z offline` has been stabilized in the 1.36 release Offline mode is now available via the --offline CLI option "#]]) .run(); } cargo-0.86.0/tests/testsuite/cargo_fetch/help/mod.rs000064400000000000000000000004771046102023000205360ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("fetch") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_fetch/help/stdout.term.svg000064400000000000000000000104451046102023000224160ustar 00000000000000 Fetch dependencies of a package from the network Usage: cargo[EXE] fetch [OPTIONS] Options: -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Compilation Options: --target [<TRIPLE>] Fetch dependencies for the target triple Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help fetch` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_fetch/mod.rs000064400000000000000000000000121046102023000175670ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_fix/help/mod.rs000064400000000000000000000004751046102023000202310ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("fix") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_fix/help/stdout.term.svg000064400000000000000000000261271046102023000221170ustar 00000000000000 Automatically fix lint warnings reported by rustc Usage: cargo[EXE] fix [OPTIONS] Options: --edition Fix in preparation for the next edition --edition-idioms Fix warnings to migrate to the idioms of an edition --broken-code Fix code even if it already has compiler errors --allow-no-vcs Fix code even if a VCS was not detected --allow-dirty Fix code even if the working directory is dirty --allow-staged Fix code even if the working directory has staged changes --message-format <FMT> Error format -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -p, --package [<SPEC>] Package(s) to fix --workspace Fix all packages in the workspace --exclude <SPEC> Exclude packages from the fixes --all Alias for --workspace (deprecated) Target Selection: --lib Fix only this package's library --bins Fix all binaries --bin [<NAME>] Fix only the specified binary --examples Fix all examples --example [<NAME>] Fix only the specified example --tests Fix all targets that have `test = true` set --test [<NAME>] Fix only the specified test target --benches Fix all targets that have `bench = true` set --bench [<NAME>] Fix only the specified bench target --all-targets Fix all targets (default) Feature Selection: -F, --features <FEATURES> Space or comma separated list of features to activate --all-features Activate all available features --no-default-features Do not activate the `default` feature Compilation Options: -j, --jobs <N> Number of parallel jobs, defaults to # of CPUs. --keep-going Do not abort the build as soon as there is an error -r, --release Fix artifacts in release mode, with optimizations --profile <PROFILE-NAME> Build artifacts with the specified profile --target [<TRIPLE>] Fix for the target triple --target-dir <DIRECTORY> Directory for all generated artifacts --timings[=<FMTS>] Timing output formats (unstable) (comma separated): html, json Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --ignore-rust-version Ignore `rust-version` specification in packages --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help fix` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_fix/mod.rs000064400000000000000000000000121046102023000172640ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_generate_lockfile/help/mod.rs000064400000000000000000000005131046102023000230760ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("generate-lockfile") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_generate_lockfile/help/stdout.term.svg000064400000000000000000000101161046102023000247620ustar 00000000000000 Generate the lockfile for a package Usage: cargo[EXE] generate-lockfile [OPTIONS] Options: -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --ignore-rust-version Ignore `rust-version` specification in packages --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help generate-lockfile` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_generate_lockfile/mod.rs000064400000000000000000000000121046102023000221400ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_git_checkout/help/mod.rs000064400000000000000000000005061046102023000221060ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("git-checkout") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_git_checkout/help/stdout.term.svg000064400000000000000000000011741046102023000237740ustar 00000000000000 The `git-checkout` command has been removed. cargo-0.86.0/tests/testsuite/cargo_git_checkout/mod.rs000064400000000000000000000000121046102023000211460ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_help/help/mod.rs000064400000000000000000000004761046102023000203740ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("help") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_help/help/stdout.term.svg000064400000000000000000000067461046102023000222660ustar 00000000000000 Displays help for a cargo subcommand Usage: cargo[EXE] help [OPTIONS] [COMMAND] Arguments: [COMMAND] Options: -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline cargo-0.86.0/tests/testsuite/cargo_help/mod.rs000064400000000000000000000000121046102023000174260ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_info/basic/mod.rs000064400000000000000000000026211046102023000205220ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); cargo_test_support::registry::Package::new("my-package", "0.1.0") .file( "Cargo.toml", r#" [package] name = "my-package" version = "0.1.0" description = "A package for testing" repository = "https://github.com/hi-rustin/cargo-infromation" documentation = "https://docs.rs/my-package/0.1.0" license = "MIT" edition = "2018" rust-version = "1.50.0" keywords = ["foo", "bar", "baz"] [features] default = ["feature1"] feature1 = [] feature2 = [] [dependencies] foo = "0.1.0" bar = "0.2.0" baz = { version = "0.3.0", optional = true } [[bin]] name = "my_bin" [lib] name = "my_lib" "#, ) .file("src/bin/my_bin.rs", "") .file("src/lib.rs", "") .publish(); snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--registry=dummy-registry") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_info/basic/stderr.term.svg000064400000000000000000000017401046102023000223700ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded my-package v0.1.0 (registry `dummy-registry`) cargo-0.86.0/tests/testsuite/cargo_info/basic/stdout.term.svg000064400000000000000000000041331046102023000224060ustar 00000000000000 my-package #foo #bar #baz A package for testing version: 0.1.0 (from registry `dummy-registry`) license: MIT rust-version: 1.50.0 documentation: https://docs.rs/my-package/0.1.0 repository: https://github.com/hi-rustin/cargo-infromation features: +default = [feature1] feature1 = [] baz = [dep:baz] feature2 = [] cargo-0.86.0/tests/testsuite/cargo_info/features/mod.rs000064400000000000000000000012011046102023000212500ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); cargo_test_support::registry::Package::new("my-package", "0.1.1") .feature("default", &["feature1", "feature2"]) .feature("feature1", &[]) .feature("feature2", &[]) .publish(); snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--registry=dummy-registry") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_info/features/stderr.term.svg000064400000000000000000000017401046102023000231250ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded my-package v0.1.1 (registry `dummy-registry`) cargo-0.86.0/tests/testsuite/cargo_info/features/stdout.term.svg000064400000000000000000000031211046102023000231370ustar 00000000000000 my-package version: 0.1.1 (from registry `dummy-registry`) license: unknown rust-version: unknown features: +default = [feature1, feature2] feature1 = [] feature2 = [] cargo-0.86.0/tests/testsuite/cargo_info/features_activated_over_limit/mod.rs000064400000000000000000000020521046102023000255320ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use super::init_registry_without_token; #[cargo_test] fn case() { const MANY_FEATURES_COUNT: usize = 200; const DEFAULT_FEATURES_COUNT: usize = 100; init_registry_without_token(); let mut test_package = cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package"); let features = (0..MANY_FEATURES_COUNT) .map(|i| format!("eyes{i:03}")) .collect::>(); for name in &features { test_package.feature(name.as_str(), &[]); } let default_features = features .iter() .take(DEFAULT_FEATURES_COUNT) .map(|s| s.as_str()) .collect::>(); test_package.feature("default", &default_features); test_package.publish(); snapbox::cmd::Command::cargo_ui() .arg("info") .arg("your-face") .arg("--registry=dummy-registry") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_info/features_activated_over_limit/stderr.term.svg000064400000000000000000000017561046102023000274110ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded your-face v99999.0.0+my-package (registry `dummy-registry`) cargo-0.86.0/tests/testsuite/cargo_info/features_activated_over_limit/stdout.term.svg000064400000000000000000000031071046102023000274200ustar 00000000000000 your-face version: 99999.0.0+my-package (from registry `dummy-registry`) license: unknown rust-version: unknown features: 101 activated features 100 deactivated features cargo-0.86.0/tests/testsuite/cargo_info/features_activated_over_limit_verbose/mod.rs000064400000000000000000000021041046102023000272550ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use super::init_registry_without_token; #[cargo_test] fn case() { const MANY_FEATURES_COUNT: usize = 200; const DEFAULT_FEATURES_COUNT: usize = 100; init_registry_without_token(); let mut test_package = cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package"); let features = (0..MANY_FEATURES_COUNT) .map(|i| format!("eyes{i:03}")) .collect::>(); for name in &features { test_package.feature(name.as_str(), &[]); } let default_features = features .iter() .take(DEFAULT_FEATURES_COUNT) .map(|s| s.as_str()) .collect::>(); test_package.feature("default", &default_features); test_package.publish(); snapbox::cmd::Command::cargo_ui() .arg("info") .arg("your-face") .arg("--verbose") .arg("--registry=dummy-registry") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_info/features_activated_over_limit_verbose/stderr.term.svg000064400000000000000000000017561046102023000311360ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded your-face v99999.0.0+my-package (registry `dummy-registry`) cargo-0.86.0/tests/testsuite/cargo_info/features_activated_over_limit_verbose/stdout.term.svg000064400000000000000000000505671046102023000311610ustar 00000000000000 your-face version: 99999.0.0+my-package (from registry `dummy-registry`) license: unknown rust-version: unknown features: +default = [eyes000, eyes001, eyes002, eyes003, eyes004, eyes005, eyes006, eyes007, eyes008, eyes009, eyes010, eyes011, eyes012, eyes013, eyes014, eyes015, eyes016, eyes017, eyes018, eyes019, eyes020, eyes021, eyes022, eyes023, eyes024, eyes025, eyes026, eyes027, eyes028, eyes029, eyes030, eyes031, eyes032, eyes033, eyes034, eyes035, eyes036, eyes037, eyes038, eyes039, eyes040, eyes041, eyes042, eyes043, eyes044, eyes045, eyes046, eyes047, eyes048, eyes049, eyes050, eyes051, eyes052, eyes053, eyes054, eyes055, eyes056, eyes057, eyes058, eyes059, eyes060, eyes061, eyes062, eyes063, eyes064, eyes065, eyes066, eyes067, eyes068, eyes069, eyes070, eyes071, eyes072, eyes073, eyes074, eyes075, eyes076, eyes077, eyes078, eyes079, eyes080, eyes081, eyes082, eyes083, eyes084, eyes085, eyes086, eyes087, eyes088, eyes089, eyes090, eyes091, eyes092, eyes093, eyes094, eyes095, eyes096, eyes097, eyes098, eyes099] eyes000 = [] eyes001 = [] eyes002 = [] eyes003 = [] eyes004 = [] eyes005 = [] eyes006 = [] eyes007 = [] eyes008 = [] eyes009 = [] eyes010 = [] eyes011 = [] eyes012 = [] eyes013 = [] eyes014 = [] eyes015 = [] eyes016 = [] eyes017 = [] eyes018 = [] eyes019 = [] eyes020 = [] eyes021 = [] eyes022 = [] eyes023 = [] eyes024 = [] eyes025 = [] eyes026 = [] eyes027 = [] eyes028 = [] eyes029 = [] eyes030 = [] eyes031 = [] eyes032 = [] eyes033 = [] eyes034 = [] eyes035 = [] eyes036 = [] eyes037 = [] eyes038 = [] eyes039 = [] eyes040 = [] eyes041 = [] eyes042 = [] eyes043 = [] eyes044 = [] eyes045 = [] eyes046 = [] eyes047 = [] eyes048 = [] eyes049 = [] eyes050 = [] eyes051 = [] eyes052 = [] eyes053 = [] eyes054 = [] eyes055 = [] eyes056 = [] eyes057 = [] eyes058 = [] eyes059 = [] eyes060 = [] eyes061 = [] eyes062 = [] eyes063 = [] eyes064 = [] eyes065 = [] eyes066 = [] eyes067 = [] eyes068 = [] eyes069 = [] eyes070 = [] eyes071 = [] eyes072 = [] eyes073 = [] eyes074 = [] eyes075 = [] eyes076 = [] eyes077 = [] eyes078 = [] eyes079 = [] eyes080 = [] eyes081 = [] eyes082 = [] eyes083 = [] eyes084 = [] eyes085 = [] eyes086 = [] eyes087 = [] eyes088 = [] eyes089 = [] eyes090 = [] eyes091 = [] eyes092 = [] eyes093 = [] eyes094 = [] eyes095 = [] eyes096 = [] eyes097 = [] eyes098 = [] eyes099 = [] eyes100 = [] eyes101 = [] eyes102 = [] eyes103 = [] eyes104 = [] eyes105 = [] eyes106 = [] eyes107 = [] eyes108 = [] eyes109 = [] eyes110 = [] eyes111 = [] eyes112 = [] eyes113 = [] eyes114 = [] eyes115 = [] eyes116 = [] eyes117 = [] eyes118 = [] eyes119 = [] eyes120 = [] eyes121 = [] eyes122 = [] eyes123 = [] eyes124 = [] eyes125 = [] eyes126 = [] eyes127 = [] eyes128 = [] eyes129 = [] eyes130 = [] eyes131 = [] eyes132 = [] eyes133 = [] eyes134 = [] eyes135 = [] eyes136 = [] eyes137 = [] eyes138 = [] eyes139 = [] eyes140 = [] eyes141 = [] eyes142 = [] eyes143 = [] eyes144 = [] eyes145 = [] eyes146 = [] eyes147 = [] eyes148 = [] eyes149 = [] eyes150 = [] eyes151 = [] eyes152 = [] eyes153 = [] eyes154 = [] eyes155 = [] eyes156 = [] eyes157 = [] eyes158 = [] eyes159 = [] eyes160 = [] eyes161 = [] eyes162 = [] eyes163 = [] eyes164 = [] eyes165 = [] eyes166 = [] eyes167 = [] eyes168 = [] eyes169 = [] eyes170 = [] eyes171 = [] eyes172 = [] eyes173 = [] eyes174 = [] eyes175 = [] eyes176 = [] eyes177 = [] eyes178 = [] eyes179 = [] eyes180 = [] eyes181 = [] eyes182 = [] eyes183 = [] eyes184 = [] eyes185 = [] eyes186 = [] eyes187 = [] eyes188 = [] eyes189 = [] eyes190 = [] eyes191 = [] eyes192 = [] eyes193 = [] eyes194 = [] eyes195 = [] eyes196 = [] eyes197 = [] eyes198 = [] eyes199 = [] cargo-0.86.0/tests/testsuite/cargo_info/features_deactivated_over_limit/mod.rs000064400000000000000000000020511046102023000260420ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use super::init_registry_without_token; #[cargo_test] fn case() { const MANY_FEATURES_COUNT: usize = 200; const DEFAULT_FEATURES_COUNT: usize = 20; init_registry_without_token(); let mut test_package = cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package"); let features = (0..MANY_FEATURES_COUNT) .map(|i| format!("eyes{i:03}")) .collect::>(); for name in &features { test_package.feature(name.as_str(), &[]); } let default_features = features .iter() .take(DEFAULT_FEATURES_COUNT) .map(|s| s.as_str()) .collect::>(); test_package.feature("default", &default_features); test_package.publish(); snapbox::cmd::Command::cargo_ui() .arg("info") .arg("your-face") .arg("--registry=dummy-registry") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_info/features_deactivated_over_limit/stderr.term.svg000064400000000000000000000017561046102023000277220ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded your-face v99999.0.0+my-package (registry `dummy-registry`) cargo-0.86.0/tests/testsuite/cargo_info/features_deactivated_over_limit/stdout.term.svg000064400000000000000000000061521046102023000277340ustar 00000000000000 your-face version: 99999.0.0+my-package (from registry `dummy-registry`) license: unknown rust-version: unknown features: +default = [eyes000, eyes001, eyes002, eyes003, eyes004, eyes005, eyes006, eyes007, eyes008, eyes009, eyes010, eyes011, eyes012, eyes013, eyes014, eyes015, eyes016, eyes017, eyes018, eyes019] eyes000 = [] eyes001 = [] eyes002 = [] eyes003 = [] eyes004 = [] eyes005 = [] eyes006 = [] eyes007 = [] eyes008 = [] eyes009 = [] eyes010 = [] eyes011 = [] eyes012 = [] eyes013 = [] eyes014 = [] eyes015 = [] eyes016 = [] eyes017 = [] eyes018 = [] eyes019 = [] 180 deactivated features cargo-0.86.0/tests/testsuite/cargo_info/git_dependency/mod.rs000064400000000000000000000020571046102023000224250ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{basic_manifest, file, git, project}; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); let baz = git::new("baz", |project| { project .file("Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("src/lib.rs", "") }); let foo = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] baz = {{ git = '{}' }} "#, baz.url() ), ) .file("src/lib.rs", "") .build(); let project_root = foo.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("info") .arg_line("--verbose foo") .current_dir(cwd) .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(""); } cargo-0.86.0/tests/testsuite/cargo_info/git_dependency/stdout.term.svg000064400000000000000000000026371046102023000243150ustar 00000000000000 foo version: 0.1.0 (from ./) license: unknown rust-version: unknown dependencies: +baz ([ROOTURL]/baz) cargo-0.86.0/tests/testsuite/cargo_info/help/mod.rs000064400000000000000000000004331046102023000203700ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("info") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(""); } cargo-0.86.0/tests/testsuite/cargo_info/help/stdout.term.svg000064400000000000000000000102741046102023000222600ustar 00000000000000 Display information about a package Usage: cargo[EXE] info [OPTIONS] <SPEC> Options: --index <INDEX> Registry index URL to search packages in --registry <REGISTRY> Registry to search packages in -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: <SPEC> Package to inspect Manifest Options: --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help info` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_info/mod.rs000064400000000000000000000023571046102023000174470ustar 00000000000000mod basic; mod features; mod features_activated_over_limit; mod features_activated_over_limit_verbose; mod features_deactivated_over_limit; mod git_dependency; mod help; mod not_found; mod path_dependency; mod pick_msrv_compatible_package; mod pick_msrv_compatible_package_within_ws; mod pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws; mod specify_empty_version_with_url; mod specify_version_outside_ws; mod specify_version_with_url_but_registry_is_not_matched; mod specify_version_within_ws_and_conflict_with_lockfile; mod specify_version_within_ws_and_match_with_lockfile; mod transitive_dependency_within_ws; mod verbose; mod with_frozen_outside_ws; mod with_frozen_within_ws; mod with_locked_outside_ws; mod with_locked_within_ws; mod with_locked_within_ws_and_pick_the_package; mod with_offline; mod with_quiet; mod within_ws; mod within_ws_and_pick_ws_package; mod within_ws_with_alternative_registry; mod within_ws_without_lockfile; mod without_requiring_registry_auth; // Initialize the registry without a token. // Otherwise, it will try to list owners of the crate and fail. pub(crate) fn init_registry_without_token() { let _reg = cargo_test_support::registry::RegistryBuilder::new() .no_configure_token() .build(); } cargo-0.86.0/tests/testsuite/cargo_info/not_found/mod.rs000064400000000000000000000012561046102023000214370ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{compare::assert_ui, current_dir, file, Project}; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("info") .arg("unknown") .arg("--registry=dummy-registry") .current_dir(cwd) .assert() .failure() .stdout_eq("") .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_info/not_found/stderr.term.svg000064400000000000000000000016541046102023000233060ustar 00000000000000 Updating `dummy-registry` index error: could not find `unknown` in registry `[ROOTURL]/registry` cargo-0.86.0/tests/testsuite/cargo_info/path_dependency/mod.rs000064400000000000000000000012201046102023000225650ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{compare::assert_ui, current_dir, file, Project}; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("info") .arg_line("--verbose foo") .current_dir(cwd) .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(""); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_info/path_dependency/stdout.term.svg000064400000000000000000000026441046102023000244640ustar 00000000000000 foo version: 0.0.0 (from ./) license: unknown rust-version: unknown dependencies: +crate1 (./crates/crate1) cargo-0.86.0/tests/testsuite/cargo_info/pick_msrv_compatible_package/mod.rs000064400000000000000000000012671046102023000253150ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); cargo_test_support::registry::Package::new("my-package", "0.1.1+my-package") .rust_version("1.0.0") .publish(); cargo_test_support::registry::Package::new("my-package", "0.2.0+my-package") .rust_version("1.9876.0") .publish(); snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--registry=dummy-registry") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_info/pick_msrv_compatible_package/stderr.term.svg000064400000000000000000000017531046102023000271620ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded my-package v0.1.1+my-package (registry `dummy-registry`) cargo-0.86.0/tests/testsuite/cargo_info/pick_msrv_compatible_package/stdout.term.svg000064400000000000000000000024521046102023000271760ustar 00000000000000 my-package version: 0.1.1+my-package (latest 0.2.0+my-package from registry `dummy-registry`) license: unknown rust-version: 1.0.0 cargo-0.86.0/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/mod.rs000064400000000000000000000020351046102023000274020ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{compare::assert_ui, current_dir, file, Project}; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); cargo_test_support::registry::Package::new("my-package", "0.1.0").publish(); cargo_test_support::registry::Package::new("my-package", "0.2.0") .rust_version("1.0.0") .publish(); cargo_test_support::registry::Package::new("my-package", "0.2.1") .rust_version("1.9876.0") .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root.join("crate1"); snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--registry=dummy-registry") .current_dir(cwd) .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/stderr.term.svg000064400000000000000000000017401046102023000312510ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded my-package v0.2.0 (registry `dummy-registry`) cargo-0.86.0/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/stdout.term.svg000064400000000000000000000024241046102023000312700ustar 00000000000000 my-package version: 0.2.0 (latest 0.2.1 from registry `dummy-registry`) license: unknown rust-version: 1.0.0 ././@LongLink00006440000000000000000000000153000000000000007772Lustar cargo-0.86.0/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/mod.rscargo-0.86.0/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/000064400000000000000000000020331046102023000325560ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{compare::assert_ui, current_dir, file, Project}; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); cargo_test_support::registry::Package::new("my-package", "0.1.0").publish(); cargo_test_support::registry::Package::new("my-package", "0.2.0") .rust_version("1.0.0") .publish(); cargo_test_support::registry::Package::new("my-package", "0.2.1") .rust_version("1.70.0") .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root.join("crate1"); snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--registry=dummy-registry") .current_dir(cwd) .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } ././@LongLink00006440000000000000000000000164000000000000007774Lustar cargo-0.86.0/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/stderr.term.svgcargo-0.86.0/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/000064400000000000000000000017401046102023000325620ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded my-package v0.2.0 (registry `dummy-registry`) ././@LongLink00006440000000000000000000000164000000000000007774Lustar cargo-0.86.0/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/stdout.term.svgcargo-0.86.0/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/000064400000000000000000000024241046102023000325620ustar 00000000000000 my-package version: 0.2.0 (latest 0.2.1 from registry `dummy-registry`) license: unknown rust-version: 1.0.0 cargo-0.86.0/tests/testsuite/cargo_info/specify_empty_version_with_url/mod.rs000064400000000000000000000011411046102023000257770ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{file, registry::RegistryBuilder}; #[cargo_test] fn case() { let _ = RegistryBuilder::new() .alternative() .no_configure_token() .build(); cargo_test_support::registry::Package::new("my-package", "99999.0.0-alpha.1+my-package") .alternative(true) .publish(); snapbox::cmd::Command::cargo_ui() .arg("info") .arg("https://crates.io") .arg("--registry=alternative") .assert() .failure() .stdout_eq("") .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_info/specify_empty_version_with_url/stderr.term.svg000064400000000000000000000017071046102023000276540ustar 00000000000000 error: invalid package ID specification: `https://crates.io` Caused by: package name cannot be empty cargo-0.86.0/tests/testsuite/cargo_info/specify_version_outside_ws/mod.rs000064400000000000000000000011241046102023000251120ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); for ver in ["0.1.1+my-package", "0.2.0+my-package", "0.2.3+my-package"] { cargo_test_support::registry::Package::new("my-package", ver).publish(); } snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package@0.2") .arg("--registry=dummy-registry") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_info/specify_version_outside_ws/stderr.term.svg000064400000000000000000000017531046102023000267670ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded my-package v0.2.3+my-package (registry `dummy-registry`) cargo-0.86.0/tests/testsuite/cargo_info/specify_version_outside_ws/stdout.term.svg000064400000000000000000000023561046102023000270060ustar 00000000000000 my-package version: 0.2.3+my-package (from registry `dummy-registry`) license: unknown rust-version: unknown cargo-0.86.0/tests/testsuite/cargo_info/specify_version_with_url_but_registry_is_not_matched/mod.rs000064400000000000000000000011541046102023000324270ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{file, registry::RegistryBuilder}; #[cargo_test] fn case() { let _ = RegistryBuilder::new() .alternative() .no_configure_token() .build(); cargo_test_support::registry::Package::new("my-package", "99999.0.0-alpha.1+my-package") .alternative(true) .publish(); snapbox::cmd::Command::cargo_ui() .arg("info") .arg("https://crates.io/my-package") .arg("--registry=alternative") .assert() .failure() .stdout_eq("") .stderr_eq(file!["stderr.term.svg"]); } ././@LongLink00006440000000000000000000000155000000000000007774Lustar cargo-0.86.0/tests/testsuite/cargo_info/specify_version_with_url_but_registry_is_not_matched/stderr.term.svgcargo-0.86.0/tests/testsuite/cargo_info/specify_version_with_url_but_registry_is_not_matched/stderr.000064400000000000000000000017131046102023000326070ustar 00000000000000 Updating `alternative` index error: could not find `https://crates.io/my-package` in registry `[ROOTURL]/alternative-registry` cargo-0.86.0/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/mod.rs000064400000000000000000000020211046102023000323430ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{compare::assert_ui, current_dir, file, Project}; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package@0.4") .arg("--registry=dummy-registry") .current_dir(cwd) .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } ././@LongLink00006440000000000000000000000155000000000000007774Lustar cargo-0.86.0/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/stderr.term.svgcargo-0.86.0/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/stderr.000064400000000000000000000017531046102023000325350ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded my-package v0.4.1+my-package (registry `dummy-registry`) ././@LongLink00006440000000000000000000000155000000000000007774Lustar cargo-0.86.0/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/stdout.term.svgcargo-0.86.0/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/stdout.000064400000000000000000000025261046102023000325530ustar 00000000000000 my-package version: 0.4.1+my-package (latest 99999.0.0+my-package from registry `dummy-registry`) license: unknown rust-version: unknown cargo-0.86.0/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/mod.rs000064400000000000000000000020211046102023000316360ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{compare::assert_ui, current_dir, file, Project}; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package@0.1") .arg("--registry=dummy-registry") .current_dir(cwd) .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } ././@LongLink00006440000000000000000000000152000000000000007771Lustar cargo-0.86.0/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/stderr.term.svgcargo-0.86.0/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/stderr.ter000064400000000000000000000024371046102023000325430ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded my-package v0.1.1+my-package (registry `dummy-registry`) note: to see how you depend on my-package, run `cargo tree --invert --package my-package@0.1.1+my-package` ././@LongLink00006440000000000000000000000152000000000000007771Lustar cargo-0.86.0/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/stdout.term.svgcargo-0.86.0/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/stdout.ter000064400000000000000000000027771046102023000325710ustar 00000000000000 my-package version: 0.1.1+my-package (latest 99999.0.0+my-package) license: unknown rust-version: unknown documentation: https://docs.rs/my-package/0.1.1+my-package crates.io: https://crates.io/crates/my-package/0.1.1+my-package cargo-0.86.0/tests/testsuite/cargo_info/transitive_dependency_within_ws/direct1-stderr.term.svg000064400000000000000000000022111046102023000313130ustar 00000000000000 Downloading crates ... Downloaded my-package v1.0.0 (registry `dummy-registry`) note: to see how you depend on my-package, run `cargo tree --invert --package my-package@1.0.0` cargo-0.86.0/tests/testsuite/cargo_info/transitive_dependency_within_ws/direct1-stdout.term.svg000064400000000000000000000027201046102023000313370ustar 00000000000000 my-package version: 1.0.0 (latest 99.0.0) license: unknown rust-version: unknown documentation: https://docs.rs/my-package/1.0.0 crates.io: https://crates.io/crates/my-package/1.0.0 cargo-0.86.0/tests/testsuite/cargo_info/transitive_dependency_within_ws/direct2-stderr.term.svg000064400000000000000000000015421046102023000313220ustar 00000000000000 note: to see how you depend on my-package, run `cargo tree --invert --package my-package@2.0.0` cargo-0.86.0/tests/testsuite/cargo_info/transitive_dependency_within_ws/direct2-stdout.term.svg000064400000000000000000000027201046102023000313400ustar 00000000000000 my-package version: 2.0.0 (latest 99.0.0) license: unknown rust-version: unknown documentation: https://docs.rs/my-package/2.0.0 crates.io: https://crates.io/crates/my-package/2.0.0 cargo-0.86.0/tests/testsuite/cargo_info/transitive_dependency_within_ws/mod.rs000064400000000000000000000056161046102023000261310ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{compare::assert_ui, current_dir, file, Project}; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); // 99.0.0 is unused for ver in ["1.0.0", "2.0.0", "3.0.0", "99.0.0"] { cargo_test_support::registry::Package::new("my-package", ver).publish(); } // Dep1 depends on 3.0.0, Dep2 depends on 2.0.0, Dep3 depends on 1.0.0 cargo_test_support::registry::Package::new("dep1", "1.0.0") .dep("my-package", "1.0.0") .publish(); cargo_test_support::registry::Package::new("dep2", "1.0.0") .dep("my-package", "2.0.0") .publish(); cargo_test_support::registry::Package::new("dep3", "1.0.0") .dep("my-package", "3.0.0") .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let transitive1_root = project_root.join("crates/transitive1"); let transitive2_root = project_root.join("crates/transitive2"); let direct1_root = project_root.join("crates/direct1"); let direct2_root = project_root.join("crates/direct2"); let ws_directory = &project_root; let transitive1_directory = &transitive1_root; let transitive2_directory = &transitive2_root; let direct1_directory = &direct1_root; let direct2_directory = &direct2_root; snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--registry=dummy-registry") .current_dir(ws_directory) .assert() .stdout_eq(file!["ws-stdout.term.svg"]) .stderr_eq(file!["ws-stderr.term.svg"]); snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--registry=dummy-registry") .current_dir(transitive1_directory) .assert() .stdout_eq(file!["transitive1-stdout.term.svg"]) .stderr_eq(file!["transitive1-stderr.term.svg"]); snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--registry=dummy-registry") .current_dir(transitive2_directory) .assert() .stdout_eq(file!["transitive2-stdout.term.svg"]) .stderr_eq(file!["transitive2-stderr.term.svg"]); snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--registry=dummy-registry") .current_dir(direct1_directory) .assert() .stdout_eq(file!["direct1-stdout.term.svg"]) .stderr_eq(file!["direct1-stderr.term.svg"]); snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--registry=dummy-registry") .current_dir(direct2_directory) .assert() .stdout_eq(file!["direct2-stdout.term.svg"]) .stderr_eq(file!["direct2-stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_info/transitive_dependency_within_ws/transitive1-stderr.term.svg000064400000000000000000000015421046102023000322370ustar 00000000000000 note: to see how you depend on my-package, run `cargo tree --invert --package my-package@2.0.0` cargo-0.86.0/tests/testsuite/cargo_info/transitive_dependency_within_ws/transitive1-stdout.term.svg000064400000000000000000000027201046102023000322550ustar 00000000000000 my-package version: 2.0.0 (latest 99.0.0) license: unknown rust-version: unknown documentation: https://docs.rs/my-package/2.0.0 crates.io: https://crates.io/crates/my-package/2.0.0 cargo-0.86.0/tests/testsuite/cargo_info/transitive_dependency_within_ws/transitive2-stderr.term.svg000064400000000000000000000015421046102023000322400ustar 00000000000000 note: to see how you depend on my-package, run `cargo tree --invert --package my-package@2.0.0` cargo-0.86.0/tests/testsuite/cargo_info/transitive_dependency_within_ws/transitive2-stdout.term.svg000064400000000000000000000027201046102023000322560ustar 00000000000000 my-package version: 2.0.0 (latest 99.0.0) license: unknown rust-version: unknown documentation: https://docs.rs/my-package/2.0.0 crates.io: https://crates.io/crates/my-package/2.0.0 cargo-0.86.0/tests/testsuite/cargo_info/transitive_dependency_within_ws/ws-stderr.term.svg000064400000000000000000000024111046102023000304130ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded my-package v2.0.0 (registry `dummy-registry`) note: to see how you depend on my-package, run `cargo tree --invert --package my-package@2.0.0` cargo-0.86.0/tests/testsuite/cargo_info/transitive_dependency_within_ws/ws-stdout.term.svg000064400000000000000000000027201046102023000304350ustar 00000000000000 my-package version: 2.0.0 (latest 99.0.0) license: unknown rust-version: unknown documentation: https://docs.rs/my-package/2.0.0 crates.io: https://crates.io/crates/my-package/2.0.0 cargo-0.86.0/tests/testsuite/cargo_info/verbose/mod.rs000064400000000000000000000026521046102023000211120ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); cargo_test_support::registry::Package::new("my-package", "0.1.0") .file( "Cargo.toml", r#" [package] name = "my-package" version = "0.1.0" description = "A package for testing" repository = "https://github.com/hi-rustin/cargo-infromation" documentation = "https://docs.rs/my-package/0.1.0" license = "MIT" edition = "2018" rust-version = "1.50.0" keywords = ["foo", "bar", "baz"] [features] default = ["feature1"] feature1 = [] feature2 = [] [dependencies] foo = "0.1.0" bar = "0.2.0" baz = { version = "0.3.0", optional = true } [[bin]] name = "my_bin" [lib] name = "my_lib" "#, ) .file("src/bin/my_bin.rs", "") .file("src/lib.rs", "") .publish(); snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--verbose") .arg("--registry=dummy-registry") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_info/verbose/stderr.term.svg000064400000000000000000000017401046102023000227540ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded my-package v0.1.0 (registry `dummy-registry`) cargo-0.86.0/tests/testsuite/cargo_info/verbose/stdout.term.svg000064400000000000000000000050011046102023000227650ustar 00000000000000 my-package #foo #bar #baz A package for testing version: 0.1.0 (from registry `dummy-registry`) license: MIT rust-version: 1.50.0 documentation: https://docs.rs/my-package/0.1.0 repository: https://github.com/hi-rustin/cargo-infromation features: +default = [feature1] feature1 = [] baz = [dep:baz] feature2 = [] dependencies: +bar@0.2.0 +foo@0.1.0 baz@0.3.0 cargo-0.86.0/tests/testsuite/cargo_info/with_frozen_outside_ws/mod.rs000064400000000000000000000013641046102023000242470ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); 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(); } snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--frozen") .arg("--registry=dummy-registry") .assert() .failure() .stdout_eq("") .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_info/with_frozen_outside_ws/stderr.term.svg000064400000000000000000000014161046102023000261120ustar 00000000000000 error: the option `--frozen` can only be used within a workspace cargo-0.86.0/tests/testsuite/cargo_info/with_frozen_within_ws/mod.rs000064400000000000000000000020151046102023000240670ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{compare::assert_ui, current_dir, file, Project}; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("info") .arg("unknown") .arg("--frozen") .arg("--registry=dummy-registry") .current_dir(cwd) .assert() .failure() .stdout_eq("") .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_info/with_frozen_within_ws/stderr.term.svg000064400000000000000000000014161046102023000257400ustar 00000000000000 error: could not find `unknown` in registry `[ROOTURL]/registry` cargo-0.86.0/tests/testsuite/cargo_info/with_locked_outside_ws/mod.rs000064400000000000000000000013641046102023000242050ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); 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(); } snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--locked") .arg("--registry=dummy-registry") .assert() .failure() .stdout_eq("") .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_info/with_locked_outside_ws/stderr.term.svg000064400000000000000000000014161046102023000260500ustar 00000000000000 error: the option `--locked` can only be used within a workspace cargo-0.86.0/tests/testsuite/cargo_info/with_locked_within_ws/mod.rs000064400000000000000000000020151046102023000240250ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{compare::assert_ui, current_dir, file, Project}; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("info") .arg("unknown") .arg("--locked") .arg("--registry=dummy-registry") .current_dir(cwd) .assert() .failure() .stdout_eq("") .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_info/with_locked_within_ws/stderr.term.svg000064400000000000000000000016541046102023000257020ustar 00000000000000 Updating `dummy-registry` index error: could not find `unknown` in registry `[ROOTURL]/registry` cargo-0.86.0/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/mod.rs000064400000000000000000000020461046102023000301740ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{compare::assert_ui, current_dir, file, Project}; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--locked") .arg("--registry=dummy-registry") .current_dir(cwd) .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/stderr.term.svg000064400000000000000000000017571046102023000320510ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded my-package v99999.0.0+my-package (registry `dummy-registry`) cargo-0.86.0/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/stdout.term.svg000064400000000000000000000023621046102023000320610ustar 00000000000000 my-package version: 99999.0.0+my-package (from registry `dummy-registry`) license: unknown rust-version: unknown cargo-0.86.0/tests/testsuite/cargo_info/with_offline/mod.rs000064400000000000000000000013651046102023000221220ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); 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(); } snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--offline") .arg("--registry=dummy-registry") .assert() .failure() .stdout_eq("") .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_info/with_offline/stderr.term.svg000064400000000000000000000014211046102023000237600ustar 00000000000000 error: could not find `my-package` in registry `[ROOTURL]/registry` cargo-0.86.0/tests/testsuite/cargo_info/with_quiet/mod.rs000064400000000000000000000013631046102023000216250ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); 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(); } snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--quiet") .arg("--registry=dummy-registry") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(""); } cargo-0.86.0/tests/testsuite/cargo_info/with_quiet/stdout.term.svg000064400000000000000000000023621046102023000235110ustar 00000000000000 my-package version: 99999.0.0+my-package (from registry `dummy-registry`) license: unknown rust-version: unknown cargo-0.86.0/tests/testsuite/cargo_info/within_ws/mod.rs000064400000000000000000000020151046102023000214510ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{compare::assert_ui, current_dir, file, Project}; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--registry=dummy-registry") .current_dir(cwd) .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_info/within_ws/stderr.term.svg000064400000000000000000000024371046102023000233260ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded my-package v0.1.1+my-package (registry `dummy-registry`) note: to see how you depend on my-package, run `cargo tree --invert --package my-package@0.1.1+my-package` cargo-0.86.0/tests/testsuite/cargo_info/within_ws/stdout.term.svg000064400000000000000000000027771046102023000233540ustar 00000000000000 my-package version: 0.1.1+my-package (latest 99999.0.0+my-package) license: unknown rust-version: unknown documentation: https://docs.rs/my-package/0.1.1+my-package crates.io: https://crates.io/crates/my-package/0.1.1+my-package cargo-0.86.0/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/mod.rs000064400000000000000000000015431046102023000254720ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{compare::assert_ui, current_dir, file, Project}; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); cargo_test_support::registry::Package::new("my-package", "0.1.1+my-package").publish(); cargo_test_support::registry::Package::new("cargo-list-test-fixture", "0.1.1+my-package") .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("info") .arg("cargo-list-test-fixture") .current_dir(cwd) .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(""); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/stdout.term.svg000064400000000000000000000023311046102023000273520ustar 00000000000000 cargo-list-test-fixture version: 0.2.0 (from ./) license: unknown rust-version: unknown cargo-0.86.0/tests/testsuite/cargo_info/within_ws_with_alternative_registry/mod.rs000064400000000000000000000016441046102023000270410ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{compare::assert_ui, registry::RegistryBuilder, Project}; use cargo_test_support::{current_dir, file}; #[cargo_test] fn case() { let _ = RegistryBuilder::new() .alternative() .no_configure_token() .build(); cargo_test_support::registry::Package::new("my-package", "99999.0.0-alpha.1+my-package") .alternative(true) .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--registry=alternative") .current_dir(cwd) .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_info/within_ws_with_alternative_registry/stderr.term.svg000064400000000000000000000021521046102023000307010ustar 00000000000000 Updating crates.io index Updating `alternative` index Downloading crates ... Downloaded my-package v99999.0.0-alpha.1+my-package (registry `alternative`) cargo-0.86.0/tests/testsuite/cargo_info/within_ws_with_alternative_registry/stdout.term.svg000064400000000000000000000023671046102023000307300ustar 00000000000000 my-package version: 99999.0.0-alpha.1+my-package (from registry `alternative`) license: unknown rust-version: unknown cargo-0.86.0/tests/testsuite/cargo_info/within_ws_without_lockfile/mod.rs000064400000000000000000000016501046102023000251100ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{compare::assert_ui, current_dir, file, Project}; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); for ver in [ "0.1.1+my-package", "0.2.0+my-package", "0.2.3+my-package", "0.4.1+my-package", ] { cargo_test_support::registry::Package::new("my-package", ver).publish(); } let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--registry=dummy-registry") .current_dir(cwd) .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_info/within_ws_without_lockfile/stderr.term.svg000064400000000000000000000032301046102023000267510ustar 00000000000000 Updating `dummy-registry` index Locking 1 package to latest compatible version Adding my-package v0.2.3+my-package (available: v0.4.1+my-package) Downloading crates ... Downloaded my-package v0.2.3+my-package (registry `dummy-registry`) note: to see how you depend on my-package, run `cargo tree --invert --package my-package@0.2.3+my-package` cargo-0.86.0/tests/testsuite/cargo_info/within_ws_without_lockfile/stdout.term.svg000064400000000000000000000027731046102023000270030ustar 00000000000000 my-package version: 0.2.3+my-package (latest 0.4.1+my-package) license: unknown rust-version: unknown documentation: https://docs.rs/my-package/0.2.3+my-package crates.io: https://crates.io/crates/my-package/0.2.3+my-package cargo-0.86.0/tests/testsuite/cargo_info/without_requiring_registry_auth/mod.rs000064400000000000000000000014441046102023000262040ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::{compare::assert_ui, current_dir, file, Project}; use super::init_registry_without_token; #[cargo_test] fn case() { init_registry_without_token(); cargo_test_support::registry::Package::new("my-package", "0.1.1+my-package").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("info") .arg("my-package") .arg("--registry=dummy-registry") .current_dir(cwd) .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_info/without_requiring_registry_auth/stderr.term.svg000064400000000000000000000024371046102023000300540ustar 00000000000000 Updating `dummy-registry` index Downloading crates ... Downloaded my-package v0.1.1+my-package (registry `dummy-registry`) note: to see how you depend on my-package, run `cargo tree --invert --package my-package@0.1.1+my-package` cargo-0.86.0/tests/testsuite/cargo_info/without_requiring_registry_auth/stdout.term.svg000064400000000000000000000026731046102023000300750ustar 00000000000000 my-package version: 0.1.1+my-package license: unknown rust-version: unknown documentation: https://docs.rs/my-package/0.1.1+my-package crates.io: https://crates.io/crates/my-package/0.1.1+my-package cargo-0.86.0/tests/testsuite/cargo_init/auto_git/in/mod.rs000064400000000000000000000003171046102023000216720ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::prelude::*; use cargo_test_support::{command_is_available, paths, Project}; use std::fs; use std::process::Command; use crate::test_root; cargo-0.86.0/tests/testsuite/cargo_init/auto_git/mod.rs000064400000000000000000000012621046102023000212640ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); assert!(project_root.join(".git").is_dir()); } cargo-0.86.0/tests/testsuite/cargo_init/auto_git/stderr.term.svg000064400000000000000000000017301046102023000231310ustar 00000000000000 Creating library package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_explicit/in/src/main.rs000064400000000000000000000001061046102023000265600ustar 00000000000000fn main() { println!("Check that our file is not overwritten") } cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_explicit/mod.rs000064400000000000000000000012131046102023000252160ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --bin --vcs none") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); } cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_explicit/stderr.term.svg000064400000000000000000000017451046102023000270750ustar 00000000000000 Creating binary (application) package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_explicit_nosrc/in/main.rs000064400000000000000000000001061046102023000271750ustar 00000000000000fn main() { println!("Check that our file is not overwritten") } cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_explicit_nosrc/mod.rs000064400000000000000000000012741046102023000264310ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --bin --vcs none") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join("src").is_dir()); } cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_explicit_nosrc/stderr.term.svg000064400000000000000000000017451046102023000303010ustar 00000000000000 Creating binary (application) package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_implicit/in/src/main.rs000064400000000000000000000001061046102023000265510ustar 00000000000000fn main() { println!("Check that our file is not overwritten") } cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_implicit/mod.rs000064400000000000000000000012051046102023000252100ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --vcs none") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); } cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_implicit/stderr.term.svg000064400000000000000000000017451046102023000270660ustar 00000000000000 Creating binary (application) package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_implicit_namenosrc/in/case.rs000064400000000000000000000001061046102023000300160ustar 00000000000000fn main() { println!("Check that our file is not overwritten") } cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_implicit_namenosrc/mod.rs000064400000000000000000000012661046102023000272640ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --vcs none") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join("src").is_dir()); } cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_implicit_namenosrc/stderr.term.svg000064400000000000000000000017451046102023000311330ustar 00000000000000 Creating binary (application) package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_implicit_namesrc/in/src/case.rs000064400000000000000000000001061046102023000302500ustar 00000000000000fn main() { println!("Check that our file is not overwritten") } cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_implicit_namesrc/mod.rs000064400000000000000000000012771046102023000267310ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --vcs none") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join("src/main.rs").is_file()); } cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_implicit_namesrc/stderr.term.svg000064400000000000000000000017451046102023000305760ustar 00000000000000 Creating binary (application) package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_implicit_nosrc/in/main.rs000064400000000000000000000001061046102023000271660ustar 00000000000000fn main() { println!("Check that our file is not overwritten") } cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_implicit_nosrc/mod.rs000064400000000000000000000012661046102023000264230ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --vcs none") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join("src").is_dir()); } cargo-0.86.0/tests/testsuite/cargo_init/bin_already_exists_implicit_nosrc/stderr.term.svg000064400000000000000000000017451046102023000302720ustar 00000000000000 Creating binary (application) package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/both_lib_and_bin/mod.rs000064400000000000000000000007011046102023000227020ustar 00000000000000use cargo_test_support::file; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { let cwd = paths::root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib --bin") .current_dir(&cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert!(!cwd.join("Cargo.toml").is_file()); } cargo-0.86.0/tests/testsuite/cargo_init/both_lib_and_bin/stderr.term.svg000064400000000000000000000013761046102023000245600ustar 00000000000000 error: can't specify both lib and binary outputs cargo-0.86.0/tests/testsuite/cargo_init/cant_create_library_when_both_binlib_present/in/case.rs000064400000000000000000000000151046102023000313160ustar 00000000000000fn main() {} cargo-0.86.0/tests/testsuite/cargo_init/cant_create_library_when_both_binlib_present/in/lib.rs000064400000000000000000000000121046102023000311460ustar 00000000000000fn f() {} cargo-0.86.0/tests/testsuite/cargo_init/cant_create_library_when_both_binlib_present/mod.rs000064400000000000000000000010111046102023000305510ustar 00000000000000use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib") .current_dir(project_root) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_init/cant_create_library_when_both_binlib_present/stderr.term.svg000064400000000000000000000016741046102023000324350ustar 00000000000000 Creating library package error: cannot have a package with multiple libraries, found both `case.rs` and `lib.rs` cargo-0.86.0/tests/testsuite/cargo_init/confused_by_multiple_lib_files/in/lib.rs000064400000000000000000000000371046102023000262700ustar 00000000000000fn f() { println!("lib.rs"); } cargo-0.86.0/tests/testsuite/cargo_init/confused_by_multiple_lib_files/in/src/lib.rs000064400000000000000000000000431046102023000270540ustar 00000000000000fn f() { println!("src/lib.rs"); } cargo-0.86.0/tests/testsuite/cargo_init/confused_by_multiple_lib_files/mod.rs000064400000000000000000000012761046102023000257010ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --vcs none") .current_dir(project_root) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join("Cargo.toml").is_file()); } cargo-0.86.0/tests/testsuite/cargo_init/confused_by_multiple_lib_files/out/lib.rs000064400000000000000000000000371046102023000264710ustar 00000000000000fn f() { println!("lib.rs"); } cargo-0.86.0/tests/testsuite/cargo_init/confused_by_multiple_lib_files/out/src/lib.rs000064400000000000000000000000431046102023000272550ustar 00000000000000fn f() { println!("src/lib.rs"); } cargo-0.86.0/tests/testsuite/cargo_init/confused_by_multiple_lib_files/stderr.term.svg000064400000000000000000000014501046102023000275400ustar 00000000000000 error: cannot have a package with multiple libraries, found both `src/lib.rs` and `lib.rs` cargo-0.86.0/tests/testsuite/cargo_init/creates_binary_when_both_binlib_present/in/case.rs000064400000000000000000000000151046102023000303140ustar 00000000000000fn main() {} cargo-0.86.0/tests/testsuite/cargo_init/creates_binary_when_both_binlib_present/in/lib.rs000064400000000000000000000000121046102023000301440ustar 00000000000000fn f() {} cargo-0.86.0/tests/testsuite/cargo_init/creates_binary_when_both_binlib_present/mod.rs000064400000000000000000000012131046102023000275530ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --bin --vcs none") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); } cargo-0.86.0/tests/testsuite/cargo_init/creates_binary_when_both_binlib_present/stderr.term.svg000064400000000000000000000017451046102023000314320ustar 00000000000000 Creating binary (application) package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/creates_binary_when_instructed_and_has_lib_file/in/case.rs000064400000000000000000000000121046102023000317640ustar 00000000000000fn f() {} cargo-0.86.0/tests/testsuite/cargo_init/creates_binary_when_instructed_and_has_lib_file/mod.rs000064400000000000000000000012131046102023000312260ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --bin --vcs none") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); } ././@LongLink00006440000000000000000000000150000000000000007767Lustar cargo-0.86.0/tests/testsuite/cargo_init/creates_binary_when_instructed_and_has_lib_file/stderr.term.svgcargo-0.86.0/tests/testsuite/cargo_init/creates_binary_when_instructed_and_has_lib_file/stderr.term.000064400000000000000000000022601046102023000323560ustar 00000000000000 Creating binary (application) package warning: file `case.rs` seems to be a library file note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/creates_library_when_instructed_and_has_bin_file/in/case.rs000064400000000000000000000000151046102023000321510ustar 00000000000000fn main() {} cargo-0.86.0/tests/testsuite/cargo_init/creates_library_when_instructed_and_has_bin_file/mod.rs000064400000000000000000000012131046102023000314100ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib --vcs none") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); } ././@LongLink00006440000000000000000000000151000000000000007770Lustar cargo-0.86.0/tests/testsuite/cargo_init/creates_library_when_instructed_and_has_bin_file/stderr.term.svgcargo-0.86.0/tests/testsuite/cargo_init/creates_library_when_instructed_and_has_bin_file/stderr.term000064400000000000000000000022601046102023000324620ustar 00000000000000 Creating library package warning: file `case.rs` seems to be a binary (application) file note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/empty_dir/mod.rs000064400000000000000000000003171046102023000214450ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::prelude::*; use cargo_test_support::{command_is_available, paths, Project}; use std::fs; use std::process::Command; use crate::test_root; cargo-0.86.0/tests/testsuite/cargo_init/explicit_bin_with_git/in/mod.rs000064400000000000000000000003171046102023000244260ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::prelude::*; use cargo_test_support::{command_is_available, paths, Project}; use std::fs; use std::process::Command; use crate::test_root; cargo-0.86.0/tests/testsuite/cargo_init/explicit_bin_with_git/mod.rs000064400000000000000000000012121046102023000240130ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --vcs git --bin") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); } cargo-0.86.0/tests/testsuite/cargo_init/explicit_bin_with_git/stderr.term.svg000064400000000000000000000017451046102023000256730ustar 00000000000000 Creating binary (application) package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/formats_source/in/rustfmt.toml000064400000000000000000000000171046102023000243630ustar 00000000000000tab_spaces = 2 cargo-0.86.0/tests/testsuite/cargo_init/formats_source/mod.rs000064400000000000000000000021241046102023000225020ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::{process, Project}; #[cargo_test] fn case() { // This cannot use `requires_rustfmt` because rustfmt is not available in // the rust-lang/rust environment. Additionally, if running cargo without // rustup (but with rustup installed), this test also fails due to HOME // preventing the proxy from choosing a toolchain. if let Err(e) = process("rustfmt").arg("-V").exec_with_output() { eprintln!("skipping test, rustfmt not available:\n{e:?}"); return; } let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib --vcs none") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); } cargo-0.86.0/tests/testsuite/cargo_init/formats_source/stderr.term.svg000064400000000000000000000017301046102023000243510ustar 00000000000000 Creating library package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/fossil_autodetect/in/.fossil/.keep000064400000000000000000000000001046102023000247410ustar 00000000000000cargo-0.86.0/tests/testsuite/cargo_init/fossil_autodetect/mod.rs000064400000000000000000000012621046102023000231710ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join(".git").is_dir()); } cargo-0.86.0/tests/testsuite/cargo_init/fossil_autodetect/stderr.term.svg000064400000000000000000000017301046102023000250360ustar 00000000000000 Creating library package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/git_autodetect/mod.rs000064400000000000000000000014261046102023000224570ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::str; use std::fs; #[cargo_test] fn case() { let project_root = &paths::root().join("foo"); // Need to create `.git` dir manually because it cannot be tracked under a git repo fs::create_dir_all(project_root.join(".git")).unwrap(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(project_root.join(".git").is_dir()); } cargo-0.86.0/tests/testsuite/cargo_init/git_autodetect/stderr.term.svg000064400000000000000000000017301046102023000243220ustar 00000000000000 Creating library package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/git_ignore_exists_no_conflicting_entries/in/.gitignore000064400000000000000000000000141046102023000312450ustar 00000000000000**/some.filecargo-0.86.0/tests/testsuite/cargo_init/git_ignore_exists_no_conflicting_entries/mod.rs000064400000000000000000000013001046102023000277730ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib --edition 2015") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(project_root.join(".git").is_dir()); } cargo-0.86.0/tests/testsuite/cargo_init/git_ignore_exists_no_conflicting_entries/stderr.term.svg000064400000000000000000000017301046102023000316470ustar 00000000000000 Creating library package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/help/mod.rs000064400000000000000000000004761046102023000204070ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("init") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_init/help/stdout.term.svg000064400000000000000000000126311046102023000222670ustar 00000000000000 Create a new cargo package in an existing directory Usage: cargo[EXE] init [OPTIONS] [PATH] Arguments: [PATH] [default: .] Options: --vcs <VCS> Initialize a new repository for the given version control system, overriding a global configuration. [possible values: git, hg, pijul, fossil, none] --bin Use a binary (application) template [default] --lib Use a library template --edition <YEAR> Edition to set for the crate generated [possible values: 2015, 2018, 2021, 2024] --name <NAME> Set the resulting package name, defaults to the directory name --registry <REGISTRY> Registry to use -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help init` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_init/ignores_failure_to_format_source/in/rustfmt.toml000064400000000000000000000000171046102023000301370ustar 00000000000000tab_spaces = 2 cargo-0.86.0/tests/testsuite/cargo_init/ignores_failure_to_format_source/mod.rs000064400000000000000000000013111046102023000262530ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib --vcs none") .env("PATH", "") // pretend that `rustfmt` is missing .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); } cargo-0.86.0/tests/testsuite/cargo_init/ignores_failure_to_format_source/stderr.term.svg000064400000000000000000000017301046102023000301250ustar 00000000000000 Creating library package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/inferred_bin_with_git/in/main.rs000064400000000000000000000000151046102023000245430ustar 00000000000000fn main() {} cargo-0.86.0/tests/testsuite/cargo_init/inferred_bin_with_git/mod.rs000064400000000000000000000012041046102023000237710ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --vcs git") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); } cargo-0.86.0/tests/testsuite/cargo_init/inferred_bin_with_git/stderr.term.svg000064400000000000000000000017451046102023000256500ustar 00000000000000 Creating binary (application) package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/inferred_lib_with_git/in/lib.rs000064400000000000000000000000121046102023000243600ustar 00000000000000fn f() {} cargo-0.86.0/tests/testsuite/cargo_init/inferred_lib_with_git/mod.rs000064400000000000000000000012041046102023000237670ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --vcs git") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); } cargo-0.86.0/tests/testsuite/cargo_init/inferred_lib_with_git/stderr.term.svg000064400000000000000000000017451046102023000256460ustar 00000000000000 Creating binary (application) package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/inherit_workspace_package_table/mod.rs000064400000000000000000000013201046102023000260060ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("init") .args(["crates/foo"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_init/inherit_workspace_package_table/stderr.term.svg000064400000000000000000000017451046102023000276660ustar 00000000000000 Creating binary (application) package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/invalid_dir_name/mod.rs000064400000000000000000000007701046102023000227400ustar 00000000000000use cargo_test_support::file; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::str; use std::fs; #[cargo_test] fn case() { let foo = &paths::root().join("foo.bar"); fs::create_dir_all(foo).unwrap(); snapbox::cmd::Command::cargo_ui() .arg_line("init") .current_dir(foo) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert!(!foo.join("Cargo.toml").is_file()); } cargo-0.86.0/tests/testsuite/cargo_init/invalid_dir_name/stderr.term.svg000064400000000000000000000033331046102023000246030ustar 00000000000000 Creating binary (application) package error: invalid character `.` in package name: `foo.bar`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters) If you need a package name to not match the directory name, consider using --name flag. If you need a binary with the name "foo.bar", use a valid package name, and set the binary name to be different from the package. This can be done by setting the binary filename to `src/bin/foo.bar.rs` or change the name in Cargo.toml with: [[bin]] name = "foo.bar" path = "src/main.rs" cargo-0.86.0/tests/testsuite/cargo_init/lib_already_exists_nosrc/in/lib.rs000064400000000000000000000000001046102023000251050ustar 00000000000000cargo-0.86.0/tests/testsuite/cargo_init/lib_already_exists_nosrc/mod.rs000064400000000000000000000012771046102023000245310ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --vcs none") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join("src/main.rs").is_file()); } cargo-0.86.0/tests/testsuite/cargo_init/lib_already_exists_nosrc/stderr.term.svg000064400000000000000000000017451046102023000263760ustar 00000000000000 Creating binary (application) package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/lib_already_exists_src/in/src/lib.rs000064400000000000000000000000121046102023000253420ustar 00000000000000fn f() {} cargo-0.86.0/tests/testsuite/cargo_init/lib_already_exists_src/mod.rs000064400000000000000000000012771046102023000241740ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --vcs none") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join("src/main.rs").is_file()); } cargo-0.86.0/tests/testsuite/cargo_init/lib_already_exists_src/stderr.term.svg000064400000000000000000000017451046102023000260410ustar 00000000000000 Creating binary (application) package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/mercurial_autodetect/in/.hg/.keep000064400000000000000000000000001046102023000245240ustar 00000000000000cargo-0.86.0/tests/testsuite/cargo_init/mercurial_autodetect/mod.rs000064400000000000000000000012621046102023000236550ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join(".git").is_dir()); } cargo-0.86.0/tests/testsuite/cargo_init/mercurial_autodetect/stderr.term.svg000064400000000000000000000017301046102023000255220ustar 00000000000000 Creating library package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/mod.rs000064400000000000000000000023601046102023000174510ustar 00000000000000//! Tests for the `cargo init` command. mod auto_git; mod bin_already_exists_explicit; mod bin_already_exists_explicit_nosrc; mod bin_already_exists_implicit; mod bin_already_exists_implicit_namenosrc; mod bin_already_exists_implicit_namesrc; mod bin_already_exists_implicit_nosrc; mod both_lib_and_bin; mod cant_create_library_when_both_binlib_present; mod confused_by_multiple_lib_files; mod creates_binary_when_both_binlib_present; mod creates_binary_when_instructed_and_has_lib_file; mod creates_library_when_instructed_and_has_bin_file; mod explicit_bin_with_git; mod formats_source; mod fossil_autodetect; mod git_autodetect; mod git_ignore_exists_no_conflicting_entries; mod help; mod ignores_failure_to_format_source; mod inferred_bin_with_git; mod inferred_lib_with_git; mod inherit_workspace_package_table; mod invalid_dir_name; mod lib_already_exists_nosrc; mod lib_already_exists_src; mod mercurial_autodetect; mod multibin_project_name_clash; #[cfg(not(windows))] mod no_filename; #[cfg(unix)] mod path_contains_separator; mod pijul_autodetect; mod reserved_name; mod simple_bin; mod simple_git; mod simple_git_ignore_exists; mod simple_hg; mod simple_hg_ignore_exists; mod simple_lib; mod unknown_flags; mod with_argument; mod workspace_add_member; cargo-0.86.0/tests/testsuite/cargo_init/multibin_project_name_clash/in/case.rs000064400000000000000000000000421046102023000257310ustar 00000000000000fn main() { println!("foo.rs"); } cargo-0.86.0/tests/testsuite/cargo_init/multibin_project_name_clash/in/main.rs000064400000000000000000000000431046102023000257430ustar 00000000000000fn main() { println!("main.rs"); } cargo-0.86.0/tests/testsuite/cargo_init/multibin_project_name_clash/mod.rs000064400000000000000000000013041046102023000251710ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib --vcs none") .current_dir(project_root) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join("Cargo.toml").is_file()); } cargo-0.86.0/tests/testsuite/cargo_init/multibin_project_name_clash/out/case.rs000064400000000000000000000000421046102023000261320ustar 00000000000000fn main() { println!("foo.rs"); } cargo-0.86.0/tests/testsuite/cargo_init/multibin_project_name_clash/out/main.rs000064400000000000000000000000431046102023000261440ustar 00000000000000fn main() { println!("main.rs"); } cargo-0.86.0/tests/testsuite/cargo_init/multibin_project_name_clash/stderr.term.svg000064400000000000000000000020001046102023000270300ustar 00000000000000 error: multiple possible binary sources found: main.rs case.rs cannot automatically generate Cargo.toml as the main target would be ambiguous cargo-0.86.0/tests/testsuite/cargo_init/no_filename/mod.rs000064400000000000000000000006061046102023000217260ustar 00000000000000use cargo_test_support::file; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cfg(not(windows))] #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg_line("init /") .current_dir(paths::root()) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_init/no_filename/stderr.term.svg000064400000000000000000000014331046102023000235720ustar 00000000000000 error: cannot auto-detect package name from path "/" ; use --name to override cargo-0.86.0/tests/testsuite/cargo_init/path_contains_separator/in/.keep000064400000000000000000000000001046102023000245560ustar 00000000000000cargo-0.86.0/tests/testsuite/cargo_init/path_contains_separator/mod.rs000064400000000000000000000015171046102023000243660ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::{t, Project}; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root().join("test:ing"); if !project_root.exists() { t!(std::fs::create_dir(&project_root)); } snapbox::cmd::Command::cargo_ui() .arg_line("init --bin --vcs none --edition 2015 --name testing") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join(".gitignore").is_file()); } cargo-0.86.0/tests/testsuite/cargo_init/path_contains_separator/stderr.term.svg000064400000000000000000000025311046102023000262300ustar 00000000000000 Creating binary (application) package warning: the path `[ROOT]/case/test:ing/.` contains invalid PATH characters (usually `:`, `;`, or `"`) It is recommended to use a different name to avoid problems. note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/pijul_autodetect/in/.pijul/.keep000064400000000000000000000000001046102023000244110ustar 00000000000000cargo-0.86.0/tests/testsuite/cargo_init/pijul_autodetect/mod.rs000064400000000000000000000012621046102023000230150ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join(".git").is_dir()); } cargo-0.86.0/tests/testsuite/cargo_init/pijul_autodetect/stderr.term.svg000064400000000000000000000017301046102023000246620ustar 00000000000000 Creating library package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/reserved_name/mod.rs000064400000000000000000000010321046102023000222630ustar 00000000000000use std::fs; use cargo_test_support::file; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { let project_root = &paths::root().join("test"); fs::create_dir_all(project_root).unwrap(); snapbox::cmd::Command::cargo_ui() .arg_line("init") .current_dir(project_root) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert!(!project_root.join("Cargo.toml").is_file()); } cargo-0.86.0/tests/testsuite/cargo_init/reserved_name/stderr.term.svg000064400000000000000000000032621046102023000241370ustar 00000000000000 Creating binary (application) package error: the name `test` cannot be used as a package name, it conflicts with Rust's built-in test library If you need a package name to not match the directory name, consider using --name flag. If you need a binary with the name "test", use a valid package name, and set the binary name to be different from the package. This can be done by setting the binary filename to `src/bin/test.rs` or change the name in Cargo.toml with: [[bin]] name = "test" path = "src/main.rs" cargo-0.86.0/tests/testsuite/cargo_init/simple_bin/in/mod.rs000064400000000000000000000003171046102023000222000ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::prelude::*; use cargo_test_support::{command_is_available, paths, Project}; use std::fs; use std::process::Command; use crate::test_root; cargo-0.86.0/tests/testsuite/cargo_init/simple_bin/mod.rs000064400000000000000000000016051046102023000215730ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --bin --vcs none --edition 2015") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join(".gitignore").is_file()); snapbox::cmd::Command::cargo_ui() .current_dir(project_root) .arg("build") .assert() .success(); assert!(project.bin("case").is_file()); } cargo-0.86.0/tests/testsuite/cargo_init/simple_bin/stderr.term.svg000064400000000000000000000017451046102023000234450ustar 00000000000000 Creating binary (application) package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/simple_git/in/mod.rs000064400000000000000000000003171046102023000222130ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::prelude::*; use cargo_test_support::{command_is_available, paths, Project}; use std::fs; use std::process::Command; use crate::test_root; cargo-0.86.0/tests/testsuite/cargo_init/simple_git/mod.rs000064400000000000000000000012731046102023000216070ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib --vcs git") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(project_root.join(".git").is_dir()); } cargo-0.86.0/tests/testsuite/cargo_init/simple_git/stderr.term.svg000064400000000000000000000017301046102023000234520ustar 00000000000000 Creating library package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/simple_git_ignore_exists/in/.gitignore000064400000000000000000000000241046102023000260130ustar 00000000000000/target **/some.filecargo-0.86.0/tests/testsuite/cargo_init/simple_git_ignore_exists/mod.rs000064400000000000000000000015061046102023000245500ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib --edition 2015") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(project_root.join(".git").is_dir()); snapbox::cmd::Command::cargo_ui() .current_dir(project_root) .arg("build") .assert() .success(); } cargo-0.86.0/tests/testsuite/cargo_init/simple_git_ignore_exists/stderr.term.svg000064400000000000000000000017301046102023000264140ustar 00000000000000 Creating library package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/simple_hg/in/mod.rs000064400000000000000000000003171046102023000220260ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::prelude::*; use cargo_test_support::{command_is_available, paths, Project}; use std::fs; use std::process::Command; use crate::test_root; cargo-0.86.0/tests/testsuite/cargo_init/simple_hg/mod.rs000064400000000000000000000013141046102023000214160ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test(requires = "hg")] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib --vcs hg") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join(".git").is_dir()); } cargo-0.86.0/tests/testsuite/cargo_init/simple_hg/stderr.term.svg000064400000000000000000000017301046102023000232650ustar 00000000000000 Creating library package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/simple_hg_ignore_exists/in/.hg/.keep000064400000000000000000000000001046102023000252310ustar 00000000000000cargo-0.86.0/tests/testsuite/cargo_init/simple_hg_ignore_exists/in/.hgignore000064400000000000000000000000121046102023000254360ustar 00000000000000^/somefilecargo-0.86.0/tests/testsuite/cargo_init/simple_hg_ignore_exists/mod.rs000064400000000000000000000012621046102023000243620ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join(".git").is_dir()); } cargo-0.86.0/tests/testsuite/cargo_init/simple_hg_ignore_exists/stderr.term.svg000064400000000000000000000017301046102023000262270ustar 00000000000000 Creating library package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/simple_lib/in/mod.rs000064400000000000000000000003171046102023000221760ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::prelude::*; use cargo_test_support::{command_is_available, paths, Project}; use std::fs; use std::process::Command; use crate::test_root; cargo-0.86.0/tests/testsuite/cargo_init/simple_lib/mod.rs000064400000000000000000000016051046102023000215710ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --lib --vcs none --edition 2015") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); assert!(!project_root.join(".gitignore").is_file()); snapbox::cmd::Command::cargo_ui() .current_dir(project_root) .arg("build") .assert() .success(); assert!(!project.bin("foo").is_file()); } cargo-0.86.0/tests/testsuite/cargo_init/simple_lib/stderr.term.svg000064400000000000000000000017301046102023000234350ustar 00000000000000 Creating library package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/unknown_flags/mod.rs000064400000000000000000000005701046102023000223250ustar 00000000000000use cargo_test_support::file; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg_line("init foo --flag") .current_dir(paths::root()) .assert() .code(1) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_init/unknown_flags/stderr.term.svg000064400000000000000000000031121046102023000241650ustar 00000000000000 error: unexpected argument '--flag' found tip: to pass '--flag' as a value, use '-- --flag' Usage: cargo[EXE] init <PATH> For more information, try '--help'. cargo-0.86.0/tests/testsuite/cargo_init/with_argument/in/foo/.keep000064400000000000000000000000001046102023000233040ustar 00000000000000cargo-0.86.0/tests/testsuite/cargo_init/with_argument/mod.rs000064400000000000000000000012111046102023000223200ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init foo --vcs none") .current_dir(project_root) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), project_root); } cargo-0.86.0/tests/testsuite/cargo_init/with_argument/stderr.term.svg000064400000000000000000000017451046102023000242010ustar 00000000000000 Creating binary (application) package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_init/workspace_add_member/mod.rs000064400000000000000000000012471046102023000236110ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = &project.root(); snapbox::cmd::Command::cargo_ui() .arg_line("init --bin --vcs none") .current_dir(project_root.join("crates").join("foo")) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_init/workspace_add_member/stderr.term.svg000064400000000000000000000021721046102023000254540ustar 00000000000000 Creating binary (application) package Adding `foo` as member of workspace at `[ROOT]/case` note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_install/help/mod.rs000064400000000000000000000005011046102023000210770ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("install") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_install/help/stdout.term.svg000064400000000000000000000257561046102023000230060ustar 00000000000000 Install a Rust binary Usage: cargo[EXE] install [OPTIONS] [CRATE[@<VER>]]... Arguments: [CRATE[@<VER>]]... Select the package from the given source Options: --version <VERSION> Specify a version to install --index <INDEX> Registry index to install from --registry <REGISTRY> Registry to use --git <URL> Git URL to install the specified crate from --branch <BRANCH> Branch to use when installing from git --tag <TAG> Tag to use when installing from git --rev <SHA> Specific commit to use when installing from git --path <PATH> Filesystem path to local crate to install from --root <DIR> Directory to install packages into -f, --force Force overwriting existing crates or binaries -n, --dry-run Perform all checks without installing (unstable) --no-track Do not save tracking information --list List all installed packages and their versions --message-format <FMT> Error format --debug Build in debug mode (with the 'dev' profile) instead of release mode -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --ignore-rust-version Ignore `rust-version` specification in packages --lockfile-path <PATH> Path to Cargo.lock (unstable) --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Target Selection: --bin [<NAME>] Install only the specified binary --bins Install all binaries --example [<NAME>] Install only the specified example --examples Install all examples Feature Selection: -F, --features <FEATURES> Space or comma separated list of features to activate --all-features Activate all available features --no-default-features Do not activate the `default` feature Compilation Options: -j, --jobs <N> Number of parallel jobs, defaults to # of CPUs. --keep-going Do not abort the build as soon as there is an error --profile <PROFILE-NAME> Install artifacts with the specified profile --target [<TRIPLE>] Build for the target triple --target-dir <DIRECTORY> Directory for all generated artifacts --timings[=<FMTS>] Timing output formats (unstable) (comma separated): html, json Run `cargo help install` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_install/mod.rs000064400000000000000000000000121046102023000201440ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_locate_project/help/mod.rs000064400000000000000000000005101046102023000224260ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("locate-project") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_locate_project/help/stdout.term.svg000064400000000000000000000101651046102023000243210ustar 00000000000000 Print a JSON representation of a Cargo.toml file's location Usage: cargo[EXE] locate-project [OPTIONS] Options: --workspace Locate Cargo.toml of the workspace root --message-format <FMT> Output representation [possible values: json, plain] -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --manifest-path <PATH> Path to Cargo.toml --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help locate-project` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_locate_project/mod.rs000064400000000000000000000000121046102023000214730ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_login/help/mod.rs000064400000000000000000000004771046102023000205550ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("login") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_login/help/stdout.term.svg000064400000000000000000000102761046102023000224370ustar 00000000000000 Log in to a registry. Usage: cargo[EXE] login [OPTIONS] [TOKEN] [-- [args]...] Arguments: [TOKEN] [args]... Additional arguments for the credential provider Options: --registry <REGISTRY> Registry to use -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help login` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_login/mod.rs000064400000000000000000000000121046102023000176060ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_logout/help/mod.rs000064400000000000000000000005001046102023000207410ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("logout") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_logout/help/stdout.term.svg000064400000000000000000000071731046102023000226420ustar 00000000000000 Remove an API token from the registry locally Usage: cargo[EXE] logout [OPTIONS] Options: --registry <REGISTRY> Registry to use -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help logout` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_logout/mod.rs000064400000000000000000000000121046102023000200070ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_metadata/help/mod.rs000064400000000000000000000005021046102023000212120ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("metadata") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_metadata/help/stdout.term.svg000064400000000000000000000131351046102023000231040ustar 00000000000000 Output the resolved dependencies of a package, the concrete used versions including overrides, in machine-readable format Usage: cargo[EXE] metadata [OPTIONS] Options: --filter-platform <TRIPLE> Only include resolve dependencies matching the given target-triple --no-deps Output information only about the workspace members and don't fetch dependencies --format-version <VERSION> Format version [possible values: 1] -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Feature Selection: -F, --features <FEATURES> Space or comma separated list of features to activate --all-features Activate all available features --no-default-features Do not activate the `default` feature Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help metadata` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_metadata/mod.rs000064400000000000000000000000121046102023000202560ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_non_workspace/mod.rs000064400000000000000000000013211046102023000251670ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("new") .args(["bar", "--lib"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_non_workspace/stderr.term.svg000064400000000000000000000017361046102023000270460ustar 00000000000000 Creating library `bar` package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/mod.rs000064400000000000000000000013171046102023000310270ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("new") .args(["crates/foo"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } ././@LongLink00006440000000000000000000000146000000000000007774Lustar cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/stderr.term.svgcargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/stderr.term.sv000064400000000000000000000022001046102023000325150ustar 00000000000000 Creating binary (application) `foo` package Adding `foo` as member of workspace at `[ROOT]/case` note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/mod.rs000064400000000000000000000013171046102023000272520ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("new") .args(["crates/foo"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/stderr.term.svg000064400000000000000000000022001046102023000311070ustar 00000000000000 Creating binary (application) `foo` package Adding `foo` as member of workspace at `[ROOT]/case` note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/mod.rs000064400000000000000000000014061046102023000317410ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; let package_path = cwd.join("crates").join("foo"); snapbox::cmd::Command::cargo_ui() .arg("new") .args([package_path]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } ././@LongLink00006440000000000000000000000153000000000000007772Lustar cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/stderr.term.svgcargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/stderr.te000064400000000000000000000022001046102023000324420ustar 00000000000000 Creating binary (application) `foo` package Adding `foo` as member of workspace at `[ROOT]/case` note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/mod.rs000064400000000000000000000013171046102023000303050ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("new") .args(["crates/foo"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/stderr.term.svg000064400000000000000000000022001046102023000321420ustar 00000000000000 Creating binary (application) `foo` package Adding `foo` as member of workspace at `[ROOT]/case` note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/mod.rs000064400000000000000000000013171046102023000301210ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("new") .args(["crates/foo"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/stderr.term.svg000064400000000000000000000017531046102023000317720ustar 00000000000000 Creating binary (application) `foo` package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/mod.rs000064400000000000000000000013171046102023000300720ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("new") .args(["crates/foo"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/stderr.term.svg000064400000000000000000000017531046102023000317430ustar 00000000000000 Creating binary (application) `foo` package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_without_members/mod.rs000064400000000000000000000013211046102023000276120ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("new") .args(["bar", "--lib"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_new/add_members_to_workspace_without_members/stderr.term.svg000064400000000000000000000021631046102023000314640ustar 00000000000000 Creating library `bar` package Adding `bar` as member of workspace at `[ROOT]/case` note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_new/empty_name/in/.keep000064400000000000000000000000001046102023000216300ustar 00000000000000cargo-0.86.0/tests/testsuite/cargo_new/empty_name/mod.rs000064400000000000000000000013261046102023000214360ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("new") .args(["foo", "--name", ""]) .current_dir(cwd) .assert() .failure() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_new/empty_name/out/.keep000064400000000000000000000000001046102023000220310ustar 00000000000000cargo-0.86.0/tests/testsuite/cargo_new/empty_name/stderr.term.svg000064400000000000000000000016301046102023000233010ustar 00000000000000 Creating binary (application) `` package error: package name cannot be empty cargo-0.86.0/tests/testsuite/cargo_new/help/mod.rs000064400000000000000000000004751046102023000202340ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("new") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_new/help/stdout.term.svg000064400000000000000000000126161046102023000221200ustar 00000000000000 Create a new cargo package at <path> Usage: cargo[EXE] new [OPTIONS] <PATH> Arguments: <PATH> Options: --vcs <VCS> Initialize a new repository for the given version control system, overriding a global configuration. [possible values: git, hg, pijul, fossil, none] --bin Use a binary (application) template [default] --lib Use a library template --edition <YEAR> Edition to set for the crate generated [possible values: 2015, 2018, 2021, 2024] --name <NAME> Set the resulting package name, defaults to the directory name --registry <REGISTRY> Registry to use -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help new` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_new/ignore_current_dir_workspace/mod.rs000064400000000000000000000013631046102023000252420ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root.join("workspace"); snapbox::cmd::Command::cargo_ui() .arg("new") .args(["../out-of-workspace", "--lib"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_new/ignore_current_dir_workspace/stderr.term.svg000064400000000000000000000017531046102023000271120ustar 00000000000000 Creating library `out-of-workspace` package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_new/inherit_workspace_lints/mod.rs000064400000000000000000000013171046102023000242310ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("new") .args(["crates/foo"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_new/inherit_workspace_lints/stderr.term.svg000064400000000000000000000017531046102023000261020ustar 00000000000000 Creating binary (application) `foo` package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_new/inherit_workspace_package_table/mod.rs000064400000000000000000000013171046102023000256420ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("new") .args(["crates/foo"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_new/inherit_workspace_package_table/stderr.term.svg000064400000000000000000000017531046102023000275130ustar 00000000000000 Creating binary (application) `foo` package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/mod.rs000064400000000000000000000013441046102023000304100ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("new") .args(["crates/foo", "--edition", "2021"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/stderr.term.svg000064400000000000000000000017531046102023000322610ustar 00000000000000 Creating binary (application) `foo` package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/mod.rs000064400000000000000000000013441046102023000306250ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("new") .args(["crates/foo", "--registry", "foo"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/stderr.term.svg000064400000000000000000000017531046102023000324760ustar 00000000000000 Creating binary (application) `foo` package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/mod.rs000064400000000000000000000013171046102023000311720ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("new") .args(["crates/foo"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } ././@LongLink00006440000000000000000000000147000000000000007775Lustar cargo-0.86.0/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/stderr.term.svgcargo-0.86.0/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/stderr.term.s000064400000000000000000000017531046102023000325060ustar 00000000000000 Creating binary (application) `foo` package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_new/mod.rs000064400000000000000000000013121046102023000172730ustar 00000000000000mod add_members_to_non_workspace; mod add_members_to_workspace_format_previous_items; mod add_members_to_workspace_format_sorted; mod add_members_to_workspace_with_absolute_package_path; mod add_members_to_workspace_with_empty_members; mod add_members_to_workspace_with_exclude_list; mod add_members_to_workspace_with_members_glob; mod add_members_to_workspace_without_members; mod empty_name; mod help; mod ignore_current_dir_workspace; mod inherit_workspace_lints; mod inherit_workspace_package_table; mod inherit_workspace_package_table_with_edition; mod inherit_workspace_package_table_with_registry; mod inherit_workspace_package_table_without_version; mod not_inherit_workspace_package_table_if_not_members; cargo-0.86.0/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_members/mod.rs000064400000000000000000000013101046102023000315630ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("new") .args(["bar"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } ././@LongLink00006440000000000000000000000152000000000000007771Lustar cargo-0.86.0/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_members/stderr.term.svgcargo-0.86.0/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_members/stderr.ter000064400000000000000000000017531046102023000324700ustar 00000000000000 Creating binary (application) `bar` package note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html cargo-0.86.0/tests/testsuite/cargo_owner/help/mod.rs000064400000000000000000000004771046102023000205770ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("owner") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_owner/help/stdout.term.svg000064400000000000000000000123041046102023000224530ustar 00000000000000 Manage the owners of a crate on the registry Usage: cargo[EXE] owner [OPTIONS] [CRATE] Arguments: [CRATE] Options: -a, --add <LOGIN> Name of a user or team to invite as an owner -r, --remove <LOGIN> Name of a user or team to remove as an owner -l, --list List owners of a crate --index <INDEX> Registry index URL to modify owners for --registry <REGISTRY> Registry to modify owners for --token <TOKEN> API token to use when authenticating -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help owner` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_owner/mod.rs000064400000000000000000000000121046102023000176300ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_package/help/mod.rs000064400000000000000000000005011046102023000210240ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("package") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_package/help/stdout.term.svg000064400000000000000000000176021046102023000227220ustar 00000000000000 Assemble the local package into a distributable tarball Usage: cargo[EXE] package [OPTIONS] Options: --index <INDEX> Registry index URL to prepare the package for (unstable) --registry <REGISTRY> Registry to prepare the package for (unstable) -l, --list Print files included in a package without making one --no-verify Don't verify the contents by building them --no-metadata Ignore warnings about a lack of human-usable metadata --allow-dirty Allow dirty working directories to be packaged -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -p, --package [<SPEC>] Package(s) to assemble --workspace Assemble all packages in the workspace --exclude <SPEC> Don't assemble specified packages Feature Selection: -F, --features <FEATURES> Space or comma separated list of features to activate --all-features Activate all available features --no-default-features Do not activate the `default` feature Compilation Options: --target [<TRIPLE>] Build for the target triple --target-dir <DIRECTORY> Directory for all generated artifacts -j, --jobs <N> Number of parallel jobs, defaults to # of CPUs. --keep-going Do not abort the build as soon as there is an error Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help package` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_package/mod.rs000064400000000000000000000000121046102023000200710ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_pkgid/help/mod.rs000064400000000000000000000004771046102023000205430ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("pkgid") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_pkgid/help/stdout.term.svg000064400000000000000000000111711046102023000224200ustar 00000000000000 Print a fully qualified package specification Usage: cargo[EXE] pkgid [OPTIONS] [SPEC] Arguments: [SPEC] Options: -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -p, --package [<SPEC>] Argument to get the package ID specifier for Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help pkgid` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_pkgid/mod.rs000064400000000000000000000000121046102023000175740ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_publish/help/mod.rs000064400000000000000000000005011046102023000210770ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("publish") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_publish/help/stdout.term.svg000064400000000000000000000175761046102023000230070ustar 00000000000000 Upload a package to the registry Usage: cargo[EXE] publish [OPTIONS] Options: -n, --dry-run Perform all checks without uploading --index <INDEX> Registry index URL to upload the package to --registry <REGISTRY> Registry to upload the package to --token <TOKEN> Token to use when uploading --no-verify Don't verify the contents by building them --allow-dirty Allow dirty working directories to be packaged -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -p, --package [<SPEC>] Package(s) to publish --workspace Publish all packages in the workspace (unstable) --exclude <SPEC> Don't publish specified packages (unstable) Feature Selection: -F, --features <FEATURES> Space or comma separated list of features to activate --all-features Activate all available features --no-default-features Do not activate the `default` feature Compilation Options: -j, --jobs <N> Number of parallel jobs, defaults to # of CPUs. --keep-going Do not abort the build as soon as there is an error --target [<TRIPLE>] Build for the target triple --target-dir <DIRECTORY> Directory for all generated artifacts Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help publish` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_publish/mod.rs000064400000000000000000000000121046102023000201440ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_read_manifest/help/mod.rs000064400000000000000000000005071046102023000222400ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("read-manifest") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_read_manifest/help/stdout.term.svg000064400000000000000000000072561046102023000241340ustar 00000000000000 DEPRECATED: Print a JSON representation of a Cargo.toml manifest. Use `cargo metadata --no-deps` instead. Usage: cargo[EXE] read-manifest [OPTIONS] Options: -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --manifest-path <PATH> Path to Cargo.toml --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline cargo-0.86.0/tests/testsuite/cargo_read_manifest/mod.rs000064400000000000000000000000121046102023000212770ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_remove/avoid_empty_tables/mod.rs000064400000000000000000000026351046102023000236620ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["clippy"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/avoid_empty_tables/stderr.term.svg000064400000000000000000000013331046102023000255210ustar 00000000000000 Removing clippy from dependencies cargo-0.86.0/tests/testsuite/cargo_remove/build/mod.rs000064400000000000000000000026501046102023000211040ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["--build", "semver"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/build/stderr.term.svg000064400000000000000000000013411046102023000227450ustar 00000000000000 Removing semver from build-dependencies cargo-0.86.0/tests/testsuite/cargo_remove/dev/mod.rs000064400000000000000000000026451046102023000205670ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["--dev", "regex"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/dev/stderr.term.svg000064400000000000000000000013361046102023000224300ustar 00000000000000 Removing regex from dev-dependencies cargo-0.86.0/tests/testsuite/cargo_remove/dry_run/mod.rs000064400000000000000000000026521046102023000214710ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["semver", "--dry-run"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/dry_run/stderr.term.svg000064400000000000000000000016331046102023000233340ustar 00000000000000 Removing semver from dependencies warning: aborting remove due to dry run cargo-0.86.0/tests/testsuite/cargo_remove/gc_keep_used_patch/mod.rs000064400000000000000000000017051046102023000236010ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("serde", "1.0.0").publish(); cargo_test_support::registry::Package::new("serde_json", "1.0.0") .dep("serde", "1.0.0") .publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); snapbox::cmd::Command::cargo_ui() .current_dir(&project_root) .arg("remove") .args(["--package", "serde", "serde_derive"]) .assert() .code(0) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/gc_keep_used_patch/stderr.term.svg000064400000000000000000000013411046102023000254420ustar 00000000000000 Removing serde_derive from dependencies cargo-0.86.0/tests/testsuite/cargo_remove/gc_patch/mod.rs000064400000000000000000000044521046102023000215570ustar 00000000000000use cargo_test_support::basic_manifest; use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::git; use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; #[cargo_test] fn case() { cargo_test_support::registry::init(); let git_project1 = git::new("bar1", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "") }) .url(); let git_project2 = git::new("bar2", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "") }) .url(); let git_project3 = git::new("bar3", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "") }) .url(); let in_project = project() .file( "Cargo.toml", &format!( "[workspace]\n\ members = [ \"my-member\" ]\n\ \n\ [package]\n\ name = \"my-project\"\n\ version = \"0.1.0\"\n\ edition = \"2015\"\n\ \n\ [dependencies]\n\ bar = {{ git = \"{git_project1}\" }}\n\ \n\ [patch.\"{git_project1}\"]\n\ bar = {{ git = \"{git_project3}\" }}\n\ \n\ [patch.crates-io]\n\ bar = {{ git = \"{git_project2}\" }}\n", ), ) .file("src/lib.rs", "") .file( "my-member/Cargo.toml", "[package]\n\ name = \"my-member\"\n\ version = \"0.1.0\"\n\ \n\ [dependencies]\n\ bar = \"0.1.0\"\n", ) .file("my-member/src/lib.rs", "") .build(); snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["bar"]) .current_dir(&in_project.root()) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &in_project.root()); } cargo-0.86.0/tests/testsuite/cargo_remove/gc_patch/stderr.term.svg000064400000000000000000000013301046102023000234140ustar 00000000000000 Removing bar from dependencies cargo-0.86.0/tests/testsuite/cargo_remove/gc_profile/mod.rs000064400000000000000000000027611046102023000221210ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["toml"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/gc_profile/stderr.term.svg000064400000000000000000000013311046102023000237560ustar 00000000000000 Removing toml from dependencies cargo-0.86.0/tests/testsuite/cargo_remove/gc_replace/mod.rs000064400000000000000000000030141046102023000220640ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["--package", "my-package", "toml"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/gc_replace/stderr.term.svg000064400000000000000000000013311046102023000237310ustar 00000000000000 Removing toml from dependencies cargo-0.86.0/tests/testsuite/cargo_remove/help/mod.rs000064400000000000000000000005001046102023000207250ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("remove") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_remove/help/stdout.term.svg000064400000000000000000000130351046102023000226200ustar 00000000000000 Remove dependencies from a Cargo.toml manifest file Usage: cargo[EXE] remove [OPTIONS] <DEP_ID>... Arguments: <DEP_ID>... Dependencies to be removed Options: -n, --dry-run Don't actually write the manifest -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Section: --dev Remove from dev-dependencies --build Remove from build-dependencies --target <TARGET> Remove from target-dependencies Package Selection: -p, --package [<SPEC>] Package to remove from Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help remove` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_remove/invalid_arg/mod.rs000064400000000000000000000026421046102023000222650ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["foo", "--flag"]) .current_dir(cwd) .assert() .code(1) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/invalid_arg/stderr.term.svg000064400000000000000000000031211046102023000241230ustar 00000000000000 error: unexpected argument '--flag' found tip: to pass '--flag' as a value, use '-- --flag' Usage: cargo[EXE] remove <DEP_ID>... For more information, try '--help'. cargo-0.86.0/tests/testsuite/cargo_remove/invalid_dep/mod.rs000064400000000000000000000022721046102023000222630ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("invalid-dependency-name", "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("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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["invalid_dependency_name"]) .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/invalid_dep/stderr.term.svg000064400000000000000000000020011046102023000241160ustar 00000000000000 Removing invalid_dependency_name from dependencies error: the dependency `invalid_dependency_name` could not be found in `dependencies`; dependency `invalid-dependency-name` exists cargo-0.86.0/tests/testsuite/cargo_remove/invalid_package/mod.rs000064400000000000000000000031431046102023000231040ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["docopt", "--package", "dep-c"]) .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/invalid_package/stderr.term.svg000064400000000000000000000014141046102023000247500ustar 00000000000000 error: package(s) `dep-c` not found in workspace `[ROOT]/case` cargo-0.86.0/tests/testsuite/cargo_remove/invalid_package_multiple/mod.rs000064400000000000000000000031151046102023000250160ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["docopt"]) .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/invalid_package_multiple/stderr.term.svg000064400000000000000000000016301046102023000266630ustar 00000000000000 error: `cargo remove` could not determine which package to modify. Use the `--package` option to specify a package. available packages: dep-a, dep-b cargo-0.86.0/tests/testsuite/cargo_remove/invalid_section/mod.rs000064400000000000000000000026501046102023000231570ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["--build", "docopt"]) .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/invalid_section/stderr.term.svg000064400000000000000000000017361046102023000250300ustar 00000000000000 Removing docopt from build-dependencies error: the dependency `docopt` could not be found in `build-dependencies`; it is present in `dependencies` cargo-0.86.0/tests/testsuite/cargo_remove/invalid_section_dep/mod.rs000064400000000000000000000026571046102023000240160ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["--dev", "semver", "regex"]) .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/invalid_section_dep/stderr.term.svg000064400000000000000000000017321046102023000256540ustar 00000000000000 Removing semver from dev-dependencies error: the dependency `semver` could not be found in `dev-dependencies`; it is present in `dependencies` cargo-0.86.0/tests/testsuite/cargo_remove/invalid_target/mod.rs000064400000000000000000000031641046102023000230020ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["--target", "powerpc-unknown-linux-gnu", "dbus"]) .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/invalid_target/stderr.term.svg000064400000000000000000000020651046102023000246460ustar 00000000000000 Removing dbus from dependencies for target `powerpc-unknown-linux-gnu` error: the dependency `dbus` could not be found in `target.powerpc-unknown-linux-gnu.dependencies`; it is present in `target.wasm32-unknown-unknown.dependencies` cargo-0.86.0/tests/testsuite/cargo_remove/invalid_target_dep/mod.rs000064400000000000000000000031611046102023000236270ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["--target", "wasm32-unknown-unknown", "toml"]) .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/invalid_target_dep/stderr.term.svg000064400000000000000000000020211046102023000254660ustar 00000000000000 Removing toml from dependencies for target `wasm32-unknown-unknown` error: the dependency `toml` could not be found in `target.wasm32-unknown-unknown.dependencies`; it is present in `dependencies` cargo-0.86.0/tests/testsuite/cargo_remove/last_dep/mod.rs000064400000000000000000000015211046102023000215740ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["docopt"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/last_dep/stderr.term.svg000064400000000000000000000013331046102023000234420ustar 00000000000000 Removing docopt from dependencies cargo-0.86.0/tests/testsuite/cargo_remove/mod.rs000064400000000000000000000012661046102023000200070ustar 00000000000000mod avoid_empty_tables; mod build; mod dev; mod dry_run; mod gc_keep_used_patch; mod gc_patch; mod gc_profile; mod gc_replace; mod help; mod invalid_arg; mod invalid_dep; mod invalid_package; mod invalid_package_multiple; mod invalid_section; mod invalid_section_dep; mod invalid_target; mod invalid_target_dep; mod last_dep; mod multiple_deps; mod multiple_dev; mod no_arg; mod offline; mod optional_dep_feature; mod optional_dep_feature_formatting; mod optional_feature; mod package; mod remove_basic; mod script; mod script_last; mod skip_gc_glob_profile; mod target; mod target_build; mod target_dev; mod update_lock_file; mod workspace; mod workspace_non_virtual; mod workspace_preserved; cargo-0.86.0/tests/testsuite/cargo_remove/multiple_deps/mod.rs000064400000000000000000000026471046102023000226610ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["docopt", "semver"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/multiple_deps/stderr.term.svg000064400000000000000000000015331046102023000245170ustar 00000000000000 Removing docopt from dependencies Removing semver from dependencies cargo-0.86.0/tests/testsuite/cargo_remove/multiple_dev/mod.rs000064400000000000000000000026561046102023000225040ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["--dev", "regex", "serde"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/multiple_dev/stderr.term.svg000064400000000000000000000015411046102023000243410ustar 00000000000000 Removing regex from dev-dependencies Removing serde from dev-dependencies cargo-0.86.0/tests/testsuite/cargo_remove/no_arg/mod.rs000064400000000000000000000026011046102023000212460ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .current_dir(cwd) .assert() .code(1) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/no_arg/stderr.term.svg000064400000000000000000000025151046102023000231170ustar 00000000000000 error: the following required arguments were not provided: <DEP_ID>... Usage: cargo[EXE] remove <DEP_ID>... For more information, try '--help'. cargo-0.86.0/tests/testsuite/cargo_remove/offline/mod.rs000064400000000000000000000031401046102023000214220ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; // run the metadata command to populate the cache snapbox::cmd::Command::cargo_ui() .arg("metadata") .current_dir(cwd) .assert() .success(); snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["docopt", "--offline"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/offline/stderr.term.svg000064400000000000000000000013331046102023000232710ustar 00000000000000 Removing docopt from dependencies cargo-0.86.0/tests/testsuite/cargo_remove/optional_dep_feature/mod.rs000064400000000000000000000026451046102023000242010ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["--dev", "serde"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/optional_dep_feature/stderr.term.svg000064400000000000000000000013361046102023000260420ustar 00000000000000 Removing serde from dev-dependencies cargo-0.86.0/tests/testsuite/cargo_remove/optional_dep_feature_formatting/mod.rs000064400000000000000000000026451046102023000264330ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["docopt", "toml"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/optional_dep_feature_formatting/stderr.term.svg000064400000000000000000000015311046102023000302710ustar 00000000000000 Removing docopt from dependencies Removing toml from dependencies cargo-0.86.0/tests/testsuite/cargo_remove/optional_feature/mod.rs000064400000000000000000000026351046102023000233500ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["semver"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/optional_feature/stderr.term.svg000064400000000000000000000013331046102023000252070ustar 00000000000000 Removing semver from dependencies cargo-0.86.0/tests/testsuite/cargo_remove/package/mod.rs000064400000000000000000000031431046102023000213760ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["docopt", "--package", "dep-a"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/package/stderr.term.svg000064400000000000000000000013331046102023000232420ustar 00000000000000 Removing docopt from dependencies cargo-0.86.0/tests/testsuite/cargo_remove/remove_basic/mod.rs000064400000000000000000000026351046102023000224460ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["docopt"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/remove_basic/stderr.term.svg000064400000000000000000000013331046102023000243050ustar 00000000000000 Removing docopt from dependencies cargo-0.86.0/tests/testsuite/cargo_remove/script/in/cargo-remove-test-fixture.rs000064400000000000000000000004241046102023000261640ustar 00000000000000--- edition = "2015" [build-dependencies] semver = "0.1.0" [dependencies] docopt = "0.6" rustc-serialize = "0.4" semver = "0.1" toml = "0.1" clippy = "0.4" [dev-dependencies] regex = "0.1.1" serde = "1.0.90" [features] std = ["serde/std", "semver/std"] --- fn main() { } cargo-0.86.0/tests/testsuite/cargo_remove/script/mod.rs000064400000000000000000000030271046102023000213100ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .masquerade_as_nightly_cargo(&["script"]) .arg("-Zscript") .arg("remove") .arg_line("--manifest-path cargo-remove-test-fixture.rs docopt") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/script/out/cargo-remove-test-fixture.rs000064400000000000000000000004051046102023000263640ustar 00000000000000--- edition = "2015" [build-dependencies] semver = "0.1.0" [dependencies] rustc-serialize = "0.4" semver = "0.1" toml = "0.1" clippy = "0.4" [dev-dependencies] regex = "0.1.1" serde = "1.0.90" [features] std = ["serde/std", "semver/std"] --- fn main() { } cargo-0.86.0/tests/testsuite/cargo_remove/script/stderr.term.svg000064400000000000000000000021521046102023000231530ustar 00000000000000 warning: `package.edition` is unspecified, defaulting to `[..]` Removing docopt from dependencies warning: `package.edition` is unspecified, defaulting to `[..]` cargo-0.86.0/tests/testsuite/cargo_remove/script_last/in/cargo-remove-test-fixture.rs000064400000000000000000000000651046102023000272100ustar 00000000000000--- [dependencies] docopt = "0.6" --- fn main() { } cargo-0.86.0/tests/testsuite/cargo_remove/script_last/mod.rs000064400000000000000000000017131046102023000223330ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .masquerade_as_nightly_cargo(&["script"]) .arg("-Zscript") .arg("remove") .arg_line("--manifest-path cargo-remove-test-fixture.rs docopt") .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/script_last/out/cargo-remove-test-fixture.rs000064400000000000000000000000301046102023000274010ustar 00000000000000--- --- fn main() { } cargo-0.86.0/tests/testsuite/cargo_remove/script_last/stderr.term.svg000064400000000000000000000021521046102023000241760ustar 00000000000000 warning: `package.edition` is unspecified, defaulting to `[..]` Removing docopt from dependencies warning: `package.edition` is unspecified, defaulting to `[..]` cargo-0.86.0/tests/testsuite/cargo_remove/skip_gc_glob_profile/mod.rs000064400000000000000000000015151046102023000241460ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish(); let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["toml"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/skip_gc_glob_profile/stderr.term.svg000064400000000000000000000013311046102023000260070ustar 00000000000000 Removing toml from dependencies cargo-0.86.0/tests/testsuite/cargo_remove/target/mod.rs000064400000000000000000000031611046102023000212710ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["--target", "wasm32-unknown-unknown", "dbus"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/target/stderr.term.svg000064400000000000000000000013751046102023000231430ustar 00000000000000 Removing dbus from dependencies for target `wasm32-unknown-unknown` cargo-0.86.0/tests/testsuite/cargo_remove/target_build/mod.rs000064400000000000000000000031761046102023000224560ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["--build", "--target", "wasm32-unknown-unknown", "semver"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/target_build/stderr.term.svg000064400000000000000000000014051046102023000243140ustar 00000000000000 Removing semver from build-dependencies for target `wasm32-unknown-unknown` cargo-0.86.0/tests/testsuite/cargo_remove/target_dev/mod.rs000064400000000000000000000031751046102023000221340ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["--dev", "--target", "wasm32-unknown-unknown", "ncurses"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/target_dev/stderr.term.svg000064400000000000000000000014041046102023000237720ustar 00000000000000 Removing ncurses from dev-dependencies for target `wasm32-unknown-unknown` cargo-0.86.0/tests/testsuite/cargo_remove/update_lock_file/mod.rs000064400000000000000000000026461046102023000233030ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["rustc-serialize"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/update_lock_file/stderr.term.svg000064400000000000000000000013441046102023000251420ustar 00000000000000 Removing rustc-serialize from dependencies cargo-0.86.0/tests/testsuite/cargo_remove/workspace/mod.rs000064400000000000000000000027031046102023000220020ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["--package", "my-package", "--build", "semver"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/workspace/stderr.term.svg000064400000000000000000000013411046102023000236440ustar 00000000000000 Removing semver from build-dependencies cargo-0.86.0/tests/testsuite/cargo_remove/workspace_non_virtual/mod.rs000064400000000000000000000027031046102023000244220ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["--package", "my-package", "--build", "semver"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/workspace_non_virtual/stderr.term.svg000064400000000000000000000013411046102023000262640ustar 00000000000000 Removing semver from build-dependencies cargo-0.86.0/tests/testsuite/cargo_remove/workspace_preserved/mod.rs000064400000000000000000000027031046102023000240610ustar 00000000000000use cargo_test_support::compare::assert_ui; use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { 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(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("remove") .args(["--package", "my-package", "--build", "semver"]) .current_dir(cwd) .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); assert_ui().subset_matches(current_dir!().join("out"), &project_root); } cargo-0.86.0/tests/testsuite/cargo_remove/workspace_preserved/stderr.term.svg000064400000000000000000000013411046102023000257230ustar 00000000000000 Removing semver from build-dependencies cargo-0.86.0/tests/testsuite/cargo_report/help/mod.rs000064400000000000000000000005001046102023000207430ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("report") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_report/help/stdout.term.svg000064400000000000000000000074261046102023000226450ustar 00000000000000 Generate and display various kinds of reports Usage: cargo[EXE] report [OPTIONS] <COMMAND> Commands: future-incompatibilities Reports any crates which will eventually stop compiling Options: -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help report` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_report/mod.rs000064400000000000000000000000121046102023000200110ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_run/help/mod.rs000064400000000000000000000004751046102023000202470ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("run") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_run/help/stdout.term.svg000064400000000000000000000207711046102023000221340ustar 00000000000000 Run a binary or example of the local package Usage: cargo[EXE] run [OPTIONS] [ARGS]... Arguments: [ARGS]... Arguments for the binary or example to run Options: --message-format <FMT> Error format -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -p, --package [<SPEC>] Package with the target to run Target Selection: --bin [<NAME>] Name of the bin target to run --example [<NAME>] Name of the example target to run Feature Selection: -F, --features <FEATURES> Space or comma separated list of features to activate --all-features Activate all available features --no-default-features Do not activate the `default` feature Compilation Options: -j, --jobs <N> Number of parallel jobs, defaults to # of CPUs. --keep-going Do not abort the build as soon as there is an error -r, --release Build artifacts in release mode, with optimizations --profile <PROFILE-NAME> Build artifacts with the specified profile --target [<TRIPLE>] Build for the target triple --target-dir <DIRECTORY> Directory for all generated artifacts --unit-graph Output build graph in JSON (unstable) --timings[=<FMTS>] Timing output formats (unstable) (comma separated): html, json Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --ignore-rust-version Ignore `rust-version` specification in packages --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help run` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_run/mod.rs000064400000000000000000000000121046102023000173020ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_rustc/help/mod.rs000064400000000000000000000004771046102023000206050ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("rustc") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_rustc/help/stdout.term.svg000064400000000000000000000252551046102023000224720ustar 00000000000000 Compile a package, and pass extra options to the compiler Usage: cargo[EXE] rustc [OPTIONS] [ARGS]... Arguments: [ARGS]... Extra rustc flags Options: --print <INFO> Output compiler information without compiling --crate-type <CRATE-TYPE> Comma separated list of types of crates for the compiler to emit --future-incompat-report Outputs a future incompatibility report at the end of the build --message-format <FMT> Error format -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -p, --package [<SPEC>] Package to build Target Selection: --lib Build only this package's library --bins Build all binaries --bin [<NAME>] Build only the specified binary --examples Build all examples --example [<NAME>] Build only the specified example --tests Build all targets that have `test = true` set --test [<NAME>] Build only the specified test target --benches Build all targets that have `bench = true` set --bench [<NAME>] Build only the specified bench target --all-targets Build all targets Feature Selection: -F, --features <FEATURES> Space or comma separated list of features to activate --all-features Activate all available features --no-default-features Do not activate the `default` feature Compilation Options: -j, --jobs <N> Number of parallel jobs, defaults to # of CPUs. --keep-going Do not abort the build as soon as there is an error -r, --release Build artifacts in release mode, with optimizations --profile <PROFILE-NAME> Build artifacts with the specified profile --target [<TRIPLE>] Target triple which compiles will be for --target-dir <DIRECTORY> Directory for all generated artifacts --unit-graph Output build graph in JSON (unstable) --timings[=<FMTS>] Timing output formats (unstable) (comma separated): html, json Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --ignore-rust-version Ignore `rust-version` specification in packages --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help rustc` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_rustc/mod.rs000064400000000000000000000000121046102023000176360ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_rustdoc/help/mod.rs000064400000000000000000000005011046102023000211140ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("rustdoc") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_rustdoc/help/stdout.term.svg000064400000000000000000000246421046102023000230140ustar 00000000000000 Build a package's documentation, using specified custom flags. Usage: cargo[EXE] rustdoc [OPTIONS] [ARGS]... Arguments: [ARGS]... Extra rustdoc flags Options: --open Opens the docs in a browser after the operation --message-format <FMT> Error format --output-format <FMT> The output type to write (unstable) [possible values: html, json] -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -p, --package [<SPEC>] Package to document Target Selection: --lib Build only this package's library --bins Build all binaries --bin [<NAME>] Build only the specified binary --examples Build all examples --example [<NAME>] Build only the specified example --tests Build all targets that have `test = true` set --test [<NAME>] Build only the specified test target --benches Build all targets that have `bench = true` set --bench [<NAME>] Build only the specified bench target --all-targets Build all targets Feature Selection: -F, --features <FEATURES> Space or comma separated list of features to activate --all-features Activate all available features --no-default-features Do not activate the `default` feature Compilation Options: -j, --jobs <N> Number of parallel jobs, defaults to # of CPUs. --keep-going Do not abort the build as soon as there is an error -r, --release Build artifacts in release mode, with optimizations --profile <PROFILE-NAME> Build artifacts with the specified profile --target [<TRIPLE>] Build for the target triple --target-dir <DIRECTORY> Directory for all generated artifacts --unit-graph Output build graph in JSON (unstable) --timings[=<FMTS>] Timing output formats (unstable) (comma separated): html, json Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --ignore-rust-version Ignore `rust-version` specification in packages --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help rustdoc` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_rustdoc/mod.rs000064400000000000000000000000121046102023000201610ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_search/help/mod.rs000064400000000000000000000005001046102023000206750ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("search") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_search/help/stdout.term.svg000064400000000000000000000106771046102023000226010ustar 00000000000000 Search packages in the registry. Default registry is crates.io Usage: cargo[EXE] search [OPTIONS] [QUERY]... Arguments: [QUERY]... Options: --limit <LIMIT> Limit the number of results (default: 10, max: 100) --index <INDEX> Registry index URL to search packages in --registry <REGISTRY> Registry to search packages in -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help search` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_search/mod.rs000064400000000000000000000000121046102023000177430ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_targets.rs000064400000000000000000000034411046102023000174010ustar 00000000000000//! Tests specifically related to target handling (lib, bins, examples, tests, benches). use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; #[cargo_test] fn warn_unmatched_target_filters() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] test = false bench = false "#, ) .file("src/lib.rs", r#"fn main() {}"#) .build(); p.cargo("check --tests --bins --examples --benches") .with_stderr_data(str![[r#" [WARNING] target filters `bins`, `tests`, `examples`, `benches` specified, but no targets matched; this is a no-op [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn reserved_windows_target_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [[bin]] name = "con" path = "src/main.rs" "#, ) .file("src/main.rs", "fn main() {}") .build(); if cfg!(windows) { p.cargo("check") .with_stderr_data(str![[r#" [WARNING] binary target `con` is a reserved Windows filename, this target will not work on Windows platforms [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } else { p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } } cargo-0.86.0/tests/testsuite/cargo_test/help/mod.rs000064400000000000000000000004761046102023000204230ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("test") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_test/help/stdout.term.svg000064400000000000000000000271321046102023000223050ustar 00000000000000 Execute all unit and integration tests and build examples of a local package Usage: cargo[EXE] test [OPTIONS] [TESTNAME] [-- [ARGS]...] Arguments: [TESTNAME] If specified, only run tests containing this string in their names [ARGS]... Arguments for the test binary Options: --no-run Compile, but don't run tests --no-fail-fast Run all tests regardless of failure --future-incompat-report Outputs a future incompatibility report at the end of the build --message-format <FMT> Error format -q, --quiet Display one character per test instead of one line -v, --verbose... Use verbose output (-vv very verbose/build.rs output) --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -p, --package [<SPEC>] Package to run tests for --workspace Test all packages in the workspace --exclude <SPEC> Exclude packages from the test --all Alias for --workspace (deprecated) Target Selection: --lib Test only this package's library --bins Test all binaries --bin [<NAME>] Test only the specified binary --examples Test all examples --example [<NAME>] Test only the specified example --tests Test all targets that have `test = true` set --test [<NAME>] Test only the specified test target --benches Test all targets that have `bench = true` set --bench [<NAME>] Test only the specified bench target --all-targets Test all targets (does not include doctests) --doc Test only this library's documentation Feature Selection: -F, --features <FEATURES> Space or comma separated list of features to activate --all-features Activate all available features --no-default-features Do not activate the `default` feature Compilation Options: -j, --jobs <N> Number of parallel jobs, defaults to # of CPUs. -r, --release Build artifacts in release mode, with optimizations --profile <PROFILE-NAME> Build artifacts with the specified profile --target [<TRIPLE>] Build for the target triple --target-dir <DIRECTORY> Directory for all generated artifacts --unit-graph Output build graph in JSON (unstable) --timings[=<FMTS>] Timing output formats (unstable) (comma separated): html, json Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --ignore-rust-version Ignore `rust-version` specification in packages --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help test` for more detailed information. Run `cargo test -- --help` for test binary options. cargo-0.86.0/tests/testsuite/cargo_test/mod.rs000064400000000000000000000000351046102023000174620ustar 00000000000000mod help; mod no_keep_going; cargo-0.86.0/tests/testsuite/cargo_test/no_keep_going/mod.rs000064400000000000000000000011251046102023000222660ustar 00000000000000use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::CargoCommandExt; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("test") .arg("--keep-going") .current_dir(cwd) .assert() .code(1) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_test/no_keep_going/stderr.term.svg000064400000000000000000000033211046102023000241330ustar 00000000000000 error: unexpected argument '--keep-going' found tip: use `--no-fail-fast` to run as many tests as possible regardless of failure Usage: cargo[EXE] test [OPTIONS] [TESTNAME] [-- [ARGS]...] For more information, try '--help'. cargo-0.86.0/tests/testsuite/cargo_tree/help/mod.rs000064400000000000000000000004761046102023000204030ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("tree") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_tree/help/stdout.term.svg000064400000000000000000000214131046102023000222610ustar 00000000000000 Display a tree visualization of a dependency graph Usage: cargo[EXE] tree [OPTIONS] Options: -e, --edges <KINDS> The kinds of dependencies to display (features, normal, build, dev, all, no-normal, no-build, no-dev, no-proc-macro) -i, --invert [<SPEC>] Invert the tree direction and focus on the given package --prune <SPEC> Prune the given package from the display of the dependency tree --depth <DEPTH> Maximum display depth of the dependency tree --prefix <PREFIX> Change the prefix (indentation) of how each entry is displayed [default: indent] [possible values: depth, indent, none] --no-dedupe Do not de-duplicate (repeats all shared dependencies) -d, --duplicates Show only dependencies which come in multiple versions (implies -i) --charset <CHARSET> Character set to use in output [possible values: utf8, ascii] -f, --format <FORMAT> Format string used for printing dependencies [default: {p}] -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -p, --package [<SPEC>] Package to be used as the root of the tree --workspace Display the tree for all packages in the workspace --exclude <SPEC> Exclude specific workspace members Feature Selection: -F, --features <FEATURES> Space or comma separated list of features to activate --all-features Activate all available features --no-default-features Do not activate the `default` feature Compilation Options: --target [<TRIPLE>] Filter dependencies matching the given target-triple (default host platform). Pass `all` to include all targets. Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help tree` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_tree/mod.rs000064400000000000000000000000121046102023000174350ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_uninstall/help/mod.rs000064400000000000000000000005031046102023000214440ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("uninstall") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_uninstall/help/stdout.term.svg000064400000000000000000000113011046102023000233260ustar 00000000000000 Remove a Rust binary Usage: cargo[EXE] uninstall [OPTIONS] [SPEC]... Arguments: [SPEC]... Options: --root <DIR> Directory to uninstall packages from -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -p, --package [<SPEC>] Package to uninstall Target Selection: --bin <NAME> Only uninstall the binary NAME Manifest Options: --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help uninstall` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_uninstall/mod.rs000064400000000000000000000000121046102023000205070ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_update/help/mod.rs000064400000000000000000000005001046102023000207120ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("update") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_update/help/stdout.term.svg000064400000000000000000000127461046102023000226150ustar 00000000000000 Update dependencies as recorded in the local lock file Usage: cargo[EXE] update [OPTIONS] [SPEC]... Options: -n, --dry-run Don't actually write the lockfile --recursive Force updating all dependencies of [SPEC]... as well --precise <PRECISE> Update [SPEC] to exactly PRECISE -b, --breaking Update [SPEC] to latest SemVer-breaking version (unstable) -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Package Selection: -w, --workspace Only update the workspace packages [SPEC]... Package to update Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --ignore-rust-version Ignore `rust-version` specification in packages --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help update` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_update/mod.rs000064400000000000000000000000411046102023000177620ustar 00000000000000mod help; mod toolchain_pkgname; cargo-0.86.0/tests/testsuite/cargo_update/toolchain_pkgname/mod.rs000064400000000000000000000010531046102023000234500ustar 00000000000000use cargo_test_support::current_dir; use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::Project; #[cargo_test] fn case() { let project = Project::from_template(current_dir!().join("in")); let project_root = project.root(); let cwd = &project_root; snapbox::cmd::Command::cargo_ui() .arg("update") .arg("+stable") .current_dir(cwd) .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/cargo_update/toolchain_pkgname/stderr.term.svg000064400000000000000000000016051046102023000253200ustar 00000000000000 error: invalid character `+` in package name: `+stable` Use `cargo +stable update` if you meant to use the `stable` toolchain. cargo-0.86.0/tests/testsuite/cargo_vendor/help/mod.rs000064400000000000000000000005001046102023000207250ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("vendor") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_vendor/help/stdout.term.svg000064400000000000000000000120511046102023000226150ustar 00000000000000 Vendor all dependencies for a project locally Usage: cargo[EXE] vendor [OPTIONS] [path] Arguments: [path] Where to vendor crates (`vendor` by default) Options: --no-delete Don't delete older crates in the vendor directory -s, --sync <TOML> Additional `Cargo.toml` to sync and vendor --respect-source-config Respect `[source]` config in `.cargo/config` --versioned-dirs Always include version in subdir name -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --manifest-path <PATH> Path to Cargo.toml --lockfile-path <PATH> Path to Cargo.lock (unstable) --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help vendor` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_vendor/mod.rs000064400000000000000000000000121046102023000177730ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_verify_project/help/mod.rs000064400000000000000000000005101046102023000224630ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("verify-project") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_verify_project/help/stdout.term.svg000064400000000000000000000071531046102023000243610ustar 00000000000000 DEPRECATED: Check correctness of crate manifest. See https://github.com/rust-lang/cargo/issues/14679. Usage: cargo[EXE] verify-project [OPTIONS] Options: -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --manifest-path <PATH> Path to Cargo.toml --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline cargo-0.86.0/tests/testsuite/cargo_verify_project/mod.rs000064400000000000000000000000121046102023000215300ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_version/help/mod.rs000064400000000000000000000005011046102023000211160ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("version") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_version/help/stdout.term.svg000064400000000000000000000066121046102023000230130ustar 00000000000000 Show version information Usage: cargo[EXE] version [OPTIONS] Options: -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help version` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_version/mod.rs000064400000000000000000000000121046102023000201630ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cargo_yank/help/mod.rs000064400000000000000000000004761046102023000204060ustar 00000000000000use cargo_test_support::file; use cargo_test_support::prelude::*; use cargo_test_support::str; #[cargo_test] fn case() { snapbox::cmd::Command::cargo_ui() .arg("yank") .arg("--help") .assert() .success() .stdout_eq(file!["stdout.term.svg"]) .stderr_eq(str![""]); } cargo-0.86.0/tests/testsuite/cargo_yank/help/stdout.term.svg000064400000000000000000000114441046102023000222670ustar 00000000000000 Remove a pushed crate from the index Usage: cargo[EXE] yank [OPTIONS] [CRATE] Arguments: [CRATE] Options: --version <VERSION> The version to yank or un-yank --undo Undo a yank, putting a version back into the index --index <INDEX> Registry index URL to yank from --registry <REGISTRY> Registry to yank from --token <TOKEN> API token to use when authenticating -v, --verbose... Use verbose output (-vv very verbose/build.rs output) -q, --quiet Do not print cargo log messages --color <WHEN> Coloring: auto, always, never --config <KEY=VALUE|PATH> Override a configuration value -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details -h, --help Print help Manifest Options: --locked Assert that `Cargo.lock` will remain unchanged --offline Run without accessing the network --frozen Equivalent to specifying both --locked and --offline Run `cargo help yank` for more detailed information. cargo-0.86.0/tests/testsuite/cargo_yank/mod.rs000064400000000000000000000000121046102023000174400ustar 00000000000000mod help; cargo-0.86.0/tests/testsuite/cfg.rs000064400000000000000000000437141046102023000153230ustar 00000000000000//! Tests for `cfg()` expressions. use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::rustc_host; use cargo_test_support::{basic_manifest, project, str}; #[cargo_test] fn cfg_easy() { let p = project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [target.'cfg(unix)'.dependencies] b = { path = 'b' } [target."cfg(windows)".dependencies] b = { path = 'b' } "#, ) .file("src/lib.rs", "extern crate b;") .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/lib.rs", "") .build(); p.cargo("check -v").run(); } #[cargo_test] fn dont_include() { let other_family = if cfg!(unix) { "windows" } else { "unix" }; let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [target.'cfg({})'.dependencies] b = {{ path = 'b' }} "#, other_family ), ) .file("src/lib.rs", "") .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] a v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn works_through_the_registry() { Package::new("baz", "0.1.0").publish(); Package::new("bar", "0.1.0") .target_dep("baz", "0.1.0", "cfg(unix)") .target_dep("baz", "0.1.0", "cfg(windows)") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file( "src/lib.rs", "#[allow(unused_extern_crates)] extern crate bar;", ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] baz v0.1.0 (registry `dummy-registry`) [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [CHECKING] baz v0.1.0 [CHECKING] bar v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn ignore_version_from_other_platform() { let this_family = if cfg!(unix) { "unix" } else { "windows" }; let other_family = if cfg!(unix) { "windows" } else { "unix" }; Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.2.0").publish(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [target.'cfg({})'.dependencies] bar = "0.1.0" [target.'cfg({})'.dependencies] bar = "0.2.0" "#, this_family, other_family ), ) .file( "src/lib.rs", "#[allow(unused_extern_crates)] extern crate bar;", ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [ADDING] bar v0.1.0 (available: v0.2.0) [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [CHECKING] bar v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn bad_target_spec() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [target.'cfg(4)'.dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: failed to parse `4` as a cfg expression: unexpected character `4` in cfg, expected parens, a comma, an identifier, or a string "#]]) .run(); } #[cargo_test] fn bad_target_spec2() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [target.'cfg(bar =)'.dependencies] baz = "0.1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: failed to parse `bar =` as a cfg expression: expected a string, but cfg expression ended "#]]) .run(); } #[cargo_test] fn multiple_match_ok() { let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [target.'cfg(unix)'.dependencies] b = {{ path = 'b' }} [target.'cfg(target_family = "unix")'.dependencies] b = {{ path = 'b' }} [target."cfg(windows)".dependencies] b = {{ path = 'b' }} [target.'cfg(target_family = "windows")'.dependencies] b = {{ path = 'b' }} [target."cfg(any(windows, unix))".dependencies] b = {{ path = 'b' }} [target.{}.dependencies] b = {{ path = 'b' }} "#, rustc_host() ), ) .file("src/lib.rs", "extern crate b;") .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/lib.rs", "") .build(); p.cargo("check -v").run(); } #[cargo_test] fn any_ok() { let p = project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [target."cfg(any(windows, unix))".dependencies] b = { path = 'b' } "#, ) .file("src/lib.rs", "extern crate b;") .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/lib.rs", "") .build(); p.cargo("check -v").run(); } // https://github.com/rust-lang/cargo/issues/5313 #[cargo_test] #[cfg(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu"))] fn cfg_looks_at_rustflags_for_target() { let p = project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [target.'cfg(with_b)'.dependencies] b = { path = 'b' } "#, ) .file( "src/main.rs", r#" #[cfg(with_b)] extern crate b; fn main() { b::foo(); } "#, ) .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/lib.rs", "pub fn foo() {}") .build(); p.cargo("check --target x86_64-unknown-linux-gnu") .env("RUSTFLAGS", "--cfg with_b") .run(); } #[cargo_test] fn bad_cfg_discovery() { // Check error messages when `rustc -v` and `rustc --print=*` parsing fails. // // This is a `rustc` replacement which behaves differently based on an // environment variable. let p = project() .at("compiler") .file("Cargo.toml", &basic_manifest("compiler", "0.1.0")) .file( "src/main.rs", r#" fn run_rustc() -> String { let mut cmd = std::process::Command::new("rustc"); for arg in std::env::args_os().skip(1) { cmd.arg(arg); } String::from_utf8(cmd.output().unwrap().stdout).unwrap() } fn main() { let mode = std::env::var("FUNKY_MODE").unwrap(); if mode == "bad-version" { println!("foo"); return; } if std::env::args_os().any(|a| a == "-vV") { print!("{}", run_rustc()); return; } if mode == "no-crate-types" { return; } if mode == "bad-crate-type" { println!("foo"); return; } let output = run_rustc(); let mut lines = output.lines(); let sysroot = loop { let line = lines.next().unwrap(); if line.contains("___") { println!("{}", line); } else { break line; } }; if mode == "no-sysroot" { return; } println!("{}", sysroot); if mode == "no-split-debuginfo" { return; } loop { let line = lines.next().unwrap(); if line == "___" { println!("\n{line}"); break; } else { // As the number split-debuginfo options varies, // concat them into one line. print!("{line},"); } }; if mode != "bad-cfg" { panic!("unexpected"); } println!("123"); } "#, ) .build(); p.cargo("build").run(); let funky_rustc = p.bin("compiler"); let p = project().file("src/lib.rs", "").build(); p.cargo("check") .env("RUSTC", &funky_rustc) .env("FUNKY_MODE", "bad-version") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `rustc -vV` didn't have a line for `host:`, got: foo "#]]) .run(); p.cargo("check") .env("RUSTC", &funky_rustc) .env("FUNKY_MODE", "no-crate-types") .with_status(101) .with_stderr_data(str![[r#" [ERROR] malformed output when learning about crate-type bin information command was: `[ROOT]/compiler/target/debug/compiler[..] --crate-name ___ [..]` (no output received) "#]]) .run(); p.cargo("check") .env("RUSTC", &funky_rustc) .env("FUNKY_MODE", "no-sysroot") .with_status(101) .with_stderr_data(str![[r#" [ERROR] output of --print=sysroot missing when learning about target-specific information from rustc command was: `[ROOT]/compiler/target/debug/compiler[..]--crate-type [..]` --- stdout ___[EXE] lib___.rlib [..]___.[..] [..]___.[..] [..]___.[..] [..]___.[..] "#]]) .run(); p.cargo("check") .env("RUSTC", &funky_rustc) .env("FUNKY_MODE", "no-split-debuginfo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] output of --print=split-debuginfo missing when learning about target-specific information from rustc command was: `[ROOT]/compiler/target/debug/compiler[..]--crate-type [..]` --- stdout ___[EXE] lib___.rlib [..]___.[..] [..]___.[..] [..]___.[..] [..]___.[..] [..] "#]]) .run(); p.cargo("check") .env("RUSTC", &funky_rustc) .env("FUNKY_MODE", "bad-cfg") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse the cfg from `rustc --print=cfg`, got: ___[EXE] lib___.rlib [..]___.[..] [..]___.[..] [..]___.[..] [..]___.[..] [..] [..],[..] ___ 123 Caused by: failed to parse `123` as a cfg expression: unexpected character `1` in cfg, expected parens, a comma, an identifier, or a string "#]]) .run(); } #[cargo_test] fn exclusive_dep_kinds() { // Checks for a bug where the same package with different cfg expressions // was not being filtered correctly. Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [target.'cfg(abc)'.dependencies] bar = "1.0" [target.'cfg(not(abc))'.build-dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .file("build.rs", "extern crate bar; fn main() {}") .build(); p.cargo("check").run(); p.change_file("src/lib.rs", "extern crate bar;"); p.cargo("check") .with_status(101) // can't find crate for `bar` .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) error[E0463]: can't find crate for `bar` ... "#]]) .run(); } #[cargo_test] fn cfg_raw_idents() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [target.'cfg(any(r#true, r#all, r#target_os = "<>"))'.dependencies] b = { path = "b/" } "#, ) .file("src/lib.rs", "") .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/lib.rs", "pub fn foo() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cfg_raw_idents_empty() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [target.'cfg(r#))'.dependencies] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: failed to parse `r#)` as a cfg expression: unexpected character `)` in cfg, expected parens, a comma, an identifier, or a string "#]]) .run(); } #[cargo_test] fn cfg_raw_idents_not_really() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [target.'cfg(r#11))'.dependencies] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: failed to parse `r#11)` as a cfg expression: unexpected character `1` in cfg, expected parens, a comma, an identifier, or a string "#]]) .run(); } #[cargo_test] fn cfg_keywords() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [target.'cfg(any(async, fn, const, return, true))'.dependencies] b = { path = "b/" } "#, ) .file( ".cargo/config.toml", r#" [target."cfg(any(for, match, extern, crate, false))"] "#, ) .file("src/lib.rs", "") .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/lib.rs", "pub fn foo() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] [[ROOT]/foo/Cargo.toml] future-incompatibility: the meaning of `cfg(true)` will change in the future | Cargo is erroneously allowing `cfg(true)` and `cfg(false)`, but both forms are interpreted as false unless manually overridden with `--cfg`. | In the future these will be built-in defines that will have the corresponding true/false value. | It is recommended to avoid using these configs until they are properly supported. | See for more information. | | [HELP] use raw-idents instead: `cfg(r#true)` [WARNING] [.cargo/config.toml] future-incompatibility: the meaning of `cfg(false)` will change in the future | Cargo is erroneously allowing `cfg(true)` and `cfg(false)`, but both forms are interpreted as false unless manually overridden with `--cfg`. | In the future these will be built-in defines that will have the corresponding true/false value. | It is recommended to avoid using these configs until they are properly supported. | See for more information. | | [HELP] use raw-idents instead: `cfg(r#false)` [LOCKING] 1 package to latest compatible version [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/check.rs000064400000000000000000001314601046102023000156350ustar 00000000000000//! Tests for the `cargo check` command. use std::fmt::{self, Write}; use cargo_test_support::compare::assert_e2e; use cargo_test_support::install::exe; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::tools; use cargo_test_support::{basic_bin_manifest, basic_manifest, git, project}; #[cargo_test] fn check_success() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" "#, ) .file( "src/main.rs", "extern crate bar; fn main() { ::bar::baz(); }", ) .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("check").run(); } #[cargo_test] fn check_fail() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" "#, ) .file( "src/main.rs", "extern crate bar; fn main() { ::bar::baz(42); }", ) .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("check") .with_status(101) .with_stderr_data(str![[r#" ... error[E0061]: this function takes 0 arguments but 1 argument was supplied ... "#]]) .run(); } #[cargo_test] fn custom_derive() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" "#, ) .file( "src/main.rs", r#" #[macro_use] extern crate bar; trait B { fn b(&self); } #[derive(B)] struct A; fn main() { let a = A; a.b(); } "#, ) .build(); let _bar = project() .at("bar") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [lib] proc-macro = true "#, ) .file( "src/lib.rs", r#" extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro_derive(B)] pub fn derive(_input: TokenStream) -> TokenStream { format!("impl B for A {{ fn b(&self) {{}} }}").parse().unwrap() } "#, ) .build(); foo.cargo("check").run(); } #[cargo_test] fn check_build() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" "#, ) .file( "src/main.rs", "extern crate bar; fn main() { ::bar::baz(); }", ) .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("check").run(); foo.cargo("build").run(); } #[cargo_test] fn build_check() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" "#, ) .file( "src/main.rs", "extern crate bar; fn main() { ::bar::baz(); }", ) .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("build -v").run(); foo.cargo("check -v").run(); } // Checks that where a project has both a lib and a bin, the lib is only checked // not built. #[cargo_test] fn issue_3418() { let foo = project() .file("src/lib.rs", "") .file("src/main.rs", "fn main() {}") .build(); foo.cargo("check -v") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] src/lib.rs [..]--emit=[..]metadata [..]` [RUNNING] `rustc --crate-name foo [..] src/main.rs [..]--emit=[..]metadata [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } // Check on a dylib should have a different metadata hash than build. #[cargo_test] fn dylib_check_preserves_build_cache() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [lib] crate-type = ["dylib"] [dependencies] "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check").run(); p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } // test `cargo rustc --profile check` #[cargo_test] fn rustc_check() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" "#, ) .file( "src/main.rs", "extern crate bar; fn main() { ::bar::baz(); }", ) .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("rustc --profile check -- --emit=metadata").run(); // Verify compatible usage of --profile with --release, issue #7488 foo.cargo("rustc --profile check --release -- --emit=metadata") .with_status(1) .with_stderr_data(str![[r#" [ERROR] the argument '--profile ' cannot be used with '--release' Usage: cargo[EXE] rustc --profile [ARGS]... For more information, try '--help'. "#]]) .run(); foo.cargo("rustc --profile test --release -- --emit=metadata") .with_status(1) .with_stderr_data(str![[r#" [ERROR] the argument '--profile ' cannot be used with '--release' Usage: cargo[EXE] rustc --profile [ARGS]... For more information, try '--help'. "#]]) .run(); } #[cargo_test] fn rustc_check_err() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" "#, ) .file( "src/main.rs", "extern crate bar; fn main() { ::bar::qux(); }", ) .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("rustc --profile check -- --emit=metadata") .with_status(101) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.0 ([ROOT]/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) error[E0425]: [..] ... "#]]) .run(); } #[cargo_test] fn check_all() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [workspace] [dependencies] b = { path = "b" } "#, ) .file("src/main.rs", "fn main() {}") .file("examples/a.rs", "fn main() {}") .file("tests/a.rs", "") .file("src/lib.rs", "") .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/main.rs", "fn main() {}") .file("b/src/lib.rs", "") .build(); p.cargo("check --workspace -v") .with_stderr_data( str![[r#" [CHECKING] b v0.0.1 ([ROOT]/foo/b) [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] src/lib.rs [..]` [RUNNING] `rustc --crate-name foo [..] src/main.rs [..]` [RUNNING] `rustc --crate-name b [..] b/src/lib.rs [..]` [RUNNING] `rustc --crate-name b [..] b/src/main.rs [..]` ... "#]] .unordered(), ) .run(); } #[cargo_test] fn check_all_exclude() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() { break_the_build(); }") .build(); p.cargo("check --workspace --exclude baz") .with_stderr_does_not_contain("[CHECKING] baz v0.1.0 [..]") .with_stderr_data(str![[r#" [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn check_all_exclude_glob() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() { break_the_build(); }") .build(); p.cargo("check --workspace --exclude '*z'") .with_stderr_does_not_contain("[CHECKING] baz v0.1.0 [..]") .with_stderr_data(str![[r#" [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn check_virtual_all_implied() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("check -v") .with_stderr_data( str![[r#" [CHECKING] baz v0.1.0 ([ROOT]/foo/baz) [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name baz [..] baz/src/lib.rs [..]` [RUNNING] `rustc --crate-name bar [..] bar/src/lib.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn check_virtual_manifest_one_project() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() { break_the_build(); }") .build(); p.cargo("check -p bar") .with_stderr_does_not_contain("[CHECKING] baz v0.1.0 [..]") .with_stderr_data(str![[r#" [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn check_virtual_manifest_glob() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() { break_the_build(); }") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("check -p '*z'") .with_stderr_does_not_contain("[CHECKING] bar v0.1.0 [..]") .with_stderr_data(str![[r#" [CHECKING] baz v0.1.0 ([ROOT]/foo/baz) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn exclude_warns_on_non_existing_package() { let p = project().file("src/lib.rs", "").build(); p.cargo("check --workspace --exclude bar") .with_stdout_data("") .with_stderr_data(str![[r#" [WARNING] excluded package(s) `bar` not found in workspace `[ROOT]/foo` [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn targets_selected_default() { let foo = project() .file("src/main.rs", "fn main() {}") .file("src/lib.rs", "pub fn smth() {}") .file("examples/example1.rs", "fn main() {}") .file("tests/test2.rs", "#[test] fn t() {}") .file("benches/bench3.rs", "") .build(); foo.cargo("check -v") .with_stderr_contains("[..] --crate-name foo [..] src/lib.rs [..]") .with_stderr_contains("[..] --crate-name foo [..] src/main.rs [..]") .with_stderr_does_not_contain("[..] --crate-name example1 [..] examples/example1.rs [..]") .with_stderr_does_not_contain("[..] --crate-name test2 [..] tests/test2.rs [..]") .with_stderr_does_not_contain("[..] --crate-name bench3 [..] benches/bench3.rs [..]") .run(); } #[cargo_test] fn targets_selected_all() { let foo = project() .file("src/main.rs", "fn main() {}") .file("src/lib.rs", "pub fn smth() {}") .file("examples/example1.rs", "fn main() {}") .file("tests/test2.rs", "#[test] fn t() {}") .file("benches/bench3.rs", "") .build(); foo.cargo("check --all-targets -v") .with_stderr_data( str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] src/lib.rs [..]` [RUNNING] `rustc --crate-name foo [..] src/main.rs [..]` [RUNNING] `rustc --crate-name example1 [..] examples/example1.rs [..]` [RUNNING] `rustc --crate-name test2 [..] tests/test2.rs [..]` [RUNNING] `rustc --crate-name bench3 [..] benches/bench3.rs [..]` ... "#]] .unordered(), ) .run(); } #[cargo_test] fn check_unit_test_profile() { let foo = project() .file( "src/lib.rs", r#" #[cfg(test)] mod tests { #[test] fn it_works() { badtext } } "#, ) .build(); foo.cargo("check").run(); foo.cargo("check --profile test") .with_status(101) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) error[E0425]: cannot find value `badtext` in this scope ... "#]]) .run(); } // Verify what is checked with various command-line filters. #[cargo_test] fn check_filters() { let p = project() .file( "src/lib.rs", r#" fn unused_normal_lib() {} #[cfg(test)] mod tests { fn unused_unit_lib() {} } "#, ) .file( "src/main.rs", r#" fn main() {} fn unused_normal_bin() {} #[cfg(test)] mod tests { fn unused_unit_bin() {} } "#, ) .file( "tests/t1.rs", r#" fn unused_normal_t1() {} #[cfg(test)] mod tests { fn unused_unit_t1() {} } "#, ) .file( "examples/ex1.rs", r#" fn main() {} fn unused_normal_ex1() {} #[cfg(test)] mod tests { fn unused_unit_ex1() {} } "#, ) .file( "benches/b1.rs", r#" fn unused_normal_b1() {} #[cfg(test)] mod tests { fn unused_unit_b1() {} } "#, ) .build(); p.cargo("check") .with_stderr_contains("[..]unused_normal_lib[..]") .with_stderr_contains("[..]unused_normal_bin[..]") .with_stderr_does_not_contain("[..]unused_normal_t1[..]") .with_stderr_does_not_contain("[..]unused_normal_ex1[..]") .with_stderr_does_not_contain("[..]unused_normal_b1[..]") .with_stderr_does_not_contain("[..]unused_unit_[..]") .run(); p.root().join("target").rm_rf(); p.cargo("check --tests -v") .with_stderr_contains("[..] --crate-name foo [..] src/lib.rs [..] --test [..]") .with_stderr_contains("[..] --crate-name foo [..] src/lib.rs [..] --crate-type lib [..]") .with_stderr_contains("[..] --crate-name foo [..] src/main.rs [..] --test [..]") .with_stderr_contains("[..]unused_unit_lib[..]") .with_stderr_contains("[..]unused_unit_bin[..]") .with_stderr_contains("[..]unused_normal_lib[..]") .with_stderr_contains("[..]unused_normal_bin[..]") .with_stderr_contains("[..]unused_unit_t1[..]") .with_stderr_does_not_contain("[..]unused_normal_ex1[..]") .with_stderr_does_not_contain("[..]unused_unit_ex1[..]") .with_stderr_does_not_contain("[..]unused_normal_b1[..]") .with_stderr_does_not_contain("[..]unused_unit_b1[..]") .with_stderr_does_not_contain("[..]--crate-type bin[..]") .run(); p.root().join("target").rm_rf(); p.cargo("check --test t1 -v") .with_stderr_contains("[..]unused_normal_lib[..]") .with_stderr_contains("[..]unused_unit_t1[..]") .with_stderr_does_not_contain("[..]unused_unit_lib[..]") .with_stderr_does_not_contain("[..]unused_normal_bin[..]") .with_stderr_does_not_contain("[..]unused_unit_bin[..]") .with_stderr_does_not_contain("[..]unused_normal_ex1[..]") .with_stderr_does_not_contain("[..]unused_normal_b1[..]") .with_stderr_does_not_contain("[..]unused_unit_ex1[..]") .with_stderr_does_not_contain("[..]unused_unit_b1[..]") .run(); p.root().join("target").rm_rf(); p.cargo("check --all-targets -v") .with_stderr_contains("[..]unused_normal_lib[..]") .with_stderr_contains("[..]unused_normal_bin[..]") .with_stderr_contains("[..]unused_normal_t1[..]") .with_stderr_contains("[..]unused_normal_ex1[..]") .with_stderr_contains("[..]unused_normal_b1[..]") .with_stderr_contains("[..]unused_unit_b1[..]") .with_stderr_contains("[..]unused_unit_t1[..]") .with_stderr_contains("[..]unused_unit_lib[..]") .with_stderr_contains("[..]unused_unit_bin[..]") .with_stderr_does_not_contain("[..]unused_unit_ex1[..]") .run(); } #[cargo_test] fn check_artifacts() { // Verify which artifacts are created when running check (#4059). let p = project() .file("src/lib.rs", "") .file("src/main.rs", "fn main() {}") .file("tests/t1.rs", "") .file("examples/ex1.rs", "fn main() {}") .file("benches/b1.rs", "") .build(); p.cargo("check").run(); assert!(!p.root().join("target/debug/libfoo.rmeta").is_file()); assert!(!p.root().join("target/debug/libfoo.rlib").is_file()); assert!(!p.root().join("target/debug").join(exe("foo")).is_file()); assert_eq!(p.glob("target/debug/deps/libfoo-*.rmeta").count(), 2); p.root().join("target").rm_rf(); p.cargo("check --lib").run(); assert!(!p.root().join("target/debug/libfoo.rmeta").is_file()); assert!(!p.root().join("target/debug/libfoo.rlib").is_file()); assert!(!p.root().join("target/debug").join(exe("foo")).is_file()); assert_eq!(p.glob("target/debug/deps/libfoo-*.rmeta").count(), 1); p.root().join("target").rm_rf(); p.cargo("check --bin foo").run(); assert!(!p.root().join("target/debug/libfoo.rmeta").is_file()); assert!(!p.root().join("target/debug/libfoo.rlib").is_file()); assert!(!p.root().join("target/debug").join(exe("foo")).is_file()); assert_eq!(p.glob("target/debug/deps/libfoo-*.rmeta").count(), 2); p.root().join("target").rm_rf(); p.cargo("check --test t1").run(); assert!(!p.root().join("target/debug/libfoo.rmeta").is_file()); assert!(!p.root().join("target/debug/libfoo.rlib").is_file()); assert!(!p.root().join("target/debug").join(exe("foo")).is_file()); assert_eq!(p.glob("target/debug/t1-*").count(), 0); assert_eq!(p.glob("target/debug/deps/libfoo-*.rmeta").count(), 1); assert_eq!(p.glob("target/debug/deps/libt1-*.rmeta").count(), 1); p.root().join("target").rm_rf(); p.cargo("check --example ex1").run(); assert!(!p.root().join("target/debug/libfoo.rmeta").is_file()); assert!(!p.root().join("target/debug/libfoo.rlib").is_file()); assert!(!p .root() .join("target/debug/examples") .join(exe("ex1")) .is_file()); assert_eq!(p.glob("target/debug/deps/libfoo-*.rmeta").count(), 1); assert_eq!(p.glob("target/debug/examples/libex1-*.rmeta").count(), 1); p.root().join("target").rm_rf(); p.cargo("check --bench b1").run(); assert!(!p.root().join("target/debug/libfoo.rmeta").is_file()); assert!(!p.root().join("target/debug/libfoo.rlib").is_file()); assert!(!p.root().join("target/debug").join(exe("foo")).is_file()); assert_eq!(p.glob("target/debug/b1-*").count(), 0); assert_eq!(p.glob("target/debug/deps/libfoo-*.rmeta").count(), 1); assert_eq!(p.glob("target/debug/deps/libb1-*.rmeta").count(), 1); } #[cargo_test] fn short_message_format() { let foo = project() .file("src/lib.rs", "fn foo() { let _x: bool = 'a'; }") .build(); foo.cargo("check --message-format=short") .with_status(101) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) src/lib.rs:1:27: error[E0308]: mismatched types[..] [ERROR] could not compile `foo` (lib) due to 1 previous error "#]]) .run(); } #[cargo_test] fn proc_macro() { let p = project() .file( "Cargo.toml", r#" [package] name = "demo" version = "0.0.1" edition = "2015" [lib] proc-macro = true "#, ) .file( "src/lib.rs", r#" extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro_derive(Foo)] pub fn demo(_input: TokenStream) -> TokenStream { "".parse().unwrap() } "#, ) .file( "src/main.rs", r#" #[macro_use] extern crate demo; #[derive(Foo)] struct A; fn main() {} "#, ) .build(); p.cargo("check -v").env("CARGO_LOG", "cargo=trace").run(); } #[cargo_test] fn check_keep_going() { let foo = project() .file("src/bin/one.rs", "compile_error!(\"ONE\"); fn main() {}") .file("src/bin/two.rs", "compile_error!(\"TWO\"); fn main() {}") .build(); // Due to -j1, without --keep-going only one of the two bins would be built. foo.cargo("check -j1 --keep-going") .with_status(101) .with_stderr_data( str![[r#" [ERROR] ONE [ERROR] TWO ... "#]] .unordered(), ) .run(); } #[cargo_test] fn does_not_use_empty_rustc_wrapper() { // An empty RUSTC_WRAPPER environment variable won't be used. // The env var will also override the config, essentially unsetting it. let p = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [build] rustc-wrapper = "do-not-execute-me" "#, ) .build(); p.cargo("check").env("RUSTC_WRAPPER", "").run(); } #[cargo_test] fn does_not_use_empty_rustc_workspace_wrapper() { let p = project().file("src/lib.rs", "").build(); p.cargo("check").env("RUSTC_WORKSPACE_WRAPPER", "").run(); } #[cargo_test] fn error_from_deep_recursion() -> Result<(), fmt::Error> { let mut big_macro = String::new(); writeln!(big_macro, "macro_rules! m {{")?; for i in 0..130 { writeln!(big_macro, "({}) => {{ m!({}); }};", i, i + 1)?; } writeln!(big_macro, "}}")?; writeln!(big_macro, "m!(0);")?; let p = project().file("src/lib.rs", &big_macro).build(); p.cargo("check --message-format=json") .with_status(101) .with_stdout_data(str![[r#" {"reason":"compiler-message",[..]"message":"recursion limit reached while expanding `m!`",[..]rendered":"[..]recursion limit reached while expanding `m!`[..]"}} ... "#]]) .run(); Ok(()) } #[cargo_test] fn rustc_workspace_wrapper_affects_all_workspace_members() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("check") .env("RUSTC_WORKSPACE_WRAPPER", tools::echo_wrapper()) .with_stderr_data( str![[r#" WRAPPER CALLED: rustc --crate-name bar [..] WRAPPER CALLED: rustc --crate-name baz [..] ... "#]] .unordered(), ) .run(); } #[cargo_test] fn rustc_workspace_wrapper_includes_path_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["bar"] [dependencies] baz = { path = "baz" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("check --workspace") .env("RUSTC_WORKSPACE_WRAPPER", tools::echo_wrapper()) .with_stderr_data( str![[r#" WRAPPER CALLED: rustc --crate-name bar [..] WRAPPER CALLED: rustc --crate-name baz [..] WRAPPER CALLED: rustc --crate-name foo [..] ... "#]] .unordered(), ) .run(); } #[cargo_test] fn rustc_workspace_wrapper_respects_primary_units() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("check -p bar") .env("RUSTC_WORKSPACE_WRAPPER", tools::echo_wrapper()) .with_stderr_contains("WRAPPER CALLED: rustc --crate-name bar [..]") .with_stdout_does_not_contain("WRAPPER CALLED: rustc --crate-name baz [..]") .run(); } #[cargo_test] fn rustc_workspace_wrapper_excludes_published_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["bar"] [dependencies] baz = "1.0.0" "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); Package::new("baz", "1.0.0").publish(); p.cargo("check --workspace -v") .env("RUSTC_WORKSPACE_WRAPPER", tools::echo_wrapper()) .with_stderr_contains("WRAPPER CALLED: rustc --crate-name foo [..]") .with_stderr_contains("WRAPPER CALLED: rustc --crate-name bar [..]") .with_stderr_contains("[CHECKING] baz [..]") .with_stdout_does_not_contain("WRAPPER CALLED: rustc --crate-name baz [..]") .run(); } #[cargo_test] fn warn_manifest_with_project() { let p = project() .file( "Cargo.toml", r#" [project] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] `[project]` is deprecated in favor of `[package]` [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn error_manifest_with_project_on_2024() { let p = project() .file( "Cargo.toml", r#" [project] name = "foo" version = "0.0.1" edition = "2024" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `[project]` is not supported as of the 2024 Edition, please use `[package]` "#]]) .run(); } #[cargo_test] fn warn_manifest_package_and_project() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [project] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] `[project]` is deprecated in favor of `[package]` [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn git_manifest_package_and_project() { let p = project(); let git_project = git::new("bar", |p| { p.file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" [project] name = "bar" version = "0.0.1" edition = "2015" "#, ) .file("src/lib.rs", "") }); let p = p .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies.bar] version = "0.0.1" git = '{}' "#, git_project.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.0.1 ([ROOTURL]/bar#[..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn git_manifest_with_project() { let p = project(); let git_project = git::new("bar", |p| { p.file( "Cargo.toml", r#" [project] name = "bar" version = "0.0.1" edition = "2015" "#, ) .file("src/lib.rs", "") }); let p = p .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies.bar] version = "0.0.1" git = '{}' "#, git_project.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.0.1 ([ROOTURL]/bar#[..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn check_fixable_warning() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/lib.rs", "use std::io;") .build(); foo.cargo("check") .with_stderr_data(str![[r#" ... [WARNING] `foo` (lib) generated 1 warning (run `cargo fix --lib -p foo` to apply 1 suggestion) ... "#]]) .run(); } #[cargo_test] fn check_fixable_test_warning() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file( "src/lib.rs", "\ mod tests { #[test] fn t1() { use std::io; } } ", ) .build(); foo.cargo("check --all-targets") .with_stderr_data(str![[r#" ... [WARNING] `foo` (lib test) generated 1 warning (run `cargo fix --lib -p foo --tests` to apply 1 suggestion) ... "#]]) .run(); foo.cargo("fix --lib -p foo --tests --allow-no-vcs").run(); assert!(!foo.read_file("src/lib.rs").contains("use std::io;")); } #[cargo_test] fn check_fixable_error_no_fix() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file( "src/lib.rs", "use std::io;\n#[derive(Debug(x))]\nstruct Foo;", ) .build(); foo.cargo("check") .with_status(101) .with_stderr_data( str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [ERROR] traits in `#[derive(...)]` don't accept arguments [WARNING] unused import: `std::io` [WARNING] `foo` (lib) generated 1 warning [ERROR] could not compile `foo` (lib) due to 1 previous error; 1 warning emitted ... "#]] .unordered(), ) .run(); } #[cargo_test] fn check_fixable_warning_workspace() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo", "bar"] "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("foo/src/lib.rs", "use std::io;") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" [dependencies] foo = { path = "../foo" } "#, ) .file("bar/src/lib.rs", "use std::io;") .build(); p.cargo("check") .with_stderr_data( str![[r#" [WARNING] `foo` (lib) generated 1 warning (run `cargo fix --lib -p foo` to apply 1 suggestion) [WARNING] `bar` (lib) generated 1 warning (run `cargo fix --lib -p bar` to apply 1 suggestion) ... "#]] .unordered(), ) .run(); } #[cargo_test] fn check_fixable_example() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" fn hello() -> &'static str { "hello" } pub fn main() { println!("{}", hello()) } "#, ) .file("examples/ex1.rs", "use std::fmt; fn main() {}") .build(); p.cargo("check --all-targets") .with_stderr_data(str![[r#" ... [WARNING] `foo` (example "ex1") generated 1 warning (run `cargo fix --example "ex1"` to apply 1 suggestion) ... "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn check_fixable_bench() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; fn hello() -> &'static str { "hello" } pub fn main() { println!("{}", hello()) } #[bench] fn bench_hello(_b: &mut test::Bencher) { use std::io; assert_eq!(hello(), "hello") } "#, ) .file( "benches/bench.rs", " #![feature(test)] extern crate test; #[bench] fn bench(_b: &mut test::Bencher) { use std::fmt; } ", ) .build(); p.cargo("check --all-targets") .with_stderr_data(str![[r#" ... [WARNING] `foo` (bench "bench") generated 1 warning (run `cargo fix --bench "bench"` to apply 1 suggestion) ... "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn check_fixable_mixed() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" #![feature(test)] #[cfg(test)] extern crate test; fn hello() -> &'static str { "hello" } pub fn main() { println!("{}", hello()) } #[bench] fn bench_hello(_b: &mut test::Bencher) { use std::io; assert_eq!(hello(), "hello") } #[test] fn t1() { use std::fmt; } "#, ) .file("examples/ex1.rs", "use std::fmt; fn main() {}") .file( "benches/bench.rs", " #![feature(test)] extern crate test; #[bench] fn bench(_b: &mut test::Bencher) { use std::fmt; } ", ) .build(); p.cargo("check --all-targets") .with_stderr_data(str![[r#" [WARNING] `foo` (example "ex1") generated 1 warning (run `cargo fix --example "ex1"` to apply 1 suggestion) [WARNING] `foo` (bench "bench") generated 1 warning (run `cargo fix --bench "bench"` to apply 1 suggestion) [WARNING] `foo` (bin "foo" test) generated 2 warnings (run `cargo fix --bin "foo" --tests` to apply 2 suggestions) ... "#]].unordered()) .run(); } #[cargo_test] fn check_fixable_warning_for_clippy() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) // We don't want to show a warning that is `clippy` // specific since we are using a `rustc` wrapper // inplace of `clippy` .file("src/lib.rs", "use std::io;") .build(); foo.cargo("check") // We can't use `clippy` so we use a `rustc` workspace wrapper instead .env("RUSTC_WORKSPACE_WRAPPER", tools::wrapped_clippy_driver()) .with_stderr_data(str![[r#" ... [WARNING] `foo` (lib) generated 1 warning (run `cargo clippy --fix --lib -p foo` to apply 1 suggestion) ... "#]]) .run(); } #[cargo_test] fn check_unused_manifest_keys() { Package::new("dep", "0.1.0").publish(); Package::new("foo", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.2.0" edition = "2015" authors = [] [dependencies] dep = { version = "0.1.0", wxz = "wxz" } foo = { version = "0.1.0", abc = "abc" } [dev-dependencies] foo = { version = "0.1.0", wxz = "wxz" } [build-dependencies] foo = { version = "0.1.0", wxz = "wxz" } [target.'cfg(windows)'.dependencies] foo = { version = "0.1.0", wxz = "wxz" } [target.wasm32-wasip1.dev-dependencies] foo = { version = "0.1.0", wxz = "wxz" } [target.bar.build-dependencies] foo = { version = "0.1.0", wxz = "wxz" } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data( str![[r#" [WARNING] unused manifest key: dependencies.dep.wxz [WARNING] unused manifest key: dependencies.foo.abc [WARNING] unused manifest key: dev-dependencies.foo.wxz [WARNING] unused manifest key: build-dependencies.foo.wxz [WARNING] unused manifest key: target.bar.build-dependencies.foo.wxz [WARNING] unused manifest key: target.cfg(windows).dependencies.foo.wxz [WARNING] unused manifest key: target.wasm32-wasip1.dev-dependencies.foo.wxz [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] foo v0.1.0 (registry `dummy-registry`) [DOWNLOADED] dep v0.1.0 (registry `dummy-registry`) [CHECKING] foo v0.1.0 [CHECKING] dep v0.1.0 [CHECKING] bar v0.2.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn versionless_package() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" description = "foo" edition = "2015" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn pkgid_querystring_works() { let git_project = git::new("gitdep", |p| { p.file("Cargo.toml", &basic_manifest("gitdep", "1.0.0")) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" edition = "2015" [dependencies] gitdep = {{ git = "{}", branch = "master" }} "#, git_project.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); let output = p.cargo("pkgid").arg("gitdep").run(); let gitdep_pkgid = String::from_utf8(output.stdout).unwrap(); let gitdep_pkgid = gitdep_pkgid.trim(); assert_e2e().eq( gitdep_pkgid, str!["git+[ROOTURL]/gitdep?branch=master#1.0.0"], ); p.cargo("build -p") .arg(gitdep_pkgid) .with_stderr_data(str![[r#" [COMPILING] gitdep v1.0.0 ([ROOTURL]/gitdep?branch=master#[..]) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/check_cfg.rs000064400000000000000000000576031046102023000164620ustar 00000000000000//! Tests for Cargo usage of rustc `--check-cfg`. use cargo_test_support::prelude::*; use cargo_test_support::{basic_manifest, project, str}; macro_rules! x { ($tool:tt => $what:tt $(of $who:tt)?) => {{ #[cfg(windows)] { concat!("[RUNNING] [..]", $tool, "[..] --check-cfg ", $what, '(', $($who,)* ')', "[..]") } #[cfg(not(windows))] { concat!("[RUNNING] [..]", $tool, "[..] --check-cfg '", $what, '(', $($who,)* ')', "'", "[..]") } }}; ($tool:tt => $what:tt of $who:tt with $($first_value:tt $($other_values:tt)*)?) => {{ #[cfg(windows)] { concat!("[RUNNING] [..]", $tool, "[..] --check-cfg \"", $what, '(', $who, ", values(", $("/\"", $first_value, "/\"", $(", ", "/\"", $other_values, "/\"",)*)* "))", '"', "[..]") } #[cfg(not(windows))] { concat!("[RUNNING] [..]", $tool, "[..] --check-cfg '", $what, '(', $who, ", values(", $("\"", $first_value, "\"", $(", ", "\"", $other_values, "\"",)*)* "))", "'", "[..]") } }}; } #[cargo_test] fn features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [features] f_a = [] f_b = [] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check -v") .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b")) .with_stderr_contains(x!("rustc" => "cfg" of "docsrs,test")) .run(); } #[cargo_test] fn features_with_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar/" } [features] f_a = [] f_b = [] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "#[allow(dead_code)] fn bar() {}") .build(); p.cargo("check -v") .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b")) .with_stderr_contains(x!("rustc" => "cfg" of "docsrs,test")) .run(); } #[cargo_test] fn features_with_opt_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar/", optional = true } [features] default = ["bar"] f_a = [] f_b = [] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "#[allow(dead_code)] fn bar() {}") .build(); p.cargo("check -v") .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "bar" "default" "f_a" "f_b")) .with_stderr_contains(x!("rustc" => "cfg" of "docsrs,test")) .run(); } #[cargo_test] fn features_with_namespaced_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar/", optional = true } [features] f_a = ["dep:bar"] f_b = [] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "#[allow(dead_code)] fn bar() {}") .build(); p.cargo("check -v") .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b")) .with_stderr_contains(x!("rustc" => "cfg" of "docsrs,test")) .run(); } #[cargo_test] fn features_fingerprint() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [features] f_a = [] f_b = [] "#, ) .file("src/lib.rs", "#[cfg(feature = \"f_b\")] fn entry() {}") .build(); p.cargo("check -v") .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b")) .with_stderr_does_not_contain("[..]unexpected_cfgs[..]") .run(); p.cargo("check -v") .with_stderr_does_not_contain("[..]rustc[..]") .run(); // checking that re-ordering the features does not invalid the fingerprint p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [features] f_b = [] f_a = [] "#, ); p.cargo("check -v") .with_stderr_does_not_contain("[..]rustc[..]") .run(); p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [features] f_a = [] "#, ); p.cargo("check -v") // we check that the fingerprint is indeed dirty // that is cause rustc to be called again with the new check-cfg args // and that we indeed found a new warning from the unexpected_cfgs lint .with_stderr_data(format!( "\ [DIRTY] foo v0.1.0 ([ROOT]/foo): the list of declared features changed [CHECKING] foo v0.1.0 ([ROOT]/foo) {running_rustc} [WARNING] unexpected `cfg` condition value: `f_b` ... ", running_rustc = x!("rustc" => "cfg" of "feature" with "f_a") )) .run(); } #[cargo_test] fn well_known_names_values() { let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check -v") .with_stderr_contains(x!("rustc" => "cfg" of "feature" with)) .with_stderr_contains(x!("rustc" => "cfg" of "docsrs,test")) .run(); } #[cargo_test] fn features_test() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [features] f_a = [] f_b = [] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("test -v") .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b")) .with_stderr_contains(x!("rustc" => "cfg" of "docsrs,test")) .run(); } #[cargo_test] fn features_doctest() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [features] default = ["f_a"] f_a = [] f_b = [] "#, ) .file("src/lib.rs", "#[allow(dead_code)] fn foo() {}") .build(); p.cargo("test -v --doc") .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "default" "f_a" "f_b")) .with_stderr_contains(x!("rustdoc" => "cfg" of "feature" with "default" "f_a" "f_b")) .with_stderr_contains(x!("rustc" => "cfg" of "docsrs,test")) .with_stderr_contains(x!("rustdoc" => "cfg" of "docsrs,test")) .run(); } #[cargo_test] fn well_known_names_values_test() { let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/main.rs", "fn main() {}") .build(); p.cargo("test -v") .with_stderr_contains(x!("rustc" => "cfg" of "feature" with)) .with_stderr_contains(x!("rustc" => "cfg" of "docsrs,test")) .run(); } #[cargo_test] fn well_known_names_values_doctest() { let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/lib.rs", "#[allow(dead_code)] fn foo() {}") .build(); p.cargo("test -v --doc") .with_stderr_contains(x!("rustc" => "cfg" of "feature" with)) .with_stderr_contains(x!("rustdoc" => "cfg" of "feature" with)) .with_stderr_contains(x!("rustc" => "cfg" of "docsrs,test")) .with_stderr_contains(x!("rustdoc" => "cfg" of "docsrs,test")) .run(); } #[cargo_test] fn features_doc() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [features] default = ["f_a"] f_a = [] f_b = [] "#, ) .file("src/lib.rs", "#[allow(dead_code)] fn foo() {}") .build(); p.cargo("doc -v") .with_stderr_contains(x!("rustdoc" => "cfg" of "feature" with "default" "f_a" "f_b")) .with_stderr_contains(x!("rustdoc" => "cfg" of "docsrs,test")) .run(); } #[cargo_test] fn build_script_feedback() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/main.rs", "fn main() {}") .file( "build.rs", r#"fn main() { println!("cargo::rustc-check-cfg=cfg(foo)"); }"#, ) .build(); p.cargo("check -v") .with_stderr_contains(x!("rustc" => "cfg" of "foo")) .with_stderr_contains(x!("rustc" => "cfg" of "docsrs,test")) .run(); } #[cargo_test] fn build_script_doc() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/main.rs", "fn main() {}") .file( "build.rs", r#"fn main() { println!("cargo::rustc-check-cfg=cfg(foo)"); }"#, ) .build(); p.cargo("doc -v") .with_stderr_does_not_contain("rustc [..] --check-cfg [..]") .with_stderr_data(format!( "\ [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] build.rs [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) {running_rustdoc} [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html ", running_rustdoc = x!("rustdoc" => "cfg" of "foo") )) .run(); } #[cargo_test] fn build_script_override() { let target = cargo_test_support::rustc_host(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] links = "a" build = "build.rs" "#, ) .file("src/main.rs", "fn main() {}") .file("build.rs", "") .file( ".cargo/config.toml", &format!( r#" [target.{}.a] rustc-check-cfg = ["cfg(foo)"] "#, target ), ) .build(); p.cargo("check -v") .with_stderr_contains(x!("rustc" => "cfg" of "foo")) .with_stderr_contains(x!("rustc" => "cfg" of "feature" with)) .with_stderr_contains(x!("rustc" => "cfg" of "docsrs,test")) .run(); } #[cargo_test] fn build_script_test() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "build.rs", r#"fn main() { println!("cargo::rustc-check-cfg=cfg(foo)"); println!("cargo::rustc-cfg=foo"); }"#, ) .file( "src/lib.rs", r#" /// /// ``` /// extern crate foo; /// /// fn main() { /// foo::foo() /// } /// ``` /// #[cfg(foo)] pub fn foo() {} #[cfg(foo)] #[test] fn test_foo() { foo() } "#, ) .file("tests/test.rs", "#[cfg(foo)] #[test] fn test_bar() {}") .build(); p.cargo("test -v") .with_stderr_data( format!( "\ {running_rustc} {running_rustdoc} ... ", running_rustc = x!("rustc" => "cfg" of "foo"), running_rustdoc = x!("rustdoc" => "cfg" of "foo") ) .unordered(), ) .with_stdout_data( str![[r#" test test_foo ... ok test test_bar ... ok test [..] ... ok ... "#]] .unordered(), ) .run(); } #[cargo_test] fn config_simple() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ["cfg(has_foo)", "cfg(has_bar, values(\"yes\", \"no\"))"] } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check -v") .with_stderr_contains(x!("rustc" => "cfg" of "has_foo")) .with_stderr_contains(x!("rustc" => "cfg" of "has_bar" with "yes" "no")) .with_stderr_does_not_contain("[..]unused manifest key[..]") .run(); } #[cargo_test] fn config_workspace() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo/"] [workspace.lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ["cfg(has_foo)"] } "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lints] workspace = true "#, ) .file("foo/src/main.rs", "fn main() {}") .build(); p.cargo("check -v") .with_stderr_data(format!( "\ ... {running_rustc} ... ", running_rustc = x!("rustc" => "cfg" of "has_foo") )) .with_stderr_does_not_contain("unexpected_cfgs") .run(); } #[cargo_test] fn config_workspace_not_inherited() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo/"] [workspace.lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ["cfg(has_foo)"] } "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file("foo/src/main.rs", "fn main() {}") .build(); p.cargo("check -v") .with_stderr_does_not_contain(x!("rustc" => "cfg" of "has_foo")) .with_stderr_does_not_contain("unexpected_cfgs") .run(); } #[cargo_test] fn config_invalid_position() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lints.rust] use_bracket = { level = "warn", check-cfg = ["cfg(has_foo)"] } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check -v") .with_stderr_data(str![[r#" [WARNING] unused manifest key: `lints.rust.use_bracket.check-cfg` ... "#]]) .with_stderr_does_not_contain(x!("rustc" => "cfg" of "has_foo")) .run(); } #[cargo_test] fn config_invalid_empty() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lints.rust] unexpected_cfgs = { } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] missing field `level` ... "#]]) .run(); } #[cargo_test] fn config_invalid_not_list() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = "cfg()" } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `lints.rust.unexpected_cfgs.check-cfg` must be a list of string "#]]) .run(); } #[cargo_test] fn config_invalid_not_list_string() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [12] } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `lints.rust.unexpected_cfgs.check-cfg` must be a list of string "#]]) .run(); } #[cargo_test] fn config_and_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [features] my_feature = [] alloc = [] [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ["cfg(has_foo)", "cfg(has_bar, values(\"yes\", \"no\"))"] } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check -v") .with_stderr_contains(x!("rustc" => "cfg" of "has_foo")) .with_stderr_contains(x!("rustc" => "cfg" of "has_bar" with "yes" "no")) .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "alloc" "my_feature")) .run(); } #[cargo_test] fn config_with_cargo_doc() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ["cfg(has_foo)"] } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("doc -v") .with_stderr_data(format!( "\ ... {running_rustdoc} ... ", running_rustdoc = x!("rustdoc" => "cfg" of "has_foo") )) .run(); } #[cargo_test] fn config_with_cargo_test() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ["cfg(has_foo)"] } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("test -v") .with_stderr_data(format!( "\ ... {running_rustc} ... ", running_rustc = x!("rustc" => "cfg" of "has_foo") )) .run(); } #[cargo_test] fn config_and_build_script() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2021" build = "build.rs" [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ["cfg(bar)"] } "#, ) .file("src/main.rs", "fn main() {}") .file( "build.rs", r#"fn main() { println!("cargo::rustc-check-cfg=cfg(foo)"); }"#, ) .build(); p.cargo("check -v") .with_stderr_contains(x!("rustc" => "cfg" of "foo")) // from build.rs .with_stderr_contains(x!("rustc" => "cfg" of "bar")) // from config .run(); } #[cargo_test] fn config_features_and_build_script() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2021" build = "build.rs" [features] serde = [] json = [] [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ["cfg(bar)"] } "#, ) .file("src/main.rs", "fn main() {}") .file( "build.rs", r#"fn main() { println!("cargo::rustc-check-cfg=cfg(foo)"); }"#, ) .build(); p.cargo("check -v") .with_stderr_contains(x!("rustc" => "cfg" of "foo")) // from build.rs .with_stderr_contains(x!("rustc" => "cfg" of "bar")) // from config .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "json" "serde")) // features .with_stderr_contains(x!("rustc" => "cfg" of "docsrs,test")) // Cargo well known .run(); } #[cargo_test] fn config_fingerprint() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ["cfg(bar)"] } "#, ) .file("src/lib.rs", "fn entry() {}") .build(); p.cargo("check -v") .with_stderr_contains(x!("rustc" => "cfg" of "bar")) .run(); p.cargo("check -v") .with_stderr_does_not_contain("[..]rustc[..]") .run(); // checking that changing the `check-cfg` config does invalid the fingerprint p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ["cfg(bar)", "cfg(foo)"] } "#, ); p.cargo("check -v") // we check that the fingerprint is indeed dirty .with_stderr_contains("[..][DIRTY][..]the profile configuration changed") // that cause rustc to be called again with the new check-cfg args .with_stderr_contains(x!("rustc" => "cfg" of "bar")) .with_stderr_contains(x!("rustc" => "cfg" of "foo")) .run(); } cargo-0.86.0/tests/testsuite/clean.rs000064400000000000000000000613151046102023000156430ustar 00000000000000//! Tests for the `cargo clean` command. use cargo_test_support::compare::assert_e2e; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::{ basic_bin_manifest, basic_manifest, git, main_file, project, project_in, rustc_host, }; use glob::GlobError; use std::env; use std::path::{Path, PathBuf}; #[cargo_test] fn cargo_clean_simple() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("build").run(); assert!(p.build_dir().is_dir()); p.cargo("clean").run(); assert!(!p.build_dir().is_dir()); } #[cargo_test] fn different_dir() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .file("src/bar/a.rs", "") .build(); p.cargo("build").run(); assert!(p.build_dir().is_dir()); p.cargo("clean") .cwd("src") .with_stderr_data(str![[r#" [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); assert!(!p.build_dir().is_dir()); } #[cargo_test] fn clean_multiple_packages() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.d1] path = "d1" [dependencies.d2] path = "d2" [[bin]] name = "foo" "#, ) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .file("d1/Cargo.toml", &basic_bin_manifest("d1")) .file("d1/src/main.rs", "fn main() { println!(\"d1\"); }") .file("d2/Cargo.toml", &basic_bin_manifest("d2")) .file("d2/src/main.rs", "fn main() { println!(\"d2\"); }") .build(); p.cargo("build -p d1 -p d2 -p foo").run(); let d1_path = &p .build_dir() .join("debug") .join(format!("d1{}", env::consts::EXE_SUFFIX)); let d2_path = &p .build_dir() .join("debug") .join(format!("d2{}", env::consts::EXE_SUFFIX)); assert!(p.bin("foo").is_file()); assert!(d1_path.is_file()); assert!(d2_path.is_file()); p.cargo("clean -p d1 -p d2") .cwd("src") .with_stderr_data(str![[r#" [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); assert!(p.bin("foo").is_file()); assert!(!d1_path.is_file()); assert!(!d2_path.is_file()); } #[cargo_test] fn clean_multiple_packages_in_glob_char_path() { let p = project_in("[d1]") .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); let foo_path = &p.build_dir().join("debug").join("deps"); #[cfg(not(target_env = "msvc"))] let file_glob = "foo-*"; #[cfg(target_env = "msvc")] let file_glob = "foo.pdb"; // Assert that build artifacts are produced p.cargo("build").run(); assert_ne!(get_build_artifacts(foo_path, file_glob).len(), 0); // Assert that build artifacts are destroyed p.cargo("clean -p foo").run(); assert_eq!(get_build_artifacts(foo_path, file_glob).len(), 0); } fn get_build_artifacts(path: &PathBuf, file_glob: &str) -> Vec> { let pattern = path.to_str().expect("expected utf-8 path"); let pattern = glob::Pattern::escape(pattern); let path = PathBuf::from(pattern).join(file_glob); let path = path.to_str().expect("expected utf-8 path"); glob::glob(path) .expect("expected glob to run") .into_iter() .collect::>>() } #[cargo_test] fn clean_p_only_cleans_specified_package() { let p = project() .file( "Cargo.toml", r#" [workspace] members = [ "foo", "foo_core", "foo-base", ] "#, ) .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/lib.rs", "//! foo") .file("foo_core/Cargo.toml", &basic_manifest("foo_core", "0.1.0")) .file("foo_core/src/lib.rs", "//! foo_core") .file("foo-base/Cargo.toml", &basic_manifest("foo-base", "0.1.0")) .file("foo-base/src/lib.rs", "//! foo-base") .build(); let fingerprint_path = &p.build_dir().join("debug").join(".fingerprint"); p.cargo("build -p foo -p foo_core -p foo-base").run(); let mut fingerprint_names = get_fingerprints_without_hashes(fingerprint_path); // Artifacts present for all after building assert!(fingerprint_names.iter().any(|e| e == "foo")); let num_foo_core_artifacts = fingerprint_names .iter() .filter(|&e| e == "foo_core") .count(); assert_ne!(num_foo_core_artifacts, 0); let num_foo_base_artifacts = fingerprint_names .iter() .filter(|&e| e == "foo-base") .count(); assert_ne!(num_foo_base_artifacts, 0); p.cargo("clean -p foo").run(); fingerprint_names = get_fingerprints_without_hashes(fingerprint_path); // Cleaning `foo` leaves artifacts for the others assert!(!fingerprint_names.iter().any(|e| e == "foo")); assert_eq!( fingerprint_names .iter() .filter(|&e| e == "foo_core") .count(), num_foo_core_artifacts, ); assert_eq!( fingerprint_names .iter() .filter(|&e| e == "foo-base") .count(), num_foo_core_artifacts, ); } fn get_fingerprints_without_hashes(fingerprint_path: &Path) -> Vec { std::fs::read_dir(fingerprint_path) .expect("Build dir should be readable") .filter_map(|entry| entry.ok()) .map(|entry| { let name = entry.file_name(); let name = name .into_string() .expect("fingerprint name should be UTF-8"); name.rsplit_once('-') .expect("Name should contain at least one hyphen") .0 .to_owned() }) .collect() } #[cargo_test] fn clean_release() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a" } "#, ) .file("src/main.rs", "fn main() {}") .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/src/lib.rs", "") .build(); p.cargo("build --release").run(); p.cargo("clean -p foo").run(); p.cargo("build --release") .with_stderr_data(str![[r#" [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("clean -p foo --release").run(); p.cargo("build --release") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build").run(); p.cargo("clean").arg("--release").run(); assert!(p.build_dir().is_dir()); assert!(p.build_dir().join("debug").is_dir()); assert!(!p.build_dir().join("release").is_dir()); } #[cargo_test] fn clean_doc() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a" } "#, ) .file("src/main.rs", "fn main() {}") .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/src/lib.rs", "") .build(); p.cargo("doc").run(); let doc_path = &p.build_dir().join("doc"); assert!(doc_path.is_dir()); p.cargo("clean --doc") .with_stderr_data(str![[r#" [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); assert!(!doc_path.is_dir()); assert!(p.build_dir().is_dir()); } #[cargo_test] fn build_script() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file("src/main.rs", "fn main() {}") .file( "build.rs", r#" use std::path::PathBuf; use std::env; fn main() { let out = PathBuf::from(env::var_os("OUT_DIR").unwrap()); if env::var("FIRST").is_ok() { std::fs::File::create(out.join("out")).unwrap(); } else { assert!(!out.join("out").exists()); } } "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("build").env("FIRST", "1").run(); p.cargo("clean -p foo").run(); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] build.rs [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc [..] src/main.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn clean_git() { let git = git::new("dep", |project| { project .file("Cargo.toml", &basic_manifest("dep", "0.5.0")) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] dep = {{ git = '{}' }} "#, git.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build").run(); p.cargo("clean -p dep") .with_stderr_data(str![[r#" [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); p.cargo("build").run(); } #[cargo_test] fn registry() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.1.0").publish(); p.cargo("build").run(); p.cargo("clean -p bar") .with_stderr_data(str![[r#" [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); p.cargo("build").run(); } #[cargo_test] fn clean_verbose() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.1.0").publish(); p.cargo("build").run(); let mut expected = String::from( "\ [REMOVING] [ROOT]/foo/target/debug/.fingerprint/bar-[HASH] [REMOVING] [ROOT]/foo/target/debug/deps/libbar-[HASH].rlib [REMOVING] [ROOT]/foo/target/debug/deps/bar-[HASH].d [REMOVING] [ROOT]/foo/target/debug/deps/libbar-[HASH].rmeta ", ); if cfg!(target_os = "macos") { // Rust 1.69 has changed so that split-debuginfo=unpacked includes unpacked for rlibs. for _ in p.glob("target/debug/deps/bar-*.o") { expected.push_str("[REMOVING] [ROOT]/foo/target/debug/deps/bar-[HASH][..].o\n"); } } expected.push_str("[REMOVED] [FILE_NUM] files, [FILE_SIZE]B total\n"); p.cargo("clean -p bar --verbose") .with_stderr_data(&expected.unordered()) .run(); p.cargo("build").run(); } #[cargo_test] fn clean_remove_rlib_rmeta() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build").run(); assert!(p.target_debug_dir().join("libfoo.rlib").exists()); let rmeta = p.glob("target/debug/deps/*.rmeta").next().unwrap().unwrap(); assert!(rmeta.exists()); p.cargo("clean -p foo").run(); assert!(!p.target_debug_dir().join("libfoo.rlib").exists()); assert!(!rmeta.exists()); } #[cargo_test] fn package_cleans_all_the_things() { // -p cleans everything // Use dashes everywhere to make sure dash/underscore stuff is handled. for crate_type in &["rlib", "dylib", "cdylib", "staticlib", "proc-macro"] { // Try each crate type individually since the behavior changes when // they are combined. let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo-bar" version = "0.1.0" edition = "2015" [lib] crate-type = ["{}"] "#, crate_type ), ) .file("src/lib.rs", "") .build(); p.cargo("build").run(); p.cargo("clean -p foo-bar").run(); assert_all_clean(&p.build_dir()); } let p = project() .file( "Cargo.toml", r#" [package] name = "foo-bar" version = "0.1.0" edition = "2018" [lib] crate-type = ["rlib", "dylib", "staticlib"] [[example]] name = "foo-ex-rlib" crate-type = ["rlib"] test = true [[example]] name = "foo-ex-cdylib" crate-type = ["cdylib"] test = true [[example]] name = "foo-ex-bin" test = true "#, ) .file("src/lib.rs", "") .file("src/lib/some-main.rs", "fn main() {}") .file("src/bin/other-main.rs", "fn main() {}") .file("examples/foo-ex-rlib.rs", "") .file("examples/foo-ex-cdylib.rs", "") .file("examples/foo-ex-bin.rs", "fn main() {}") .file("tests/foo-test.rs", "") .file("benches/foo-bench.rs", "") .file("build.rs", "fn main() {}") .build(); p.cargo("build --all-targets") .env("CARGO_INCREMENTAL", "1") .run(); p.cargo("test --all-targets") .env("CARGO_INCREMENTAL", "1") .run(); p.cargo("check --all-targets") .env("CARGO_INCREMENTAL", "1") .run(); p.cargo("clean -p foo-bar").run(); assert_all_clean(&p.build_dir()); // Try some targets. p.cargo("build --all-targets --target") .arg(rustc_host()) .run(); p.cargo("clean -p foo-bar --target").arg(rustc_host()).run(); assert_all_clean(&p.build_dir()); } // Ensures that all files for the package have been deleted. #[track_caller] fn assert_all_clean(build_dir: &Path) { let walker = walkdir::WalkDir::new(build_dir).into_iter(); for entry in walker.filter_entry(|e| { let path = e.path(); // This is a known limitation, clean can't differentiate between // the different build scripts from different packages. !(path .file_name() .unwrap() .to_str() .unwrap() .starts_with("build_script_build") && path .parent() .unwrap() .file_name() .unwrap() .to_str() .unwrap() == "incremental") }) { let entry = entry.unwrap(); let path = entry.path(); if let ".rustc_info.json" | ".cargo-lock" | "CACHEDIR.TAG" = path.file_name().unwrap().to_str().unwrap() { continue; } if path.is_symlink() || path.is_file() { panic!("{:?} was not cleaned", path); } } } #[cargo_test] fn clean_spec_version() { // clean -p foo where foo matches multiple versions Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.2.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar1 = {version="0.1", package="bar"} bar2 = {version="0.2", package="bar"} "#, ) .file("src/lib.rs", "") .build(); p.cargo("build").run(); // Check suggestion for bad pkgid. p.cargo("clean -p baz") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package ID specification `baz` did not match any packages Did you mean `bar`? "#]]) .run(); p.cargo("clean -p bar:0.1.0") .with_stderr_data(str![[r#" [WARNING] version qualifier in `-p bar:0.1.0` is ignored, cleaning all versions of `bar` found [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); let mut walker = walkdir::WalkDir::new(p.build_dir()) .into_iter() .filter_map(|e| e.ok()) .filter(|e| { let n = e.file_name().to_str().unwrap(); n.starts_with("bar") || n.starts_with("libbar") }); if let Some(e) = walker.next() { panic!("{:?} was not cleaned", e.path()); } } #[cargo_test] fn clean_spec_partial_version() { // clean -p foo where foo matches multiple versions Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.2.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar1 = {version="0.1", package="bar"} bar2 = {version="0.2", package="bar"} "#, ) .file("src/lib.rs", "") .build(); p.cargo("build").run(); // Check suggestion for bad pkgid. p.cargo("clean -p baz") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package ID specification `baz` did not match any packages Did you mean `bar`? "#]]) .run(); p.cargo("clean -p bar:0.1") .with_stderr_data(str![[r#" [WARNING] version qualifier in `-p bar:0.1` is ignored, cleaning all versions of `bar` found [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); let mut walker = walkdir::WalkDir::new(p.build_dir()) .into_iter() .filter_map(|e| e.ok()) .filter(|e| { let n = e.file_name().to_str().unwrap(); n.starts_with("bar") || n.starts_with("libbar") }); if let Some(e) = walker.next() { panic!("{:?} was not cleaned", e.path()); } } #[cargo_test] fn clean_spec_partial_version_ambiguous() { // clean -p foo where foo matches multiple versions Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.2.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar1 = {version="0.1", package="bar"} bar2 = {version="0.2", package="bar"} "#, ) .file("src/lib.rs", "") .build(); p.cargo("build").run(); // Check suggestion for bad pkgid. p.cargo("clean -p baz") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package ID specification `baz` did not match any packages Did you mean `bar`? "#]]) .run(); p.cargo("clean -p bar:0") .with_stderr_data(str![[r#" [WARNING] version qualifier in `-p bar:0` is ignored, cleaning all versions of `bar` found [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); let mut walker = walkdir::WalkDir::new(p.build_dir()) .into_iter() .filter_map(|e| e.ok()) .filter(|e| { let n = e.file_name().to_str().unwrap(); n.starts_with("bar") || n.starts_with("libbar") }); if let Some(e) = walker.next() { panic!("{:?} was not cleaned", e.path()); } } #[cargo_test] fn clean_spec_reserved() { // Clean when a target (like a test) has a reserved name. In this case, // make sure `clean -p` doesn't delete the reserved directory `build` when // there is a test named `build`. Package::new("bar", "1.0.0") .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .file("tests/build.rs", "") .build(); p.cargo("build --all-targets").run(); assert!(p.target_debug_dir().join("build").is_dir()); let build_test = p.glob("target/debug/deps/build-*").next().unwrap().unwrap(); assert!(build_test.exists()); // Tests are never "uplifted". assert!(p.glob("target/debug/build-*").next().is_none()); p.cargo("clean -p foo").run(); // Should not delete this. assert!(p.target_debug_dir().join("build").is_dir()); // This should not rebuild bar. p.cargo("build -v --all-targets") .with_stderr_data(str![[r#" [FRESH] bar v1.0.0 [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..]` [RUNNING] `rustc [..]` [RUNNING] `rustc [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn clean_dry_run() { // Basic `clean --dry-run` test. Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); // Start with no files. p.cargo("clean --dry-run") .with_stdout_data("") .with_stderr_data(str![[r#" [SUMMARY] 0 files [WARNING] no files deleted due to --dry-run "#]]) .run(); p.cargo("check").run(); let before = p.build_dir().ls_r(); p.cargo("clean --dry-run") .with_stderr_data(str![[r#" [SUMMARY] [FILE_NUM] files, [FILE_SIZE]B total [WARNING] no files deleted due to --dry-run "#]]) .run(); // Verify it didn't delete anything. let after = p.build_dir().ls_r(); assert_eq!(before, after); let mut expected = itertools::join(before.iter().map(|p| p.to_str().unwrap()), "\n"); expected.push_str("\n"); let expected = snapbox::filter::normalize_paths(&expected); let expected = assert_e2e().redactions().redact(&expected); eprintln!("{expected}"); // Verify the verbose output. p.cargo("clean --dry-run -v") .with_stdout_data(expected.unordered()) .with_stderr_data(str![[r#" [SUMMARY] [FILE_NUM] files, [FILE_SIZE]B total [WARNING] no files deleted due to --dry-run "#]]) .run(); } #[cargo_test] fn doc_with_package_selection() { // --doc with -p let p = project().file("src/lib.rs", "").build(); p.cargo("clean --doc -p foo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] --doc cannot be used with -p "#]]) .run(); } #[cargo_test] fn quiet_does_not_show_summary() { // Checks that --quiet works with `cargo clean`, since there was a // subtle issue with how the flag is defined as a global flag. let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/lib.rs", "") .build(); p.cargo("check").run(); p.cargo("clean --quiet --dry-run") .with_stdout_data("") .with_stderr_data("") .run(); // Verify exact same command without -q would actually display something. p.cargo("clean --dry-run") .with_stdout_data("") .with_stderr_data(str![[r#" [SUMMARY] [FILE_NUM] files, [FILE_SIZE]B total [WARNING] no files deleted due to --dry-run "#]]) .run(); } cargo-0.86.0/tests/testsuite/collisions.rs000064400000000000000000000427111046102023000167360ustar 00000000000000//! Tests for when multiple artifacts have the same output filename. //! See for more details. //! Ideally these should never happen, but I don't think we'll ever be able to //! prevent all collisions. use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::{basic_manifest, cross_compile, project}; use std::env; #[cargo_test] fn collision_dylib() { // Path dependencies don't include metadata hash in filename for dylibs. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "1.0.0" edition = "2015" [lib] crate-type = ["dylib"] "#, ) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "1.0.0" edition = "2015" [lib] crate-type = ["dylib"] name = "a" "#, ) .file("b/src/lib.rs", "") .build(); // `j=1` is required because on Windows you'll get an error due to // two processes writing to the file at the same time. p.cargo("build -j=1") .with_stderr_data(&format!("\ ... [WARNING] output filename collision. The lib target `a` in package `b v1.0.0 ([ROOT]/foo/b)` has the same output filename as the lib target `a` in package `a v1.0.0 ([ROOT]/foo/a)`. Colliding filename is: [ROOT]/foo/target/debug/deps/{}a{} The targets should have unique names. Consider changing their names to be unique or compiling them separately. This may become a hard error in the future; see . ... ", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX)) .run(); } #[cargo_test] fn collision_example() { // Examples in a workspace can easily collide. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file("a/Cargo.toml", &basic_manifest("a", "1.0.0")) .file("a/examples/ex1.rs", "fn main() {}") .file("b/Cargo.toml", &basic_manifest("b", "1.0.0")) .file("b/examples/ex1.rs", "fn main() {}") .build(); // `j=1` is required because on Windows you'll get an error due to // two processes writing to the file at the same time. p.cargo("build --examples -j=1") .with_stderr_data(str![[r#" ... [WARNING] output filename collision. The example target `ex1` in package `b v1.0.0 ([ROOT]/foo/b)` has the same output filename as the example target `ex1` in package `a v1.0.0 ([ROOT]/foo/a)`. Colliding filename is: [ROOT]/foo/target/debug/examples/ex1[EXE] The targets should have unique names. Consider changing their names to be unique or compiling them separately. This may become a hard error in the future; see . ... "#]]) .run(); } #[cargo_test] // See https://github.com/rust-lang/cargo/issues/7493 #[cfg_attr( any(target_env = "msvc", target_vendor = "apple"), ignore = "--artifact-dir and examples are currently broken on MSVC and apple" )] fn collision_export() { // `--artifact-dir` combines some things which can cause conflicts. let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("examples/foo.rs", "fn main() {}") .file("src/main.rs", "fn main() {}") .build(); // -j1 to avoid issues with two processes writing to the same file at the // same time. p.cargo("build -j1 --artifact-dir=out -Z unstable-options --bins --examples") .masquerade_as_nightly_cargo(&["artifact-dir"]) .with_stderr_data(str![[r#" [WARNING] `--artifact-dir` filename collision. The example target `foo` in package `foo v1.0.0 ([ROOT]/foo)` has the same output filename as the bin target `foo` in package `foo v1.0.0 ([ROOT]/foo)`. Colliding filename is: [ROOT]/foo/out/foo[EXE] The exported filenames should be unique. Consider changing their names to be unique or compiling them separately. This may become a hard error in the future; see . ... "#]]) .run(); } #[cargo_test] fn collision_doc() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] foo2 = { path = "foo2" } "#, ) .file("src/lib.rs", "") .file( "foo2/Cargo.toml", r#" [package] name = "foo2" version = "0.1.0" edition = "2015" [lib] name = "foo" "#, ) .file("foo2/src/lib.rs", "") .build(); p.cargo("doc -j=1") .with_stderr_data(str![[r#" ... [WARNING] output filename collision. The lib target `foo` in package `foo2 v0.1.0 ([ROOT]/foo/foo2)` has the same output filename as the lib target `foo` in package `foo v0.1.0 ([ROOT]/foo)`. Colliding filename is: [ROOT]/foo/target/doc/foo/index.html The targets should have unique names. This is a known bug where multiple crates with the same name use the same path; see . ... "#]]) .run(); } #[cargo_test] fn collision_doc_multiple_versions() { // Multiple versions of the same package. Package::new("old-dep", "1.0.0").publish(); Package::new("bar", "1.0.0").dep("old-dep", "1.0").publish(); // Note that this removes "old-dep". Just checking what happens when there // are orphans. Package::new("bar", "2.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" bar2 = { package="bar", version="2.0" } "#, ) .file("src/lib.rs", "") .build(); // Should only document bar 2.0, should not document old-dep. p.cargo("doc") .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 3 packages to latest compatible versions [ADDING] bar v1.0.0 (available: v2.0.0) [DOWNLOADING] crates ... [DOWNLOADED] bar v2.0.0 (registry `dummy-registry`) [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [DOWNLOADED] old-dep v1.0.0 (registry `dummy-registry`) [CHECKING] old-dep v1.0.0 [CHECKING] bar v2.0.0 [CHECKING] bar v1.0.0 [DOCUMENTING] bar v2.0.0 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [DOCUMENTING] foo v0.1.0 ([ROOT]/foo) [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]] .unordered(), ) .run(); } #[cargo_test] fn collision_doc_host_target_feature_split() { // Same dependency built twice due to different features. // // foo v0.1.0 // β”œβ”€β”€ common v1.0.0 // β”‚ └── common-dep v1.0.0 // └── pm v0.1.0 (proc-macro) // └── common v1.0.0 // └── common-dep v1.0.0 // [build-dependencies] // └── common-dep v1.0.0 // // Here `common` and `common-dep` are built twice. `common-dep` has // different features for host versus target. Package::new("common-dep", "1.0.0") .feature("bdep-feat", &[]) .file( "src/lib.rs", r#" /// Some doc pub fn f() {} /// Another doc #[cfg(feature = "bdep-feat")] pub fn bdep_func() {} "#, ) .publish(); Package::new("common", "1.0.0") .dep("common-dep", "1.0") .file( "src/lib.rs", r#" /// Some doc pub fn f() {} "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" resolver = "2" [dependencies] pm = { path = "pm" } common = "1.0" [build-dependencies] common-dep = { version = "1.0", features = ["bdep-feat"] } "#, ) .file( "src/lib.rs", r#" /// Some doc pub fn f() {} "#, ) .file("build.rs", "fn main() {}") .file( "pm/Cargo.toml", r#" [package] name = "pm" version = "0.1.0" edition = "2018" [lib] proc-macro = true [dependencies] common = "1.0" "#, ) .file( "pm/src/lib.rs", r#" use proc_macro::TokenStream; /// Some doc #[proc_macro] pub fn pm(_input: TokenStream) -> TokenStream { "".parse().unwrap() } "#, ) .build(); // No warnings, no duplicates, common and common-dep only documented once. p.cargo("doc") // Cannot check full output due to https://github.com/rust-lang/cargo/issues/9076 .with_stderr_does_not_contain("[WARNING][..]") .run(); assert!(p.build_dir().join("doc/common_dep/fn.f.html").exists()); assert!(!p .build_dir() .join("doc/common_dep/fn.bdep_func.html") .exists()); assert!(p.build_dir().join("doc/common/fn.f.html").exists()); assert!(p.build_dir().join("doc/pm/macro.pm.html").exists()); assert!(p.build_dir().join("doc/foo/fn.f.html").exists()); } #[cargo_test] fn collision_doc_profile_split() { // Same dependency built twice due to different profile settings. Package::new("common", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] pm = { path = "pm" } common = "1.0" [profile.dev] opt-level = 2 "#, ) .file("src/lib.rs", "") .file( "pm/Cargo.toml", r#" [package] name = "pm" version = "0.1.0" edition = "2015" [dependencies] common = "1.0" [lib] proc-macro = true "#, ) .file("pm/src/lib.rs", "") .build(); // Just to verify that common is normally built twice. // This is unordered because in rare cases `pm` may start // building in-between the two `common`. p.cargo("build -v") .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] common v1.0.0 (registry `dummy-registry`) [COMPILING] common v1.0.0 [RUNNING] `rustc --crate-name common [..] [RUNNING] `rustc --crate-name common [..] [COMPILING] pm v0.1.0 ([ROOT]/foo/pm) [RUNNING] `rustc --crate-name pm [..] [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] [FINISHED] `dev` profile [optimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); // Should only document common once, no warnings. p.cargo("doc") .with_stderr_data( str![[r#" [CHECKING] common v1.0.0 [DOCUMENTING] common v1.0.0 [DOCUMENTING] pm v0.1.0 ([ROOT]/foo/pm) [DOCUMENTING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [optimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]] .unordered(), ) .run(); } #[cargo_test] fn collision_doc_sources() { // Different sources with the same package. Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" bar2 = { path = "bar", package = "bar" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "1.0.0")) .file("bar/src/lib.rs", "") .build(); p.cargo("doc -j=1") .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [WARNING] output filename collision. The lib target `bar` in package `bar v1.0.0` has the same output filename as the lib target `bar` in package `bar v1.0.0 ([ROOT]/foo/bar)`. Colliding filename is: [ROOT]/foo/target/doc/bar/index.html The targets should have unique names. This is a known bug where multiple crates with the same name use the same path; see . [CHECKING] bar v1.0.0 ([ROOT]/foo/bar) [DOCUMENTING] bar v1.0.0 ([ROOT]/foo/bar) [DOCUMENTING] bar v1.0.0 [CHECKING] bar v1.0.0 [DOCUMENTING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]] .unordered(), ) .run(); } #[cargo_test] fn collision_doc_target() { // collision in doc with --target, doesn't fail due to orphans if cross_compile::disabled() { return; } Package::new("orphaned", "1.0.0").publish(); Package::new("bar", "1.0.0") .dep("orphaned", "1.0") .publish(); Package::new("bar", "2.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar2 = { version = "2.0", package="bar" } bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("doc --target") .arg(cross_compile::alternate()) .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 3 packages to latest compatible versions [ADDING] bar v1.0.0 (available: v2.0.0) [DOWNLOADING] crates ... [DOWNLOADED] orphaned v1.0.0 (registry `dummy-registry`) [DOWNLOADED] bar v2.0.0 (registry `dummy-registry`) [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [CHECKING] orphaned v1.0.0 [DOCUMENTING] bar v2.0.0 [CHECKING] bar v2.0.0 [CHECKING] bar v1.0.0 [DOCUMENTING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/[ALT_TARGET]/doc/foo/index.html "#]] .unordered(), ) .run(); } #[cargo_test] fn collision_with_root() { // Check for a doc collision between a root package and a dependency. // In this case, `foo-macro` comes from both the workspace and crates.io. // This checks that the duplicate correction code doesn't choke on this // by removing the root unit. Package::new("foo-macro", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["abc", "foo-macro"] "#, ) .file( "abc/Cargo.toml", r#" [package] name = "abc" version = "1.0.0" edition = "2015" [dependencies] foo-macro = "1.0" "#, ) .file("abc/src/lib.rs", "") .file( "foo-macro/Cargo.toml", r#" [package] name = "foo-macro" version = "1.0.0" edition = "2015" [lib] proc-macro = true [dependencies] abc = {path="../abc"} "#, ) .file("foo-macro/src/lib.rs", "") .build(); p.cargo("doc -j=1") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] foo-macro v1.0.0 (registry `dummy-registry`) [WARNING] output filename collision. The lib target `foo_macro` in package `foo-macro v1.0.0` has the same output filename as the lib target `foo_macro` in package `foo-macro v1.0.0 ([ROOT]/foo/foo-macro)`. Colliding filename is: [ROOT]/foo/target/doc/foo_macro/index.html The targets should have unique names. This is a known bug where multiple crates with the same name use the same path; see . [CHECKING] foo-macro v1.0.0 [DOCUMENTING] foo-macro v1.0.0 [CHECKING] abc v1.0.0 ([ROOT]/foo/abc) [DOCUMENTING] foo-macro v1.0.0 ([ROOT]/foo/foo-macro) [DOCUMENTING] abc v1.0.0 ([ROOT]/foo/abc) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/abc/index.html and 1 other file "#]].unordered()) .run(); } cargo-0.86.0/tests/testsuite/concurrent.rs000064400000000000000000000347551046102023000167530ustar 00000000000000//! Tests for running multiple `cargo` processes at the same time. use std::fs; use std::net::TcpListener; use std::process::Stdio; use std::sync::mpsc::channel; use std::thread; use std::{env, str}; use cargo_test_support::cargo_process; use cargo_test_support::git; use cargo_test_support::install::assert_has_installed_exe; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::{basic_manifest, execs, project, slow_cpu_multiplier}; fn pkg(name: &str, vers: &str) { Package::new(name, vers) .file("src/main.rs", "fn main() {{}}") .publish(); } #[cargo_test] fn multiple_installs() { let p = project() .no_manifest() .file("a/Cargo.toml", &basic_manifest("foo", "0.0.0")) .file("a/src/main.rs", "fn main() {}") .file("b/Cargo.toml", &basic_manifest("bar", "0.0.0")) .file("b/src/main.rs", "fn main() {}"); let p = p.build(); let mut a = p.cargo("install").cwd("a").build_command(); let mut b = p.cargo("install").cwd("b").build_command(); a.stdout(Stdio::piped()).stderr(Stdio::piped()); b.stdout(Stdio::piped()).stderr(Stdio::piped()); let a = a.spawn().unwrap(); let b = b.spawn().unwrap(); let a = thread::spawn(move || a.wait_with_output().unwrap()); let b = b.wait_with_output().unwrap(); let a = a.join().unwrap(); execs().run_output(&a); execs().run_output(&b); assert_has_installed_exe(paths::cargo_home(), "foo"); assert_has_installed_exe(paths::cargo_home(), "bar"); } #[cargo_test] fn concurrent_installs() { const LOCKED_BUILD: &str = "waiting for file lock on build directory"; pkg("foo", "0.0.1"); pkg("bar", "0.0.1"); let mut a = cargo_process("install foo").build_command(); let mut b = cargo_process("install bar").build_command(); a.stdout(Stdio::piped()).stderr(Stdio::piped()); b.stdout(Stdio::piped()).stderr(Stdio::piped()); let a = a.spawn().unwrap(); let b = b.spawn().unwrap(); let a = thread::spawn(move || a.wait_with_output().unwrap()); let b = b.wait_with_output().unwrap(); let a = a.join().unwrap(); assert!(!str::from_utf8(&a.stderr).unwrap().contains(LOCKED_BUILD)); assert!(!str::from_utf8(&b.stderr).unwrap().contains(LOCKED_BUILD)); execs().run_output(&a); execs().run_output(&b); assert_has_installed_exe(paths::cargo_home(), "foo"); assert_has_installed_exe(paths::cargo_home(), "bar"); } #[cargo_test] fn one_install_should_be_bad() { let p = project() .no_manifest() .file("a/Cargo.toml", &basic_manifest("foo", "0.0.0")) .file("a/src/main.rs", "fn main() {}") .file("b/Cargo.toml", &basic_manifest("foo", "0.0.0")) .file("b/src/main.rs", "fn main() {}"); let p = p.build(); let mut a = p.cargo("install").cwd("a").build_command(); let mut b = p.cargo("install").cwd("b").build_command(); a.stdout(Stdio::piped()).stderr(Stdio::piped()); b.stdout(Stdio::piped()).stderr(Stdio::piped()); let a = a.spawn().unwrap(); let b = b.spawn().unwrap(); let a = thread::spawn(move || a.wait_with_output().unwrap()); let b = b.wait_with_output().unwrap(); let a = a.join().unwrap(); execs().run_output(&a); execs().run_output(&b); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn multiple_registry_fetches() { let mut pkg = Package::new("bar", "1.0.2"); for i in 0..10 { let name = format!("foo{}", i); Package::new(&name, "1.0.0").publish(); pkg.dep(&name, "*"); } pkg.publish(); let p = project() .no_manifest() .file( "a/Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.0" [dependencies] bar = "*" "#, ) .file("a/src/main.rs", "fn main() {}") .file( "b/Cargo.toml", r#" [package] name = "bar" authors = [] version = "0.0.0" [dependencies] bar = "*" "#, ) .file("b/src/main.rs", "fn main() {}"); let p = p.build(); let mut a = p.cargo("build").cwd("a").build_command(); let mut b = p.cargo("build").cwd("b").build_command(); a.stdout(Stdio::piped()).stderr(Stdio::piped()); b.stdout(Stdio::piped()).stderr(Stdio::piped()); let a = a.spawn().unwrap(); let b = b.spawn().unwrap(); let a = thread::spawn(move || a.wait_with_output().unwrap()); let b = b.wait_with_output().unwrap(); let a = a.join().unwrap(); execs().run_output(&a); execs().run_output(&b); let suffix = env::consts::EXE_SUFFIX; assert!(p .root() .join("a/target/debug") .join(format!("foo{}", suffix)) .is_file()); assert!(p .root() .join("b/target/debug") .join(format!("bar{}", suffix)) .is_file()); } #[cargo_test] fn git_same_repo_different_tags() { let a = git::new("dep", |project| { project .file("Cargo.toml", &basic_manifest("dep", "0.5.0")) .file("src/lib.rs", "pub fn tag1() {}") }); let repo = git2::Repository::open(&a.root()).unwrap(); git::tag(&repo, "tag1"); a.change_file("src/lib.rs", "pub fn tag2() {}"); git::add(&repo); git::commit(&repo); git::tag(&repo, "tag2"); let p = project() .no_manifest() .file( "a/Cargo.toml", &format!( r#" [package] name = "foo" authors = [] version = "0.0.0" [dependencies] dep = {{ git = '{}', tag = 'tag1' }} "#, a.url() ), ) .file( "a/src/main.rs", "extern crate dep; fn main() { dep::tag1(); }", ) .file( "b/Cargo.toml", &format!( r#" [package] name = "bar" authors = [] version = "0.0.0" [dependencies] dep = {{ git = '{}', tag = 'tag2' }} "#, a.url() ), ) .file( "b/src/main.rs", "extern crate dep; fn main() { dep::tag2(); }", ); let p = p.build(); let mut a = p.cargo("build -v").cwd("a").build_command(); let mut b = p.cargo("build -v").cwd("b").build_command(); a.stdout(Stdio::piped()).stderr(Stdio::piped()); b.stdout(Stdio::piped()).stderr(Stdio::piped()); let a = a.spawn().unwrap(); let b = b.spawn().unwrap(); let a = thread::spawn(move || a.wait_with_output().unwrap()); let b = b.wait_with_output().unwrap(); let a = a.join().unwrap(); execs().run_output(&a); execs().run_output(&b); } #[cargo_test] fn git_same_branch_different_revs() { let a = git::new("dep", |project| { project .file("Cargo.toml", &basic_manifest("dep", "0.5.0")) .file("src/lib.rs", "pub fn f1() {}") }); let p = project() .no_manifest() .file( "a/Cargo.toml", &format!( r#" [package] name = "foo" authors = [] version = "0.0.0" [dependencies] dep = {{ git = '{}' }} "#, a.url() ), ) .file( "a/src/main.rs", "extern crate dep; fn main() { dep::f1(); }", ) .file( "b/Cargo.toml", &format!( r#" [package] name = "bar" authors = [] version = "0.0.0" [dependencies] dep = {{ git = '{}' }} "#, a.url() ), ) .file( "b/src/main.rs", "extern crate dep; fn main() { dep::f2(); }", ); let p = p.build(); // Generate a Cargo.lock pointing at the current rev, then clear out the // target directory p.cargo("build").cwd("a").run(); fs::remove_dir_all(p.root().join("a/target")).unwrap(); // Make a new commit on the master branch let repo = git2::Repository::open(&a.root()).unwrap(); a.change_file("src/lib.rs", "pub fn f2() {}"); git::add(&repo); git::commit(&repo); // Now run both builds in parallel. The build of `b` should pick up the // newest commit while the build of `a` should use the locked old commit. let mut a = p.cargo("build").cwd("a").build_command(); let mut b = p.cargo("build").cwd("b").build_command(); a.stdout(Stdio::piped()).stderr(Stdio::piped()); b.stdout(Stdio::piped()).stderr(Stdio::piped()); let a = a.spawn().unwrap(); let b = b.spawn().unwrap(); let a = thread::spawn(move || a.wait_with_output().unwrap()); let b = b.wait_with_output().unwrap(); let a = a.join().unwrap(); execs().run_output(&a); execs().run_output(&b); } #[cargo_test] fn same_project() { let p = project() .file("src/main.rs", "fn main() {}") .file("src/lib.rs", ""); let p = p.build(); let mut a = p.cargo("build").build_command(); let mut b = p.cargo("build").build_command(); a.stdout(Stdio::piped()).stderr(Stdio::piped()); b.stdout(Stdio::piped()).stderr(Stdio::piped()); let a = a.spawn().unwrap(); let b = b.spawn().unwrap(); let a = thread::spawn(move || a.wait_with_output().unwrap()); let b = b.wait_with_output().unwrap(); let a = a.join().unwrap(); execs().run_output(&a); execs().run_output(&b); } // Make sure that if Cargo dies while holding a lock that it's released and the // next Cargo to come in will take over cleanly. #[cargo_test] fn killing_cargo_releases_the_lock() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.0" build = "build.rs" "#, ) .file("src/main.rs", "fn main() {}") .file( "build.rs", r#" use std::net::TcpStream; fn main() { if std::env::var("A").is_ok() { TcpStream::connect(&std::env::var("ADDR").unwrap()[..]) .unwrap(); std::thread::sleep(std::time::Duration::new(10, 0)); } } "#, ); let p = p.build(); // Our build script will connect to our local TCP socket to inform us that // it's started and that's how we know that `a` will have the lock // when we kill it. let l = TcpListener::bind("127.0.0.1:0").unwrap(); let mut a = p.cargo("build").build_command(); let mut b = p.cargo("build").build_command(); a.stdout(Stdio::piped()).stderr(Stdio::piped()); b.stdout(Stdio::piped()).stderr(Stdio::piped()); a.env("ADDR", l.local_addr().unwrap().to_string()) .env("A", "a"); b.env("ADDR", l.local_addr().unwrap().to_string()) .env_remove("A"); // Spawn `a`, wait for it to get to the build script (at which point the // lock is held), then kill it. let mut a = a.spawn().unwrap(); l.accept().unwrap(); a.kill().unwrap(); // Spawn `b`, then just finish the output of a/b the same way the above // tests does. let b = b.spawn().unwrap(); let a = thread::spawn(move || a.wait_with_output().unwrap()); let b = b.wait_with_output().unwrap(); let a = a.join().unwrap(); // We killed `a`, so it shouldn't succeed, but `b` should have succeeded. assert!(!a.status.success()); execs().run_output(&b); } #[cargo_test] fn debug_release_ok() { let p = project().file("src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("build").run(); fs::remove_dir_all(p.root().join("target")).unwrap(); let mut a = p.cargo("build").build_command(); let mut b = p.cargo("build --release").build_command(); a.stdout(Stdio::piped()).stderr(Stdio::piped()); b.stdout(Stdio::piped()).stderr(Stdio::piped()); let a = a.spawn().unwrap(); let b = b.spawn().unwrap(); let a = thread::spawn(move || a.wait_with_output().unwrap()); let b = b.wait_with_output().unwrap(); let a = a.join().unwrap(); execs() .with_stderr_data(str![[r#" ... [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run_output(&a); execs() .with_stderr_data(str![[r#" ... [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run_output(&b); } #[cargo_test] fn no_deadlock_with_git_dependencies() { let dep1 = git::new("dep1", |project| { project .file("Cargo.toml", &basic_manifest("dep1", "0.5.0")) .file("src/lib.rs", "") }); let dep2 = git::new("dep2", |project| { project .file("Cargo.toml", &basic_manifest("dep2", "0.5.0")) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" authors = [] version = "0.0.0" [dependencies] dep1 = {{ git = '{}' }} dep2 = {{ git = '{}' }} "#, dep1.url(), dep2.url() ), ) .file("src/main.rs", "fn main() { }"); let p = p.build(); let n_concurrent_builds = 5; let (tx, rx) = channel(); for _ in 0..n_concurrent_builds { let cmd = p .cargo("build") .build_command() .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn(); let tx = tx.clone(); thread::spawn(move || { let result = cmd.unwrap().wait_with_output().unwrap(); tx.send(result).unwrap() }); } for _ in 0..n_concurrent_builds { let result = rx.recv_timeout(slow_cpu_multiplier(30)).expect("Deadlock!"); execs().run_output(&result); } } cargo-0.86.0/tests/testsuite/config.rs000064400000000000000000001640701046102023000160300ustar 00000000000000//! Tests for config settings. use std::borrow::Borrow; use std::collections::{BTreeMap, HashMap}; use std::fs; use std::io; use std::os; use std::path::{Path, PathBuf}; use cargo::core::features::{GitFeatures, GitoxideFeatures}; use cargo::core::{PackageIdSpec, Shell}; use cargo::util::context::{ self, Definition, GlobalContext, JobsConfig, SslVersionConfig, StringList, }; use cargo::CargoResult; use cargo_test_support::compare::assert_e2e; use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::{paths, project, project_in_home, symlink_supported, t}; use cargo_util_schemas::manifest::TomlTrimPaths; use cargo_util_schemas::manifest::TomlTrimPathsValue; use cargo_util_schemas::manifest::{self as cargo_toml, TomlDebugInfo, VecStringOrBool as VSOB}; use serde::Deserialize; /// Helper for constructing a `GlobalContext` object. pub struct GlobalContextBuilder { env: HashMap, unstable: Vec, config_args: Vec, cwd: Option, root: Option, enable_nightly_features: bool, } impl GlobalContextBuilder { pub fn new() -> GlobalContextBuilder { GlobalContextBuilder { env: HashMap::new(), unstable: Vec::new(), config_args: Vec::new(), root: None, cwd: None, enable_nightly_features: false, } } /// Passes a `-Z` flag. pub fn unstable_flag(&mut self, s: impl Into) -> &mut Self { self.unstable.push(s.into()); self } /// Sets an environment variable. pub fn env(&mut self, key: impl Into, val: impl Into) -> &mut Self { self.env.insert(key.into(), val.into()); self } /// Unconditionally enable nightly features, even on stable channels. pub fn nightly_features_allowed(&mut self, allowed: bool) -> &mut Self { self.enable_nightly_features = allowed; self } /// Passes a `--config` flag. pub fn config_arg(&mut self, arg: impl Into) -> &mut Self { self.config_args.push(arg.into()); self } /// Sets the current working directory where config files will be loaded. /// /// Default is the root from [`GlobalContextBuilder::root`] or [`paths::root`]. pub fn cwd(&mut self, path: impl AsRef) -> &mut Self { let path = path.as_ref(); let cwd = self .root .as_ref() .map_or_else(|| paths::root().join(path), |r| r.join(path)); self.cwd = Some(cwd); self } /// Sets the test root directory. /// /// This generally should not be necessary. It is only useful if you want /// to create a [`GlobalContext`] from within a thread. Since Cargo's /// testsuite uses thread-local storage, this can be used to avoid accessing /// that thread-local storage. /// /// Default is [`paths::root`]. pub fn root(&mut self, path: impl Into) -> &mut Self { self.root = Some(path.into()); self } /// Creates the [`GlobalContext`]. pub fn build(&self) -> GlobalContext { self.build_err().unwrap() } /// Creates the [`GlobalContext`], returning a Result. pub fn build_err(&self) -> CargoResult { let root = self.root.clone().unwrap_or_else(|| paths::root()); let output = Box::new(fs::File::create(root.join("shell.out")).unwrap()); let shell = Shell::from_write(output); let cwd = self.cwd.clone().unwrap_or_else(|| root.clone()); let homedir = root.join("home").join(".cargo"); let mut gctx = GlobalContext::new(shell, cwd, homedir); gctx.nightly_features_allowed = self.enable_nightly_features || !self.unstable.is_empty(); gctx.set_env(self.env.clone()); gctx.set_search_stop_path(&root); gctx.configure( 0, false, None, false, false, false, &None, &self.unstable, &self.config_args, )?; Ok(gctx) } } fn new_gctx() -> GlobalContext { GlobalContextBuilder::new().build() } /// Read the output from Config. pub fn read_output(gctx: GlobalContext) -> String { drop(gctx); // Paranoid about flushing the file. let path = paths::root().join("shell.out"); fs::read_to_string(path).unwrap() } #[cargo_test] fn read_env_vars_for_config() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.0" build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" use std::env; fn main() { assert_eq!(env::var("NUM_JOBS").unwrap(), "100"); } "#, ) .build(); p.cargo("check").env("CARGO_BUILD_JOBS", "100").run(); } pub fn write_config_extless(config: &str) { write_config_at(paths::root().join(".cargo/config"), config); } pub fn write_config_at(path: impl AsRef, contents: &str) { let path = paths::root().join(path.as_ref()); fs::create_dir_all(path.parent().unwrap()).unwrap(); fs::write(path, contents).unwrap(); } pub fn write_config_toml(config: &str) { write_config_at(paths::root().join(".cargo/config.toml"), config); } #[cfg(unix)] fn symlink_file(target: &Path, link: &Path) -> io::Result<()> { os::unix::fs::symlink(target, link) } #[cfg(windows)] fn symlink_file(target: &Path, link: &Path) -> io::Result<()> { os::windows::fs::symlink_file(target, link) } fn make_config_symlink_to_config_toml_absolute() { let toml_path = paths::root().join(".cargo/config.toml"); let symlink_path = paths::root().join(".cargo/config"); t!(symlink_file(&toml_path, &symlink_path)); } fn make_config_symlink_to_config_toml_relative() { let symlink_path = paths::root().join(".cargo/config"); t!(symlink_file(Path::new("config.toml"), &symlink_path)); } fn rename_config_toml_to_config_replacing_with_symlink() { let root = paths::root(); t!(fs::rename( root.join(".cargo/config.toml"), root.join(".cargo/config") )); t!(symlink_file( Path::new("config"), &root.join(".cargo/config.toml") )); } #[track_caller] pub fn assert_error>(error: E, msgs: impl IntoData) { let causes = error .borrow() .chain() .enumerate() .map(|(i, e)| { if i == 0 { e.to_string() } else { format!("Caused by:\n {}", e) } }) .collect::>() .join("\n\n"); assert_e2e().eq(&causes, msgs); } #[cargo_test] fn get_config() { write_config_toml( "\ [S] f1 = 123 ", ); let gctx = new_gctx(); #[derive(Debug, Deserialize, Eq, PartialEq)] struct S { f1: Option, } let s: S = gctx.get("S").unwrap(); assert_eq!(s, S { f1: Some(123) }); let gctx = GlobalContextBuilder::new().env("CARGO_S_F1", "456").build(); let s: S = gctx.get("S").unwrap(); assert_eq!(s, S { f1: Some(456) }); } #[cfg(windows)] #[cargo_test] fn environment_variable_casing() { // Issue #11814: Environment variable names are case-insensitive on Windows. let gctx = GlobalContextBuilder::new() .env("Path", "abc") .env("Two-Words", "abc") .env("two_words", "def") .build(); let var = gctx.get_env("PATH").unwrap(); assert_eq!(var, String::from("abc")); let var = gctx.get_env("path").unwrap(); assert_eq!(var, String::from("abc")); let var = gctx.get_env("TWO-WORDS").unwrap(); assert_eq!(var, String::from("abc")); // Make sure that we can still distinguish between dashes and underscores // in variable names. let var = gctx.get_env("Two_Words").unwrap(); assert_eq!(var, String::from("def")); } #[cargo_test] fn config_works_without_extension() { write_config_extless( "\ [foo] f1 = 1 ", ); let gctx = new_gctx(); assert_eq!(gctx.get::>("foo.f1").unwrap(), Some(1)); // It should NOT have warned for the symlink. let output = read_output(gctx); let expected = str![[r#" [WARNING] `[ROOT]/.cargo/config` is deprecated in favor of `config.toml` [NOTE] if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml` "#]]; assert_e2e().eq(&output, expected); } #[cargo_test] fn home_config_works_without_extension() { write_config_at( paths::cargo_home().join("config"), "\ [foo] f1 = 1 ", ); let p = project_in_home("foo").file("src/lib.rs", "").build(); p.cargo("-vV") .with_stderr_data(str![[r#" [WARNING] `[ROOT]/home/.cargo/config` is deprecated in favor of `config.toml` [NOTE] if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml` "#]]) .run(); } #[cargo_test] fn config_ambiguous_filename_symlink_doesnt_warn() { // Windows requires special permissions to create symlinks. // If we don't have permission, just skip this test. if !symlink_supported() { return; }; write_config_toml( "\ [foo] f1 = 1 ", ); make_config_symlink_to_config_toml_absolute(); let gctx = new_gctx(); assert_eq!(gctx.get::>("foo.f1").unwrap(), Some(1)); // It should NOT have warned for the symlink. let output = read_output(gctx); assert_e2e().eq(&output, str![[""]]); } #[cargo_test] fn config_ambiguous_filename_symlink_doesnt_warn_relative() { // Windows requires special permissions to create symlinks. // If we don't have permission, just skip this test. if !symlink_supported() { return; }; write_config_toml( "\ [foo] f1 = 1 ", ); make_config_symlink_to_config_toml_relative(); let gctx = new_gctx(); assert_eq!(gctx.get::>("foo.f1").unwrap(), Some(1)); // It should NOT have warned for the symlink. let output = read_output(gctx); assert_e2e().eq(&output, str![[""]]); } #[cargo_test] fn config_ambiguous_filename_symlink_doesnt_warn_backward() { // Windows requires special permissions to create symlinks. // If we don't have permission, just skip this test. if !symlink_supported() { return; }; write_config_toml( "\ [foo] f1 = 1 ", ); rename_config_toml_to_config_replacing_with_symlink(); let gctx = new_gctx(); assert_eq!(gctx.get::>("foo.f1").unwrap(), Some(1)); // It should NOT have warned for this situation. let output = read_output(gctx); assert_e2e().eq(&output, str![[""]]); } #[cargo_test] fn config_ambiguous_filename() { write_config_extless( "\ [foo] f1 = 1 ", ); write_config_toml( "\ [foo] f1 = 2 ", ); let gctx = new_gctx(); // It should use the value from the one without the extension for // backwards compatibility. assert_eq!(gctx.get::>("foo.f1").unwrap(), Some(1)); // But it also should have warned. let output = read_output(gctx); let expected = str![[r#" [WARNING] both `[ROOT]/.cargo/config` and `[ROOT]/.cargo/config.toml` exist. Using `[ROOT]/.cargo/config` "#]]; assert_e2e().eq(&output, expected); } #[cargo_test] fn config_unused_fields() { write_config_toml( "\ [S] unused = 456 ", ); let gctx = GlobalContextBuilder::new() .env("CARGO_S_UNUSED2", "1") .env("CARGO_S2_UNUSED", "2") .build(); #[derive(Debug, Deserialize, Eq, PartialEq)] struct S { f1: Option, } // This prints a warning (verified below). let s: S = gctx.get("S").unwrap(); assert_eq!(s, S { f1: None }); // This does not print anything, we cannot easily/reliably warn for // environment variables. let s: S = gctx.get("S2").unwrap(); assert_eq!(s, S { f1: None }); // Verify the warnings. let output = read_output(gctx); let expected = str![[r#" [WARNING] unused config key `S.unused` in `[ROOT]/.cargo/config.toml` "#]]; assert_e2e().eq(&output, expected); } #[cargo_test] fn config_load_toml_profile() { write_config_toml( "\ [profile.dev] opt-level = 's' lto = true codegen-units=4 debug = true debug-assertions = true rpath = true panic = 'abort' overflow-checks = true incremental = true [profile.dev.build-override] opt-level = 1 [profile.dev.package.bar] codegen-units = 9 [profile.no-lto] inherits = 'dev' dir-name = 'without-lto' lto = false ", ); let gctx = GlobalContextBuilder::new() .unstable_flag("advanced-env") .env("CARGO_PROFILE_DEV_CODEGEN_UNITS", "5") .env("CARGO_PROFILE_DEV_BUILD_OVERRIDE_CODEGEN_UNITS", "11") .env("CARGO_PROFILE_DEV_PACKAGE_env_CODEGEN_UNITS", "13") .env("CARGO_PROFILE_DEV_PACKAGE_bar_OPT_LEVEL", "2") .build(); // TODO: don't use actual `tomlprofile`. let p: cargo_toml::TomlProfile = gctx.get("profile.dev").unwrap(); let mut packages = BTreeMap::new(); let key = cargo_toml::ProfilePackageSpec::Spec(::cargo::core::PackageIdSpec::parse("bar").unwrap()); let o_profile = cargo_toml::TomlProfile { opt_level: Some(cargo_toml::TomlOptLevel("2".to_string())), codegen_units: Some(9), ..Default::default() }; packages.insert(key, o_profile); let key = cargo_toml::ProfilePackageSpec::Spec(::cargo::core::PackageIdSpec::parse("env").unwrap()); let o_profile = cargo_toml::TomlProfile { codegen_units: Some(13), ..Default::default() }; packages.insert(key, o_profile); assert_eq!( p, cargo_toml::TomlProfile { opt_level: Some(cargo_toml::TomlOptLevel("s".to_string())), lto: Some(cargo_toml::StringOrBool::Bool(true)), codegen_units: Some(5), debug: Some(cargo_toml::TomlDebugInfo::Full), debug_assertions: Some(true), rpath: Some(true), panic: Some("abort".to_string()), overflow_checks: Some(true), incremental: Some(true), package: Some(packages), build_override: Some(Box::new(cargo_toml::TomlProfile { opt_level: Some(cargo_toml::TomlOptLevel("1".to_string())), codegen_units: Some(11), ..Default::default() })), ..Default::default() } ); let p: cargo_toml::TomlProfile = gctx.get("profile.no-lto").unwrap(); assert_eq!( p, cargo_toml::TomlProfile { lto: Some(cargo_toml::StringOrBool::Bool(false)), dir_name: Some(String::from("without-lto")), inherits: Some(String::from("dev")), ..Default::default() } ); } #[cargo_test] fn profile_env_var_prefix() { // Check for a bug with collision on DEBUG vs DEBUG_ASSERTIONS. let gctx = GlobalContextBuilder::new() .env("CARGO_PROFILE_DEV_DEBUG_ASSERTIONS", "false") .build(); let p: cargo_toml::TomlProfile = gctx.get("profile.dev").unwrap(); assert_eq!(p.debug_assertions, Some(false)); assert_eq!(p.debug, None); let gctx = GlobalContextBuilder::new() .env("CARGO_PROFILE_DEV_DEBUG", "1") .build(); let p: cargo_toml::TomlProfile = gctx.get("profile.dev").unwrap(); assert_eq!(p.debug_assertions, None); assert_eq!(p.debug, Some(cargo_toml::TomlDebugInfo::Limited)); let gctx = GlobalContextBuilder::new() .env("CARGO_PROFILE_DEV_DEBUG_ASSERTIONS", "false") .env("CARGO_PROFILE_DEV_DEBUG", "1") .build(); let p: cargo_toml::TomlProfile = gctx.get("profile.dev").unwrap(); assert_eq!(p.debug_assertions, Some(false)); assert_eq!(p.debug, Some(cargo_toml::TomlDebugInfo::Limited)); } #[cargo_test] fn config_deserialize_any() { // Some tests to exercise deserialize_any for deserializers that need to // be told the format. write_config_toml( "\ a = true b = ['b'] c = ['c'] ", ); // advanced-env let gctx = GlobalContextBuilder::new() .unstable_flag("advanced-env") .env("CARGO_ENVB", "false") .env("CARGO_C", "['d']") .env("CARGO_ENVL", "['a', 'b']") .build(); assert_eq!(gctx.get::("a").unwrap(), VSOB::Bool(true)); assert_eq!( gctx.get::("b").unwrap(), VSOB::VecString(vec!["b".to_string()]) ); assert_eq!( gctx.get::("c").unwrap(), VSOB::VecString(vec!["c".to_string(), "d".to_string()]) ); assert_eq!(gctx.get::("envb").unwrap(), VSOB::Bool(false)); assert_eq!( gctx.get::("envl").unwrap(), VSOB::VecString(vec!["a".to_string(), "b".to_string()]) ); // Demonstrate where merging logic isn't very smart. This could be improved. let gctx = GlobalContextBuilder::new().env("CARGO_A", "x y").build(); assert_error( gctx.get::("a").unwrap_err(), "\ error in environment variable `CARGO_A`: could not load config key `a` Caused by: invalid type: string \"x y\", expected a boolean or vector of strings", ); // Normal env. let gctx = GlobalContextBuilder::new() .unstable_flag("advanced-env") .env("CARGO_B", "d e") .env("CARGO_C", "f g") .build(); assert_eq!( gctx.get::("b").unwrap(), VSOB::VecString(vec!["b".to_string(), "d".to_string(), "e".to_string()]) ); assert_eq!( gctx.get::("c").unwrap(), VSOB::VecString(vec!["c".to_string(), "f".to_string(), "g".to_string()]) ); // config-cli // This test demonstrates that ConfigValue::merge isn't very smart. // It would be nice if it was smarter. let gctx = GlobalContextBuilder::new() .config_arg("a = ['a']") .build_err(); assert_error( gctx.unwrap_err(), "\ failed to merge --config key `a` into `[..]/.cargo/config.toml` Caused by: failed to merge config value from `--config cli option` into `[..]/.cargo/config.toml`: \ expected boolean, but found array", ); // config-cli and advanced-env let gctx = GlobalContextBuilder::new() .unstable_flag("advanced-env") .config_arg("b=['clib']") .config_arg("c=['clic']") .env("CARGO_B", "env1 env2") .env("CARGO_C", "['e1', 'e2']") .build(); assert_eq!( gctx.get::("b").unwrap(), VSOB::VecString(vec![ "b".to_string(), "env1".to_string(), "env2".to_string(), "clib".to_string(), ]) ); assert_eq!( gctx.get::("c").unwrap(), VSOB::VecString(vec![ "c".to_string(), "e1".to_string(), "e2".to_string(), "clic".to_string(), ]) ); } #[cargo_test] fn config_toml_errors() { write_config_toml( "\ [profile.dev] opt-level = 'foo' ", ); let gctx = new_gctx(); assert_error( gctx.get::("profile.dev") .unwrap_err(), "\ error in [..]/.cargo/config.toml: could not load config key `profile.dev.opt-level` Caused by: must be `0`, `1`, `2`, `3`, `s` or `z`, but found the string: \"foo\"", ); let gctx = GlobalContextBuilder::new() .env("CARGO_PROFILE_DEV_OPT_LEVEL", "asdf") .build(); assert_error( gctx.get::("profile.dev").unwrap_err(), "\ error in environment variable `CARGO_PROFILE_DEV_OPT_LEVEL`: could not load config key `profile.dev.opt-level` Caused by: must be `0`, `1`, `2`, `3`, `s` or `z`, but found the string: \"asdf\"", ); } #[cargo_test] fn load_nested() { write_config_toml( "\ [nest.foo] f1 = 1 f2 = 2 [nest.bar] asdf = 3 ", ); let gctx = GlobalContextBuilder::new() .unstable_flag("advanced-env") .env("CARGO_NEST_foo_f2", "3") .env("CARGO_NESTE_foo_f1", "1") .env("CARGO_NESTE_foo_f2", "3") .env("CARGO_NESTE_bar_asdf", "3") .build(); type Nested = HashMap>; let n: Nested = gctx.get("nest").unwrap(); let mut expected = HashMap::new(); let mut foo = HashMap::new(); foo.insert("f1".to_string(), 1); foo.insert("f2".to_string(), 3); expected.insert("foo".to_string(), foo); let mut bar = HashMap::new(); bar.insert("asdf".to_string(), 3); expected.insert("bar".to_string(), bar); assert_eq!(n, expected); let n: Nested = gctx.get("neste").unwrap(); assert_eq!(n, expected); } #[cargo_test] fn get_errors() { write_config_toml( "\ [S] f1 = 123 f2 = 'asdf' big = 123456789 ", ); let gctx = GlobalContextBuilder::new() .env("CARGO_E_S", "asdf") .env("CARGO_E_BIG", "123456789") .build(); assert_error( gctx.get::("foo").unwrap_err(), "missing config key `foo`", ); assert_error( gctx.get::("foo.bar").unwrap_err(), "missing config key `foo.bar`", ); assert_error( gctx.get::("S.f2").unwrap_err(), "error in [..]/.cargo/config.toml: `S.f2` expected an integer, but found a string", ); assert_error( gctx.get::("S.big").unwrap_err(), "\ error in [..].cargo/config.toml: could not load config key `S.big` Caused by: invalid value: integer `123456789`, expected u8", ); // Environment variable type errors. assert_error( gctx.get::("e.s").unwrap_err(), "error in environment variable `CARGO_E_S`: invalid digit found in string", ); assert_error( gctx.get::("e.big").unwrap_err(), "\ error in environment variable `CARGO_E_BIG`: could not load config key `e.big` Caused by: invalid value: integer `123456789`, expected i8", ); #[derive(Debug, Deserialize)] #[allow(dead_code)] struct S { f1: i64, f2: String, f3: i64, big: i64, } assert_error(gctx.get::("S").unwrap_err(), "missing field `f3`"); } #[cargo_test] fn config_get_option() { write_config_toml( "\ [foo] f1 = 1 ", ); let gctx = GlobalContextBuilder::new() .env("CARGO_BAR_ASDF", "3") .build(); assert_eq!(gctx.get::>("a").unwrap(), None); assert_eq!(gctx.get::>("a.b").unwrap(), None); assert_eq!(gctx.get::>("foo.f1").unwrap(), Some(1)); assert_eq!(gctx.get::>("bar.asdf").unwrap(), Some(3)); assert_eq!(gctx.get::>("bar.zzzz").unwrap(), None); } #[cargo_test] fn config_bad_toml() { write_config_toml("asdf"); let gctx = new_gctx(); assert_error( gctx.get::("foo").unwrap_err(), "\ could not load Cargo configuration Caused by: could not parse TOML configuration in `[..]/.cargo/config.toml` Caused by: TOML parse error at line 1, column 5 | 1 | asdf | ^ expected `.`, `=` ", ); } #[cargo_test] fn config_get_list() { write_config_toml( "\ l1 = [] l2 = ['one', 'two'] l3 = 123 l4 = ['one', 'two'] [nested] l = ['x'] [nested2] l = ['y'] [nested-empty] ", ); type L = Vec; let gctx = GlobalContextBuilder::new() .unstable_flag("advanced-env") .env("CARGO_L4", "['three', 'four']") .env("CARGO_L5", "['a']") .env("CARGO_ENV_EMPTY", "[]") .env("CARGO_ENV_BLANK", "") .env("CARGO_ENV_NUM", "1") .env("CARGO_ENV_NUM_LIST", "[1]") .env("CARGO_ENV_TEXT", "asdf") .env("CARGO_LEPAIR", "['a', 'b']") .env("CARGO_NESTED2_L", "['z']") .env("CARGO_NESTEDE_L", "['env']") .env("CARGO_BAD_ENV", "[zzz]") .build(); assert_eq!(gctx.get::("unset").unwrap(), vec![] as Vec); assert_eq!(gctx.get::("l1").unwrap(), vec![] as Vec); assert_eq!(gctx.get::("l2").unwrap(), vec!["one", "two"]); assert_error( gctx.get::("l3").unwrap_err(), "\ invalid configuration for key `l3` expected a list, but found a integer for `l3` in [..]/.cargo/config.toml", ); assert_eq!( gctx.get::("l4").unwrap(), vec!["one", "two", "three", "four"] ); assert_eq!(gctx.get::("l5").unwrap(), vec!["a"]); assert_eq!(gctx.get::("env-empty").unwrap(), vec![] as Vec); assert_eq!(gctx.get::("env-blank").unwrap(), vec![] as Vec); assert_eq!(gctx.get::("env-num").unwrap(), vec!["1".to_string()]); assert_error( gctx.get::("env-num-list").unwrap_err(), "error in environment variable `CARGO_ENV_NUM_LIST`: \ expected string, found integer", ); assert_eq!(gctx.get::("env-text").unwrap(), vec!["asdf".to_string()]); // "invalid number" here isn't the best error, but I think it's just toml.rs. assert_error( gctx.get::("bad-env").unwrap_err(), "\ error in environment variable `CARGO_BAD_ENV`: could not parse TOML list: TOML parse error at line 1, column 2 | 1 | [zzz] | ^ invalid array expected `]` ", ); // Try some other sequence-like types. assert_eq!( gctx.get::<(String, String, String, String)>("l4").unwrap(), ( "one".to_string(), "two".to_string(), "three".to_string(), "four".to_string() ) ); assert_eq!(gctx.get::<(String,)>("l5").unwrap(), ("a".to_string(),)); // Tuple struct #[derive(Debug, Deserialize, Eq, PartialEq)] struct TupS(String, String); assert_eq!( gctx.get::("lepair").unwrap(), TupS("a".to_string(), "b".to_string()) ); // Nested with an option. #[derive(Debug, Deserialize, Eq, PartialEq)] struct S { l: Option>, } assert_eq!(gctx.get::("nested-empty").unwrap(), S { l: None }); assert_eq!( gctx.get::("nested").unwrap(), S { l: Some(vec!["x".to_string()]), } ); assert_eq!( gctx.get::("nested2").unwrap(), S { l: Some(vec!["y".to_string(), "z".to_string()]), } ); assert_eq!( gctx.get::("nestede").unwrap(), S { l: Some(vec!["env".to_string()]), } ); } #[cargo_test] fn config_get_other_types() { write_config_toml( "\ ns = 123 ns2 = 456 ", ); let gctx = GlobalContextBuilder::new() .env("CARGO_NSE", "987") .env("CARGO_NS2", "654") .build(); #[derive(Debug, Deserialize, Eq, PartialEq)] #[serde(transparent)] struct NewS(i32); assert_eq!(gctx.get::("ns").unwrap(), NewS(123)); assert_eq!(gctx.get::("ns2").unwrap(), NewS(654)); assert_eq!(gctx.get::("nse").unwrap(), NewS(987)); assert_error( gctx.get::("unset").unwrap_err(), "missing config key `unset`", ); } #[cargo_test] fn config_relative_path() { write_config_toml(&format!( "\ p1 = 'foo/bar' p2 = '../abc' p3 = 'b/c' abs = '{}' ", paths::home().display(), )); let gctx = GlobalContextBuilder::new() .env("CARGO_EPATH", "a/b") .env("CARGO_P3", "d/e") .build(); assert_eq!( gctx.get::("p1") .unwrap() .resolve_path(&gctx), paths::root().join("foo/bar") ); assert_eq!( gctx.get::("p2") .unwrap() .resolve_path(&gctx), paths::root().join("../abc") ); assert_eq!( gctx.get::("p3") .unwrap() .resolve_path(&gctx), paths::root().join("d/e") ); assert_eq!( gctx.get::("abs") .unwrap() .resolve_path(&gctx), paths::home() ); assert_eq!( gctx.get::("epath") .unwrap() .resolve_path(&gctx), paths::root().join("a/b") ); } #[cargo_test] fn config_get_integers() { write_config_toml( "\ npos = 123456789 nneg = -123456789 i64max = 9223372036854775807 ", ); let gctx = GlobalContextBuilder::new() .env("CARGO_EPOS", "123456789") .env("CARGO_ENEG", "-1") .env("CARGO_EI64MAX", "9223372036854775807") .build(); assert_eq!( gctx.get::("i64max").unwrap(), 9_223_372_036_854_775_807 ); assert_eq!( gctx.get::("i64max").unwrap(), 9_223_372_036_854_775_807 ); assert_eq!( gctx.get::("ei64max").unwrap(), 9_223_372_036_854_775_807 ); assert_eq!( gctx.get::("ei64max").unwrap(), 9_223_372_036_854_775_807 ); assert_error( gctx.get::("nneg").unwrap_err(), "\ error in [..].cargo/config.toml: could not load config key `nneg` Caused by: invalid value: integer `-123456789`, expected u32", ); assert_error( gctx.get::("eneg").unwrap_err(), "\ error in environment variable `CARGO_ENEG`: could not load config key `eneg` Caused by: invalid value: integer `-1`, expected u32", ); assert_error( gctx.get::("npos").unwrap_err(), "\ error in [..].cargo/config.toml: could not load config key `npos` Caused by: invalid value: integer `123456789`, expected i8", ); assert_error( gctx.get::("epos").unwrap_err(), "\ error in environment variable `CARGO_EPOS`: could not load config key `epos` Caused by: invalid value: integer `123456789`, expected i8", ); } #[cargo_test] fn config_get_ssl_version_missing() { write_config_toml( "\ [http] hello = 'world' ", ); let gctx = new_gctx(); assert!(gctx .get::>("http.ssl-version") .unwrap() .is_none()); } #[cargo_test] fn config_get_ssl_version_single() { write_config_toml( "\ [http] ssl-version = 'tlsv1.2' ", ); let gctx = new_gctx(); let a = gctx .get::>("http.ssl-version") .unwrap() .unwrap(); match a { SslVersionConfig::Single(v) => assert_eq!(&v, "tlsv1.2"), SslVersionConfig::Range(_) => panic!("Did not expect ssl version min/max."), }; } #[cargo_test] fn config_get_ssl_version_min_max() { write_config_toml( "\ [http] ssl-version.min = 'tlsv1.2' ssl-version.max = 'tlsv1.3' ", ); let gctx = new_gctx(); let a = gctx .get::>("http.ssl-version") .unwrap() .unwrap(); match a { SslVersionConfig::Single(_) => panic!("Did not expect exact ssl version."), SslVersionConfig::Range(range) => { assert_eq!(range.min, Some(String::from("tlsv1.2"))); assert_eq!(range.max, Some(String::from("tlsv1.3"))); } }; } #[cargo_test] fn config_get_ssl_version_both_forms_configured() { // this is not allowed write_config_toml( "\ [http] ssl-version = 'tlsv1.1' ssl-version.min = 'tlsv1.2' ssl-version.max = 'tlsv1.3' ", ); let gctx = new_gctx(); assert_error( gctx.get::("http.ssl-version") .unwrap_err(), "\ could not load Cargo configuration Caused by: could not parse TOML configuration in `[..]/.cargo/config.toml` Caused by: TOML parse error at line 3, column 1 | 3 | ssl-version.min = 'tlsv1.2' | ^ dotted key `ssl-version` attempted to extend non-table type (string) ", ); } #[cargo_test] /// Assert that unstable options can be configured with the `unstable` table in /// cargo config files fn unstable_table_notation() { write_config_toml( "\ [unstable] print-im-a-teapot = true ", ); let gctx = GlobalContextBuilder::new() .nightly_features_allowed(true) .build(); assert_eq!(gctx.cli_unstable().print_im_a_teapot, true); } #[cargo_test] /// Assert that dotted notation works for configuring unstable options fn unstable_dotted_notation() { write_config_toml( "\ unstable.print-im-a-teapot = true ", ); let gctx = GlobalContextBuilder::new() .nightly_features_allowed(true) .build(); assert_eq!(gctx.cli_unstable().print_im_a_teapot, true); } #[cargo_test] /// Assert that Zflags on the CLI take precedence over those from config fn unstable_cli_precedence() { write_config_toml( "\ unstable.print-im-a-teapot = true ", ); let gctx = GlobalContextBuilder::new() .nightly_features_allowed(true) .build(); assert_eq!(gctx.cli_unstable().print_im_a_teapot, true); let gctx = GlobalContextBuilder::new() .unstable_flag("print-im-a-teapot=no") .build(); assert_eq!(gctx.cli_unstable().print_im_a_teapot, false); } #[cargo_test] /// Assert that attempting to set an unstable flag that doesn't exist via config /// is ignored on stable fn unstable_invalid_flag_ignored_on_stable() { write_config_toml( "\ unstable.an-invalid-flag = 'yes' ", ); assert!(GlobalContextBuilder::new().build_err().is_ok()); } #[cargo_test] /// Assert that unstable options can be configured with the `unstable` table in /// cargo config files fn unstable_flags_ignored_on_stable() { write_config_toml( "\ [unstable] print-im-a-teapot = true ", ); // Enforce stable channel even when testing on nightly. let gctx = GlobalContextBuilder::new() .nightly_features_allowed(false) .build(); assert_eq!(gctx.cli_unstable().print_im_a_teapot, false); } #[cargo_test] fn table_merge_failure() { // Config::merge fails to merge entries in two tables. write_config_at( "foo/.cargo/config.toml", " [table] key = ['foo'] ", ); write_config_at( ".cargo/config.toml", " [table] key = 'bar' ", ); #[derive(Debug, Deserialize)] #[allow(dead_code)] struct Table { key: StringList, } let gctx = GlobalContextBuilder::new().cwd("foo").build(); assert_error( gctx.get::("table").unwrap_err(), "\ could not load Cargo configuration Caused by: failed to merge configuration at `[..]/.cargo/config.toml` Caused by: failed to merge key `table` between [..]/foo/.cargo/config.toml and [..]/.cargo/config.toml Caused by: failed to merge key `key` between [..]/foo/.cargo/config.toml and [..]/.cargo/config.toml Caused by: failed to merge config value from `[..]/.cargo/config.toml` into `[..]/foo/.cargo/config.toml`: \ expected array, but found string", ); } #[cargo_test] fn non_string_in_array() { // Currently only strings are supported. write_config_toml("foo = [1, 2, 3]"); let gctx = new_gctx(); assert_error( gctx.get::>("foo").unwrap_err(), "\ could not load Cargo configuration Caused by: failed to load TOML configuration from `[..]/.cargo/config.toml` Caused by: failed to parse key `foo` Caused by: expected string but found integer in list", ); } #[cargo_test] fn struct_with_opt_inner_struct() { // Struct with a key that is Option of another struct. // Check that can be defined with environment variable. #[derive(Deserialize)] struct Inner { value: Option, } #[derive(Deserialize)] struct Foo { inner: Option, } let gctx = GlobalContextBuilder::new() .env("CARGO_FOO_INNER_VALUE", "12") .build(); let f: Foo = gctx.get("foo").unwrap(); assert_eq!(f.inner.unwrap().value.unwrap(), 12); } #[cargo_test] fn struct_with_default_inner_struct() { // Struct with serde defaults. // Check that can be defined with environment variable. #[derive(Deserialize, Default)] #[serde(default)] struct Inner { value: i32, } #[derive(Deserialize, Default)] #[serde(default)] struct Foo { inner: Inner, } let gctx = GlobalContextBuilder::new() .env("CARGO_FOO_INNER_VALUE", "12") .build(); let f: Foo = gctx.get("foo").unwrap(); assert_eq!(f.inner.value, 12); } #[cargo_test] fn overlapping_env_config() { // Issue where one key is a prefix of another. #[derive(Deserialize)] #[serde(rename_all = "kebab-case")] struct Ambig { debug: Option, debug_assertions: Option, } let gctx = GlobalContextBuilder::new() .env("CARGO_AMBIG_DEBUG_ASSERTIONS", "true") .build(); let s: Ambig = gctx.get("ambig").unwrap(); assert_eq!(s.debug_assertions, Some(true)); assert_eq!(s.debug, None); let gctx = GlobalContextBuilder::new() .env("CARGO_AMBIG_DEBUG", "0") .build(); let s: Ambig = gctx.get("ambig").unwrap(); assert_eq!(s.debug_assertions, None); assert_eq!(s.debug, Some(0)); let gctx = GlobalContextBuilder::new() .env("CARGO_AMBIG_DEBUG", "1") .env("CARGO_AMBIG_DEBUG_ASSERTIONS", "true") .build(); let s: Ambig = gctx.get("ambig").unwrap(); assert_eq!(s.debug_assertions, Some(true)); assert_eq!(s.debug, Some(1)); } #[cargo_test] fn overlapping_env_with_defaults_errors_out() { // Issue where one key is a prefix of another. // This is a limitation of mapping environment variables on to a hierarchy. // Check that we error out when we hit ambiguity in this way, rather than // the more-surprising defaulting through. // If, in the future, we can handle this more correctly, feel free to delete // this test. #[derive(Deserialize, Default)] #[serde(default, rename_all = "kebab-case")] struct Ambig { debug: u32, debug_assertions: bool, } let gctx = GlobalContextBuilder::new() .env("CARGO_AMBIG_DEBUG_ASSERTIONS", "true") .build(); let err = gctx.get::("ambig").err().unwrap(); assert!(format!("{}", err).contains("missing config key `ambig.debug`")); let gctx = GlobalContextBuilder::new() .env("CARGO_AMBIG_DEBUG", "5") .build(); let s: Ambig = gctx.get("ambig").unwrap(); assert_eq!(s.debug_assertions, bool::default()); assert_eq!(s.debug, 5); let gctx = GlobalContextBuilder::new() .env("CARGO_AMBIG_DEBUG", "1") .env("CARGO_AMBIG_DEBUG_ASSERTIONS", "true") .build(); let s: Ambig = gctx.get("ambig").unwrap(); assert_eq!(s.debug_assertions, true); assert_eq!(s.debug, 1); } #[cargo_test] fn struct_with_overlapping_inner_struct_and_defaults() { // Struct with serde defaults. // Check that can be defined with environment variable. #[derive(Deserialize, Default)] #[serde(default)] struct Inner { value: i32, } // Containing struct with a prefix of inner // // This is a limitation of mapping environment variables on to a hierarchy. // Check that we error out when we hit ambiguity in this way, rather than // the more-surprising defaulting through. // If, in the future, we can handle this more correctly, feel free to delete // this case. #[derive(Deserialize, Default)] struct PrefixContainer { inn: bool, inner: Inner, } let gctx = GlobalContextBuilder::new() .env("CARGO_PREFIXCONTAINER_INNER_VALUE", "12") .build(); let err = gctx .get::("prefixcontainer") .err() .unwrap(); assert!(format!("{}", err).contains("missing field `inn`")); let gctx = GlobalContextBuilder::new() .env("CARGO_PREFIXCONTAINER_INNER_VALUE", "12") .env("CARGO_PREFIXCONTAINER_INN", "true") .build(); let f: PrefixContainer = gctx.get("prefixcontainer").unwrap(); assert_eq!(f.inner.value, 12); assert_eq!(f.inn, true); // Use default attribute of serde, then we can skip setting the inn field #[derive(Deserialize, Default)] #[serde(default)] struct PrefixContainerFieldDefault { inn: bool, inner: Inner, } let gctx = GlobalContextBuilder::new() .env("CARGO_PREFIXCONTAINER_INNER_VALUE", "12") .build(); let f = gctx .get::("prefixcontainer") .unwrap(); assert_eq!(f.inner.value, 12); assert_eq!(f.inn, false); // Containing struct where the inner value's field is a prefix of another // // This is a limitation of mapping environment variables on to a hierarchy. // Check that we error out when we hit ambiguity in this way, rather than // the more-surprising defaulting through. // If, in the future, we can handle this more correctly, feel free to delete // this case. #[derive(Deserialize, Default)] #[serde(default)] struct InversePrefixContainer { inner_field: bool, inner: Inner, } let gctx = GlobalContextBuilder::new() .env("CARGO_INVERSEPREFIXCONTAINER_INNER_VALUE", "12") .build(); let f: InversePrefixContainer = gctx.get("inverseprefixcontainer").unwrap(); assert_eq!(f.inner_field, bool::default()); assert_eq!(f.inner.value, 12); } #[cargo_test] fn string_list_tricky_env() { // Make sure StringList handles typed env values. let gctx = GlobalContextBuilder::new() .env("CARGO_KEY1", "123") .env("CARGO_KEY2", "true") .env("CARGO_KEY3", "1 2") .build(); let x = gctx.get::("key1").unwrap(); assert_eq!(x.as_slice(), &["123".to_string()]); let x = gctx.get::("key2").unwrap(); assert_eq!(x.as_slice(), &["true".to_string()]); let x = gctx.get::("key3").unwrap(); assert_eq!(x.as_slice(), &["1".to_string(), "2".to_string()]); } #[cargo_test] fn string_list_wrong_type() { // What happens if StringList is given then wrong type. write_config_toml("some_list = 123"); let gctx = GlobalContextBuilder::new().build(); assert_error( gctx.get::("some_list").unwrap_err(), "\ invalid configuration for key `some_list` expected a string or array of strings, but found a integer for `some_list` in [..]/.cargo/config.toml", ); write_config_toml("some_list = \"1 2\""); let gctx = GlobalContextBuilder::new().build(); let x = gctx.get::("some_list").unwrap(); assert_eq!(x.as_slice(), &["1".to_string(), "2".to_string()]); } #[cargo_test] fn string_list_advanced_env() { // StringList with advanced env. let gctx = GlobalContextBuilder::new() .unstable_flag("advanced-env") .env("CARGO_KEY1", "[]") .env("CARGO_KEY2", "['1 2', '3']") .env("CARGO_KEY3", "[123]") .build(); let x = gctx.get::("key1").unwrap(); assert_eq!(x.as_slice(), &[] as &[String]); let x = gctx.get::("key2").unwrap(); assert_eq!(x.as_slice(), &["1 2".to_string(), "3".to_string()]); assert_error( gctx.get::("key3").unwrap_err(), "error in environment variable `CARGO_KEY3`: expected string, found integer", ); } #[cargo_test] fn parse_strip_with_string() { write_config_toml( "\ [profile.release] strip = 'debuginfo' ", ); let gctx = new_gctx(); let p: cargo_toml::TomlProfile = gctx.get("profile.release").unwrap(); let strip = p.strip.unwrap(); assert_eq!( strip, cargo_toml::StringOrBool::String("debuginfo".to_string()) ); } #[cargo_test] fn cargo_target_empty_cfg() { write_config_toml( "\ [build] target-dir = '' ", ); let gctx = new_gctx(); assert_error( gctx.target_dir().unwrap_err(), "the target directory is set to an empty string in [..]/.cargo/config.toml", ); } #[cargo_test] fn cargo_target_empty_env() { let project = project().build(); project.cargo("check") .env("CARGO_TARGET_DIR", "") .with_stderr_data(str![[r#" [ERROR] the target directory is set to an empty string in the `CARGO_TARGET_DIR` environment variable "#]]) .with_status(101) .run(); } #[cargo_test] fn all_profile_options() { // Check that all profile options can be serialized/deserialized. let base_settings = cargo_toml::TomlProfile { opt_level: Some(cargo_toml::TomlOptLevel("0".to_string())), lto: Some(cargo_toml::StringOrBool::String("thin".to_string())), codegen_backend: Some(String::from("example")), codegen_units: Some(123), debug: Some(cargo_toml::TomlDebugInfo::Limited), split_debuginfo: Some("packed".to_string()), debug_assertions: Some(true), rpath: Some(true), panic: Some("abort".to_string()), overflow_checks: Some(true), incremental: Some(true), dir_name: Some(String::from("dir_name")), inherits: Some(String::from("debug")), strip: Some(cargo_toml::StringOrBool::String("symbols".to_string())), package: None, build_override: None, rustflags: None, trim_paths: None, }; let mut overrides = BTreeMap::new(); let key = cargo_toml::ProfilePackageSpec::Spec(PackageIdSpec::parse("foo").unwrap()); overrides.insert(key, base_settings.clone()); let profile = cargo_toml::TomlProfile { build_override: Some(Box::new(base_settings.clone())), package: Some(overrides), ..base_settings }; let profile_toml = toml::to_string(&profile).unwrap(); let roundtrip: cargo_toml::TomlProfile = toml::from_str(&profile_toml).unwrap(); let roundtrip_toml = toml::to_string(&roundtrip).unwrap(); assert_e2e().eq(&roundtrip_toml, &profile_toml); } #[cargo_test] fn value_in_array() { // Value in an array should work let root_path = paths::root().join(".cargo/config.toml"); write_config_at( &root_path, "\ [net.ssh] known-hosts = [ \"example.com ...\", \"example.net ...\", ] ", ); let foo_path = paths::root().join("foo/.cargo/config.toml"); write_config_at( &foo_path, "\ [net.ssh] known-hosts = [ \"example.org ...\", ] ", ); let gctx = GlobalContextBuilder::new() .cwd("foo") // environment variables don't actually work for known-hosts due to // space splitting, but this is included here just to validate that // they work (particularly if other Vec config vars are added // in the future). .env("CARGO_NET_SSH_KNOWN_HOSTS", "env-example") .build(); let net_config = gctx.net_config().unwrap(); let kh = net_config .ssh .as_ref() .unwrap() .known_hosts .as_ref() .unwrap(); assert_eq!(kh.len(), 4); assert_eq!(kh[0].val, "example.com ..."); assert_eq!(kh[0].definition, Definition::Path(root_path.clone())); assert_eq!(kh[1].val, "example.net ..."); assert_eq!(kh[1].definition, Definition::Path(root_path.clone())); assert_eq!(kh[2].val, "example.org ..."); assert_eq!(kh[2].definition, Definition::Path(foo_path.clone())); assert_eq!(kh[3].val, "env-example"); assert_eq!( kh[3].definition, Definition::Environment("CARGO_NET_SSH_KNOWN_HOSTS".to_string()) ); } #[cargo_test] fn debuginfo_parsing() { let gctx = GlobalContextBuilder::new().build(); let p: cargo_toml::TomlProfile = gctx.get("profile.dev").unwrap(); assert_eq!(p.debug, None); let env_test_cases = [ (TomlDebugInfo::None, ["false", "0", "none"].as_slice()), (TomlDebugInfo::LineDirectivesOnly, &["line-directives-only"]), (TomlDebugInfo::LineTablesOnly, &["line-tables-only"]), (TomlDebugInfo::Limited, &["1", "limited"]), (TomlDebugInfo::Full, &["true", "2", "full"]), ]; for (expected, config_strs) in env_test_cases { for &val in config_strs { let gctx = GlobalContextBuilder::new() .env("CARGO_PROFILE_DEV_DEBUG", val) .build(); let debug: TomlDebugInfo = gctx.get("profile.dev.debug").unwrap(); assert_eq!(debug, expected, "failed to parse {val}"); } } let toml_test_cases = [ (TomlDebugInfo::None, ["false", "0", "\"none\""].as_slice()), ( TomlDebugInfo::LineDirectivesOnly, &["\"line-directives-only\""], ), (TomlDebugInfo::LineTablesOnly, &["\"line-tables-only\""]), (TomlDebugInfo::Limited, &["1", "\"limited\""]), (TomlDebugInfo::Full, &["true", "2", "\"full\""]), ]; for (expected, config_strs) in toml_test_cases { for &val in config_strs { let gctx = GlobalContextBuilder::new() .config_arg(format!("profile.dev.debug={val}")) .build(); let debug: TomlDebugInfo = gctx.get("profile.dev.debug").unwrap(); assert_eq!(debug, expected, "failed to parse {val}"); } } let toml_err_cases = ["\"\"", "\"unrecognized\"", "3"]; for err_val in toml_err_cases { let gctx = GlobalContextBuilder::new() .config_arg(format!("profile.dev.debug={err_val}")) .build(); let err = gctx.get::("profile.dev.debug").unwrap_err(); assert!(err .to_string() .ends_with("could not load config key `profile.dev.debug`")); } } #[cargo_test] fn build_jobs_missing() { write_config_toml( "\ [build] ", ); let gctx = new_gctx(); assert!(gctx .get::>("build.jobs") .unwrap() .is_none()); } #[cargo_test] fn build_jobs_default() { write_config_toml( "\ [build] jobs = \"default\" ", ); let gctx = new_gctx(); let a = gctx .get::>("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_toml( "\ [build] jobs = 2 ", ); let gctx = new_gctx(); let a = gctx .get::>("build.jobs") .unwrap() .unwrap(); match a { JobsConfig::String(_) => panic!("Did not except an integer."), JobsConfig::Integer(v) => assert_eq!(v, 2), } } #[cargo_test] fn trim_paths_parsing() { let gctx = GlobalContextBuilder::new().build(); let p: cargo_toml::TomlProfile = gctx.get("profile.dev").unwrap(); assert_eq!(p.trim_paths, None); let test_cases = [ (TomlTrimPathsValue::Diagnostics.into(), "diagnostics"), (TomlTrimPathsValue::Macro.into(), "macro"), (TomlTrimPathsValue::Object.into(), "object"), ]; for (expected, val) in test_cases { // env let gctx = GlobalContextBuilder::new() .env("CARGO_PROFILE_DEV_TRIM_PATHS", val) .build(); let trim_paths: TomlTrimPaths = gctx.get("profile.dev.trim-paths").unwrap(); assert_eq!(trim_paths, expected, "failed to parse {val}"); // config.toml let gctx = GlobalContextBuilder::new() .config_arg(format!("profile.dev.trim-paths='{val}'")) .build(); let trim_paths: TomlTrimPaths = gctx.get("profile.dev.trim-paths").unwrap(); assert_eq!(trim_paths, expected, "failed to parse {val}"); } let test_cases = [(TomlTrimPaths::none(), false), (TomlTrimPaths::All, true)]; for (expected, val) in test_cases { // env let gctx = GlobalContextBuilder::new() .env("CARGO_PROFILE_DEV_TRIM_PATHS", format!("{val}")) .build(); let trim_paths: TomlTrimPaths = gctx.get("profile.dev.trim-paths").unwrap(); assert_eq!(trim_paths, expected, "failed to parse {val}"); // config.toml let gctx = GlobalContextBuilder::new() .config_arg(format!("profile.dev.trim-paths={val}")) .build(); let trim_paths: TomlTrimPaths = gctx.get("profile.dev.trim-paths").unwrap(); assert_eq!(trim_paths, expected, "failed to parse {val}"); } let expected = vec![ TomlTrimPathsValue::Diagnostics, TomlTrimPathsValue::Macro, TomlTrimPathsValue::Object, ] .into(); let val = r#"["diagnostics", "macro", "object"]"#; // config.toml let gctx = GlobalContextBuilder::new() .config_arg(format!("profile.dev.trim-paths={val}")) .build(); let trim_paths: TomlTrimPaths = gctx.get("profile.dev.trim-paths").unwrap(); assert_eq!(trim_paths, expected, "failed to parse {val}"); } #[cargo_test] fn missing_fields() { #[derive(Deserialize, Default, Debug)] struct Foo { bar: Bar, } #[derive(Deserialize, Default, Debug)] struct Bar { bax: bool, baz: bool, } let gctx = GlobalContextBuilder::new() .env("CARGO_FOO_BAR_BAZ", "true") .build(); assert_error( gctx.get::("foo").unwrap_err(), "\ could not load config key `foo.bar` Caused by: missing field `bax`", ); let gctx: GlobalContext = GlobalContextBuilder::new() .env("CARGO_FOO_BAR_BAZ", "true") .env("CARGO_FOO_BAR_BAX", "true") .build(); let foo = gctx.get::("foo").unwrap(); assert_eq!(foo.bar.bax, true); assert_eq!(foo.bar.baz, true); let gctx: GlobalContext = GlobalContextBuilder::new() .config_arg("foo.bar.baz=true") .build(); assert_error( gctx.get::("foo").unwrap_err(), "\ error in --config cli option: could not load config key `foo.bar` Caused by: missing field `bax`", ); } #[cargo_test] fn git_features() { let gctx = GlobalContextBuilder::new() .env("CARGO_UNSTABLE_GIT", "shallow-index") .build(); assert!(do_check( gctx, Some(GitFeatures { shallow_index: true, ..GitFeatures::default() }), )); let gctx = GlobalContextBuilder::new() .env("CARGO_UNSTABLE_GIT", "shallow-index,abc") .build(); assert_error( gctx.get::>("unstable") .unwrap_err(), "\ error in environment variable `CARGO_UNSTABLE_GIT`: could not load config key `unstable.git` Caused by: [..]unstable 'git' only takes [..] as valid inputs", ); let gctx = GlobalContextBuilder::new() .env("CARGO_UNSTABLE_GIT", "shallow-deps") .build(); assert!(do_check( gctx, Some(GitFeatures { shallow_index: false, shallow_deps: true, }), )); let gctx = GlobalContextBuilder::new() .env("CARGO_UNSTABLE_GIT", "true") .build(); assert!(do_check(gctx, Some(GitFeatures::all()))); let gctx = GlobalContextBuilder::new() .env("CARGO_UNSTABLE_GIT_SHALLOW_INDEX", "true") .build(); assert!(do_check( gctx, Some(GitFeatures { shallow_index: true, ..Default::default() }), )); let gctx = GlobalContextBuilder::new() .env("CARGO_UNSTABLE_GIT_SHALLOW_INDEX", "true") .env("CARGO_UNSTABLE_GIT_SHALLOW_DEPS", "true") .build(); assert!(do_check( gctx, Some(GitFeatures { shallow_index: true, shallow_deps: true, ..Default::default() }), )); write_config_toml( "\ [unstable] git = 'shallow-index' ", ); let gctx = GlobalContextBuilder::new().build(); assert!(do_check( gctx, Some(GitFeatures { shallow_index: true, shallow_deps: false, }), )); write_config_toml( "\ [unstable.git] shallow_deps = false shallow_index = true ", ); let gctx = GlobalContextBuilder::new().build(); assert!(do_check( gctx, Some(GitFeatures { shallow_index: true, shallow_deps: false, ..Default::default() }), )); write_config_toml( "\ [unstable.git] ", ); let gctx = GlobalContextBuilder::new().build(); assert!(do_check(gctx, Some(Default::default()))); fn do_check(gctx: GlobalContext, expect: Option) -> bool { let unstable_flags = gctx .get::>("unstable") .unwrap() .unwrap(); unstable_flags.git == expect } } #[cargo_test] fn gitoxide_features() { let gctx = GlobalContextBuilder::new() .env("CARGO_UNSTABLE_GITOXIDE", "fetch") .build(); assert!(do_check( gctx, Some(GitoxideFeatures { fetch: true, ..GitoxideFeatures::default() }), )); let gctx = GlobalContextBuilder::new() .env("CARGO_UNSTABLE_GITOXIDE", "fetch,abc") .build(); assert_error( gctx.get::>("unstable") .unwrap_err(), "\ error in environment variable `CARGO_UNSTABLE_GITOXIDE`: could not load config key `unstable.gitoxide` Caused by: [..]unstable 'gitoxide' only takes [..] as valid inputs, for shallow fetches see `-Zgit=shallow-index,shallow-deps`", ); let gctx = GlobalContextBuilder::new() .env("CARGO_UNSTABLE_GITOXIDE", "true") .build(); assert!(do_check(gctx, Some(GitoxideFeatures::all()))); let gctx = GlobalContextBuilder::new() .env("CARGO_UNSTABLE_GITOXIDE_FETCH", "true") .build(); assert!(do_check( gctx, Some(GitoxideFeatures { fetch: true, ..Default::default() }), )); write_config_toml( "\ [unstable] gitoxide = \"fetch\" ", ); let gctx = GlobalContextBuilder::new().build(); assert!(do_check( gctx, Some(GitoxideFeatures { fetch: true, ..GitoxideFeatures::default() }), )); write_config_toml( "\ [unstable.gitoxide] fetch = true checkout = false internal_use_git2 = false ", ); let gctx = GlobalContextBuilder::new().build(); assert!(do_check( gctx, Some(GitoxideFeatures { fetch: true, checkout: false, internal_use_git2: false, }), )); write_config_toml( "\ [unstable.gitoxide] ", ); let gctx = GlobalContextBuilder::new().build(); assert!(do_check(gctx, Some(Default::default()))); fn do_check(gctx: GlobalContext, expect: Option) -> bool { let unstable_flags = gctx .get::>("unstable") .unwrap() .unwrap(); unstable_flags.gitoxide == expect } } cargo-0.86.0/tests/testsuite/config_cli.rs000064400000000000000000000414751046102023000166620ustar 00000000000000//! Tests for the --config CLI option. use std::{collections::HashMap, fs}; use cargo::util::context::Definition; use cargo_test_support::compare::assert_e2e; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::str; use super::config::{ assert_error, read_output, write_config_at, write_config_toml, GlobalContextBuilder, }; #[cargo_test] fn basic() { // Simple example. let gctx = GlobalContextBuilder::new() .config_arg("foo='bar'") .config_arg("net.git-fetch-with-cli=true") .build(); assert_eq!(gctx.get::("foo").unwrap(), "bar"); assert_eq!(gctx.net_config().unwrap().git_fetch_with_cli, Some(true)); } #[cargo_test] fn cli_priority() { // Command line takes priority over files and env vars. write_config_toml( " demo_list = ['a'] [build] jobs = 3 rustc = 'file' [term] quiet = false verbose = false ", ); let gctx = GlobalContextBuilder::new().build(); assert_eq!(gctx.get::("build.jobs").unwrap(), 3); assert_eq!(gctx.get::("build.rustc").unwrap(), "file"); assert_eq!(gctx.get::("term.quiet").unwrap(), false); assert_eq!(gctx.get::("term.verbose").unwrap(), false); let gctx = GlobalContextBuilder::new() .env("CARGO_BUILD_JOBS", "2") .env("CARGO_BUILD_RUSTC", "env") .env("CARGO_TERM_VERBOSE", "false") .env("CARGO_NET_GIT_FETCH_WITH_CLI", "false") .config_arg("build.jobs=1") .config_arg("build.rustc='cli'") .config_arg("term.verbose=true") .config_arg("net.git-fetch-with-cli=true") .build(); assert_eq!(gctx.get::("build.jobs").unwrap(), 1); assert_eq!(gctx.get::("build.rustc").unwrap(), "cli"); assert_eq!(gctx.get::("term.verbose").unwrap(), true); assert_eq!(gctx.net_config().unwrap().git_fetch_with_cli, Some(true)); // Setting both term.verbose and term.quiet is invalid and is tested // in the run test suite. let gctx = GlobalContextBuilder::new() .env("CARGO_TERM_QUIET", "false") .config_arg("term.quiet=true") .build(); assert_eq!(gctx.get::("term.quiet").unwrap(), true); } #[cargo_test] fn merge_primitives_for_multiple_cli_occurrences() { let config_path0 = ".cargo/file0.toml"; write_config_at(config_path0, "k = 'file0'"); let config_path1 = ".cargo/file1.toml"; write_config_at(config_path1, "k = 'file1'"); // k=env0 let gctx = GlobalContextBuilder::new().env("CARGO_K", "env0").build(); assert_eq!(gctx.get::("k").unwrap(), "env0"); // k=env0 // --config k='cli0' // --config k='cli1' let gctx = GlobalContextBuilder::new() .env("CARGO_K", "env0") .config_arg("k='cli0'") .config_arg("k='cli1'") .build(); assert_eq!(gctx.get::("k").unwrap(), "cli1"); // Env has a lower priority when comparing with file from CLI arg. // // k=env0 // --config k='cli0' // --config k='cli1' // --config .cargo/file0.toml let gctx = GlobalContextBuilder::new() .env("CARGO_K", "env0") .config_arg("k='cli0'") .config_arg("k='cli1'") .config_arg(config_path0) .build(); assert_eq!(gctx.get::("k").unwrap(), "file0"); // k=env0 // --config k='cli0' // --config k='cli1' // --config .cargo/file0.toml // --config k='cli2' let gctx = GlobalContextBuilder::new() .env("CARGO_K", "env0") .config_arg("k='cli0'") .config_arg("k='cli1'") .config_arg(config_path0) .config_arg("k='cli2'") .build(); assert_eq!(gctx.get::("k").unwrap(), "cli2"); // k=env0 // --config k='cli0' // --config k='cli1' // --config .cargo/file0.toml // --config k='cli2' // --config .cargo/file1.toml let gctx = GlobalContextBuilder::new() .env("CARGO_K", "env0") .config_arg("k='cli0'") .config_arg("k='cli1'") .config_arg(config_path0) .config_arg("k='cli2'") .config_arg(config_path1) .build(); assert_eq!(gctx.get::("k").unwrap(), "file1"); } #[cargo_test] fn merges_array() { // Array entries are appended. write_config_toml( " [build] rustflags = ['--file'] ", ); let gctx = GlobalContextBuilder::new() .config_arg("build.rustflags = ['--cli']") .build(); assert_eq!( gctx.get::>("build.rustflags").unwrap(), ["--file", "--cli"] ); // With normal env. let gctx = GlobalContextBuilder::new() .env("CARGO_BUILD_RUSTFLAGS", "--env1 --env2") .config_arg("build.rustflags = ['--cli']") .build(); assert_eq!( gctx.get::>("build.rustflags").unwrap(), ["--file", "--env1", "--env2", "--cli"] ); // With advanced-env. let gctx = GlobalContextBuilder::new() .unstable_flag("advanced-env") .env("CARGO_BUILD_RUSTFLAGS", "--env") .config_arg("build.rustflags = ['--cli']") .build(); assert_eq!( gctx.get::>("build.rustflags").unwrap(), ["--file", "--env", "--cli"] ); // Merges multiple instances. let gctx = GlobalContextBuilder::new() .config_arg("build.rustflags=['--one']") .config_arg("build.rustflags=['--two']") .build(); assert_eq!( gctx.get::>("build.rustflags").unwrap(), ["--file", "--one", "--two"] ); } #[cargo_test] fn string_list_array() { // Using the StringList type. write_config_toml( " [build] rustflags = ['--file'] ", ); let gctx = GlobalContextBuilder::new() .config_arg("build.rustflags = ['--cli']") .build(); assert_eq!( gctx.get::("build.rustflags") .unwrap() .as_slice(), ["--file", "--cli"] ); // With normal env. let gctx = GlobalContextBuilder::new() .env("CARGO_BUILD_RUSTFLAGS", "--env1 --env2") .config_arg("build.rustflags = ['--cli']") .build(); assert_eq!( gctx.get::("build.rustflags") .unwrap() .as_slice(), ["--file", "--env1", "--env2", "--cli"] ); // With advanced-env. let gctx = GlobalContextBuilder::new() .unstable_flag("advanced-env") .env("CARGO_BUILD_RUSTFLAGS", "['--env']") .config_arg("build.rustflags = ['--cli']") .build(); assert_eq!( gctx.get::("build.rustflags") .unwrap() .as_slice(), ["--file", "--env", "--cli"] ); } #[cargo_test] fn merges_table() { // Tables are merged. write_config_toml( " [foo] key1 = 1 key2 = 2 key3 = 3 ", ); let gctx = GlobalContextBuilder::new() .config_arg("foo.key2 = 4") .config_arg("foo.key3 = 5") .config_arg("foo.key4 = 6") .build(); assert_eq!(gctx.get::("foo.key1").unwrap(), 1); assert_eq!(gctx.get::("foo.key2").unwrap(), 4); assert_eq!(gctx.get::("foo.key3").unwrap(), 5); assert_eq!(gctx.get::("foo.key4").unwrap(), 6); // With env. let gctx = GlobalContextBuilder::new() .env("CARGO_FOO_KEY3", "7") .env("CARGO_FOO_KEY4", "8") .env("CARGO_FOO_KEY5", "9") .config_arg("foo.key2 = 4") .config_arg("foo.key3 = 5") .config_arg("foo.key4 = 6") .build(); assert_eq!(gctx.get::("foo.key1").unwrap(), 1); assert_eq!(gctx.get::("foo.key2").unwrap(), 4); assert_eq!(gctx.get::("foo.key3").unwrap(), 5); assert_eq!(gctx.get::("foo.key4").unwrap(), 6); assert_eq!(gctx.get::("foo.key5").unwrap(), 9); } #[cargo_test] fn merge_array_mixed_def_paths() { // Merging of arrays with different def sites. write_config_toml( " paths = ['file'] ", ); // Create a directory for CWD to differentiate the paths. let somedir = paths::root().join("somedir"); fs::create_dir(&somedir).unwrap(); let gctx = GlobalContextBuilder::new() .cwd(&somedir) .config_arg("paths=['cli']") // env is currently ignored for get_list() .env("CARGO_PATHS", "env") .build(); let paths = gctx.get_list("paths").unwrap().unwrap(); // The definition for the root value is somewhat arbitrary, but currently starts with the file because that is what is loaded first. assert_eq!(paths.definition, Definition::Path(paths::root())); assert_eq!(paths.val.len(), 2); assert_eq!(paths.val[0].0, "file"); assert_eq!(paths.val[0].1.root(&gctx), paths::root()); assert_eq!(paths.val[1].0, "cli"); assert_eq!(paths.val[1].1.root(&gctx), somedir); } #[cargo_test] fn enforces_format() { // These dotted key expressions should all be fine. let gctx = GlobalContextBuilder::new() .config_arg("a=true") .config_arg(" b.a = true ") .config_arg("c.\"b\".'a'=true") .config_arg("d.\"=\".'='=true") .config_arg("e.\"'\".'\"'=true") .build(); assert_eq!(gctx.get::("a").unwrap(), true); assert_eq!( gctx.get::>("b").unwrap(), HashMap::from([("a".to_string(), true)]) ); assert_eq!( gctx.get::>>("c") .unwrap(), HashMap::from([("b".to_string(), HashMap::from([("a".to_string(), true)]))]) ); assert_eq!( gctx.get::>>("d") .unwrap(), HashMap::from([("=".to_string(), HashMap::from([("=".to_string(), true)]))]) ); assert_eq!( gctx.get::>>("e") .unwrap(), HashMap::from([("'".to_string(), HashMap::from([("\"".to_string(), true)]))]) ); // But anything that's not a dotted key expression should be disallowed. let _ = GlobalContextBuilder::new() .config_arg("[a] foo=true") .build_err() .unwrap_err(); let _ = GlobalContextBuilder::new() .config_arg("a = true\nb = true") .build_err() .unwrap_err(); // We also disallow overwriting with tables since it makes merging unclear. let _ = GlobalContextBuilder::new() .config_arg("a = { first = true, second = false }") .build_err() .unwrap_err(); let _ = GlobalContextBuilder::new() .config_arg("a = { first = true }") .build_err() .unwrap_err(); } #[cargo_test] fn unused_key() { // Unused key passed on command line. let gctx = GlobalContextBuilder::new() .config_arg("build.unused = 2") .build(); gctx.build_config().unwrap(); let output = read_output(gctx); let expected = str![[r#" [WARNING] unused config key `build.unused` in `--config cli option` "#]]; assert_e2e().eq(&output, expected); } #[cargo_test] fn rerooted_remains() { // Re-rooting keeps cli args. let somedir = paths::root().join("somedir"); fs::create_dir_all(somedir.join(".cargo")).unwrap(); fs::write( somedir.join(".cargo").join("config"), " a = 'file1' b = 'file2' ", ) .unwrap(); let mut gctx = GlobalContextBuilder::new() .cwd(&somedir) .config_arg("b='cli1'") .config_arg("c='cli2'") .build(); assert_eq!(gctx.get::("a").unwrap(), "file1"); assert_eq!(gctx.get::("b").unwrap(), "cli1"); assert_eq!(gctx.get::("c").unwrap(), "cli2"); gctx.reload_rooted_at(paths::root()).unwrap(); assert_eq!(gctx.get::>("a").unwrap(), None); assert_eq!(gctx.get::("b").unwrap(), "cli1"); assert_eq!(gctx.get::("c").unwrap(), "cli2"); } #[cargo_test] fn bad_parse() { // Fail to TOML parse. let gctx = GlobalContextBuilder::new().config_arg("abc").build_err(); assert_error( gctx.unwrap_err(), "\ failed to parse value from --config argument `abc` as a dotted key expression Caused by: TOML parse error at line 1, column 4 | 1 | abc | ^ expected `.`, `=` ", ); let gctx = GlobalContextBuilder::new().config_arg("").build_err(); assert_error( gctx.unwrap_err(), "--config argument `` was not a TOML dotted key expression (such as `build.jobs = 2`)", ); } #[cargo_test] fn too_many_values() { // Currently restricted to only 1 value. let gctx = GlobalContextBuilder::new() .config_arg("a=1\nb=2") .build_err(); assert_error( gctx.unwrap_err(), "\ --config argument `a=1 b=2` was not a TOML dotted key expression (such as `build.jobs = 2`)", ); } #[cargo_test] fn no_disallowed_values() { let gctx = GlobalContextBuilder::new() .config_arg("registry.token=\"hello\"") .build_err(); assert_error( gctx.unwrap_err(), "registry.token cannot be set through --config for security reasons", ); let gctx = GlobalContextBuilder::new() .config_arg("registries.crates-io.token=\"hello\"") .build_err(); assert_error( gctx.unwrap_err(), "registries.crates-io.token cannot be set through --config for security reasons", ); let gctx = GlobalContextBuilder::new() .config_arg("registry.secret-key=\"hello\"") .build_err(); assert_error( gctx.unwrap_err(), "registry.secret-key cannot be set through --config for security reasons", ); let gctx = GlobalContextBuilder::new() .config_arg("registries.crates-io.secret-key=\"hello\"") .build_err(); assert_error( gctx.unwrap_err(), "registries.crates-io.secret-key cannot be set through --config for security reasons", ); } #[cargo_test] fn no_inline_table_value() { // Disallow inline tables let gctx = GlobalContextBuilder::new() .config_arg("a.b={c = \"d\"}") .build_err(); assert_error( gctx.unwrap_err(), "--config argument `a.b={c = \"d\"}` sets a value to an inline table, which is not accepted", ); } #[cargo_test] fn no_array_of_tables_values() { // Disallow array-of-tables when not in dotted form let gctx = GlobalContextBuilder::new() .config_arg("[[a.b]]\nc = \"d\"") .build_err(); assert_error( gctx.unwrap_err(), "\ --config argument `[[a.b]] c = \"d\"` was not a TOML dotted key expression (such as `build.jobs = 2`)", ); } #[cargo_test] fn no_comments() { // Disallow comments in dotted form. let gctx = GlobalContextBuilder::new() .config_arg("a.b = \"c\" # exactly") .build_err(); assert_error( gctx.unwrap_err(), "\ --config argument `a.b = \"c\" # exactly` includes non-whitespace decoration", ); let gctx = GlobalContextBuilder::new() .config_arg("# exactly\na.b = \"c\"") .build_err(); assert_error( gctx.unwrap_err(), "\ --config argument `# exactly\na.b = \"c\"` includes non-whitespace decoration", ); } #[cargo_test] fn bad_cv_convert() { // ConfigValue does not support all TOML types. let gctx = GlobalContextBuilder::new() .config_arg("a=2019-12-01") .build_err(); assert_error( gctx.unwrap_err(), "\ failed to convert --config argument `a=2019-12-01` Caused by: failed to parse key `a` Caused by: found TOML configuration value of unknown type `datetime`", ); } #[cargo_test] fn fail_to_merge_multiple_args() { // Error message when multiple args fail to merge. let gctx = GlobalContextBuilder::new() .config_arg("foo='a'") .config_arg("foo=['a']") .build_err(); // This is a little repetitive, but hopefully the user can figure it out. assert_error( gctx.unwrap_err(), "\ failed to merge --config argument `foo=['a']` Caused by: failed to merge key `foo` between --config cli option and --config cli option Caused by: failed to merge config value from `--config cli option` into `--config cli option`: \ expected string, but found array", ); } #[cargo_test] fn cli_path() { // --config path_to_file fs::write(paths::root().join("myconfig.toml"), "key = 123").unwrap(); let gctx = GlobalContextBuilder::new() .cwd(paths::root()) .config_arg("myconfig.toml") .build(); assert_eq!(gctx.get::("key").unwrap(), 123); let gctx = GlobalContextBuilder::new() .config_arg("missing.toml") .build_err(); assert_error( gctx.unwrap_err(), "\ failed to parse value from --config argument `missing.toml` as a dotted key expression Caused by: TOML parse error at line 1, column 13 | 1 | missing.toml | ^ expected `.`, `=` ", ); } cargo-0.86.0/tests/testsuite/config_include.rs000064400000000000000000000300141046102023000175210ustar 00000000000000//! Tests for `include` config field. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; use super::config::{assert_error, write_config_at, write_config_toml, GlobalContextBuilder}; #[cargo_test] fn gated() { // Requires -Z flag. write_config_toml("include='other.toml'"); write_config_at( ".cargo/other.toml", " othervalue = 1 ", ); let gctx = GlobalContextBuilder::new().build(); assert_eq!(gctx.get::>("othervalue").unwrap(), None); let gctx = GlobalContextBuilder::new() .unstable_flag("config-include") .build(); assert_eq!(gctx.get::("othervalue").unwrap(), 1); } #[cargo_test] fn simple() { // Simple test. write_config_at( ".cargo/config.toml", " include = 'other.toml' key1 = 1 key2 = 2 ", ); write_config_at( ".cargo/other.toml", " key2 = 3 key3 = 4 ", ); let gctx = GlobalContextBuilder::new() .unstable_flag("config-include") .build(); assert_eq!(gctx.get::("key1").unwrap(), 1); assert_eq!(gctx.get::("key2").unwrap(), 2); assert_eq!(gctx.get::("key3").unwrap(), 4); } #[cargo_test] fn enable_in_unstable_config() { // config-include enabled in the unstable config table: write_config_at( ".cargo/config.toml", " include = 'other.toml' key1 = 1 key2 = 2 [unstable] config-include = true ", ); write_config_at( ".cargo/other.toml", " key2 = 3 key3 = 4 ", ); let gctx = GlobalContextBuilder::new() .nightly_features_allowed(true) .build(); assert_eq!(gctx.get::("key1").unwrap(), 1); assert_eq!(gctx.get::("key2").unwrap(), 2); assert_eq!(gctx.get::("key3").unwrap(), 4); } #[cargo_test] fn mix_of_hierarchy_and_include() { write_config_at( "foo/.cargo/config.toml", " include = 'other.toml' key1 = 1 # also make sure unstable flags merge in the correct order [unstable] features = ['1'] ", ); write_config_at( "foo/.cargo/other.toml", " key1 = 2 key2 = 2 [unstable] features = ['2'] ", ); write_config_at( ".cargo/config.toml", " include = 'other.toml' key1 = 3 key2 = 3 key3 = 3 [unstable] features = ['3'] ", ); write_config_at( ".cargo/other.toml", " key1 = 4 key2 = 4 key3 = 4 key4 = 4 [unstable] features = ['4'] ", ); let gctx = GlobalContextBuilder::new() .unstable_flag("config-include") .cwd("foo") .nightly_features_allowed(true) .build(); assert_eq!(gctx.get::("key1").unwrap(), 1); assert_eq!(gctx.get::("key2").unwrap(), 2); assert_eq!(gctx.get::("key3").unwrap(), 3); assert_eq!(gctx.get::("key4").unwrap(), 4); assert_eq!( gctx.get::>("unstable.features").unwrap(), vec![ "4".to_string(), "3".to_string(), "2".to_string(), "1".to_string() ] ); } #[cargo_test] fn mix_of_hierarchy_and_include_with_enable_in_unstable_config() { // `mix_of_hierarchy_and_include`, but with the config-include // feature itself enabled in the unstable config table: write_config_at( "foo/.cargo/config.toml", " include = 'other.toml' key1 = 1 # also make sure unstable flags merge in the correct order [unstable] features = ['1'] config-include = true ", ); write_config_at( "foo/.cargo/other.toml", " key1 = 2 key2 = 2 [unstable] features = ['2'] ", ); write_config_at( ".cargo/config.toml", " include = 'other.toml' key1 = 3 key2 = 3 key3 = 3 [unstable] features = ['3'] ", ); write_config_at( ".cargo/other.toml", " key1 = 4 key2 = 4 key3 = 4 key4 = 4 [unstable] features = ['4'] ", ); let gctx = GlobalContextBuilder::new() .cwd("foo") .nightly_features_allowed(true) .build(); assert_eq!(gctx.get::("key1").unwrap(), 1); assert_eq!(gctx.get::("key2").unwrap(), 2); assert_eq!(gctx.get::("key3").unwrap(), 3); assert_eq!(gctx.get::("key4").unwrap(), 4); assert_eq!( gctx.get::>("unstable.features").unwrap(), vec![ "4".to_string(), "3".to_string(), "2".to_string(), "1".to_string() ] ); } #[cargo_test] fn works_with_cli() { write_config_at( ".cargo/config.toml", " include = 'other.toml' [build] rustflags = ['-W', 'unused'] ", ); write_config_at( ".cargo/other.toml", " [build] rustflags = ['-W', 'unsafe-code'] ", ); let p = project().file("src/lib.rs", "").build(); p.cargo("check -v") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]-W unused` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check -v -Z config-include") .masquerade_as_nightly_cargo(&["config-include"]) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]-W unsafe-code -W unused` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn left_to_right_bottom_to_top() { // How it merges multiple nested includes. write_config_at( ".cargo/config.toml", " 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/right-bottom.toml", " top = -1 right-middle = -1 right-bottom = -1 ", ); write_config_at( ".cargo/left-middle.toml", " 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 gctx = GlobalContextBuilder::new() .unstable_flag("config-include") .build(); assert_eq!(gctx.get::("top").unwrap(), 1); assert_eq!(gctx.get::("right-middle").unwrap(), 0); assert_eq!(gctx.get::("right-bottom").unwrap(), -1); assert_eq!(gctx.get::("left-middle").unwrap(), -2); assert_eq!(gctx.get::("left-bottom").unwrap(), -3); } #[cargo_test] fn missing_file() { // Error when there's a missing file. write_config_toml("include='missing.toml'"); let gctx = GlobalContextBuilder::new() .unstable_flag("config-include") .build_err(); assert_error( gctx.unwrap_err(), &format!( "\ could not load Cargo configuration Caused by: failed to load config include `missing.toml` from `[..]/.cargo/config.toml` Caused by: failed to read configuration file `[..]/.cargo/missing.toml` Caused by: [NOT_FOUND]", ), ); } #[cargo_test] fn wrong_file_extension() { // Error when it doesn't end with `.toml`. write_config_toml("include='config.png'"); let gctx = GlobalContextBuilder::new() .unstable_flag("config-include") .build_err(); assert_error( gctx.unwrap_err(), "\ could not load Cargo configuration Caused by: expected a config include path ending with `.toml`, but found `config.png` from `[ROOT]/.cargo/config.toml`", ); } #[cargo_test] fn cycle() { // Detects a cycle. 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 gctx = GlobalContextBuilder::new() .unstable_flag("config-include") .build_err(); assert_error( gctx.unwrap_err(), "\ could not load Cargo configuration Caused by: failed to load config include `one.toml` from `[..]/.cargo/config.toml` Caused by: failed to load config include `two.toml` from `[..]/.cargo/one.toml` Caused by: failed to load config include `config.toml` from `[..]/.cargo/two.toml` Caused by: config `include` cycle detected with path `[..]/.cargo/config.toml`", ); } #[cargo_test] fn cli_include() { // Using --config with include. // CLI takes priority over files. write_config_at( ".cargo/config.toml", " foo = 1 bar = 2 ", ); write_config_at(".cargo/config-foo.toml", "foo = 2"); let gctx = GlobalContextBuilder::new() .unstable_flag("config-include") .config_arg("include='.cargo/config-foo.toml'") .build(); assert_eq!(gctx.get::("foo").unwrap(), 2); assert_eq!(gctx.get::("bar").unwrap(), 2); } #[cargo_test] fn bad_format() { // Not a valid format. write_config_toml("include = 1"); let gctx = GlobalContextBuilder::new() .unstable_flag("config-include") .build_err(); assert_error( gctx.unwrap_err(), "\ could not load Cargo configuration Caused by: `include` expected a string or list, but found integer in `[..]/.cargo/config.toml`", ); } #[cargo_test] fn cli_include_failed() { // Error message when CLI include fails to load. let gctx = GlobalContextBuilder::new() .unstable_flag("config-include") .config_arg("include='foobar.toml'") .build_err(); assert_error( gctx.unwrap_err(), &format!( "\ failed to load --config include Caused by: failed to load config include `foobar.toml` from `--config cli option` Caused by: failed to read configuration file `[..]/foobar.toml` Caused by: [NOT_FOUND]" ), ); } #[cargo_test] fn cli_merge_failed() { // Error message when CLI include merge fails. write_config_toml("foo = ['a']"); write_config_at( ".cargo/other.toml", " foo = 'b' ", ); let gctx = GlobalContextBuilder::new() .unstable_flag("config-include") .config_arg("include='.cargo/other.toml'") .build_err(); // Maybe this error message should mention it was from an include file? assert_error( gctx.unwrap_err(), "\ failed to merge --config key `foo` into `[..]/.cargo/config.toml` Caused by: failed to merge config value from `[..]/.cargo/other.toml` into `[..]/.cargo/config.toml`: \ expected array, but found string", ); } #[cargo_test] fn cli_include_take_priority_over_env() { write_config_at(".cargo/include.toml", "k='include'"); // k=env let gctx = GlobalContextBuilder::new().env("CARGO_K", "env").build(); assert_eq!(gctx.get::("k").unwrap(), "env"); // k=env // --config 'include=".cargo/include.toml"' let gctx = GlobalContextBuilder::new() .env("CARGO_K", "env") .unstable_flag("config-include") .config_arg("include='.cargo/include.toml'") .build(); assert_eq!(gctx.get::("k").unwrap(), "include"); // k=env // --config '.cargo/foo.toml' write_config_at(".cargo/foo.toml", "include='include.toml'"); let gctx = GlobalContextBuilder::new() .env("CARGO_K", "env") .unstable_flag("config-include") .config_arg(".cargo/foo.toml") .build(); assert_eq!(gctx.get::("k").unwrap(), "include"); } cargo-0.86.0/tests/testsuite/corrupt_git.rs000064400000000000000000000101501046102023000171110ustar 00000000000000//! Tests for corrupt git repos. use std::fs; use std::path::{Path, PathBuf}; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::{basic_manifest, git, project}; use cargo_util::paths as cargopaths; #[cargo_test] fn deleting_database_files() { let project = project(); let git_project = git::new("bar", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "") }); let project = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" authors = [] [dependencies] bar = {{ git = '{}' }} "#, git_project.url() ), ) .file("src/lib.rs", "") .build(); project.cargo("check").run(); let mut files = Vec::new(); find_files(&paths::home().join(".cargo/git/db"), &mut files); assert!(!files.is_empty()); let log = "cargo::sources::git=trace"; for file in files { if !file.exists() { continue; } println!("deleting {}", file.display()); cargopaths::remove_file(&file).unwrap(); project.cargo("check -v").env("CARGO_LOG", log).run(); if !file.exists() { continue; } println!("truncating {}", file.display()); make_writable(&file); fs::OpenOptions::new() .write(true) .open(&file) .unwrap() .set_len(2) .unwrap(); project.cargo("check -v").env("CARGO_LOG", log).run(); } } #[cargo_test] fn deleting_checkout_files() { let project = project(); let git_project = git::new("bar", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "") }); let project = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" authors = [] [dependencies] bar = {{ git = '{}' }} "#, git_project.url() ), ) .file("src/lib.rs", "") .build(); project.cargo("check").run(); let dir = paths::home() .join(".cargo/git/checkouts") // get the first entry in the checkouts dir for the package's location .read_dir() .unwrap() .next() .unwrap() .unwrap() .path() // get the first child of that checkout dir for our checkout .read_dir() .unwrap() .next() .unwrap() .unwrap() .path() // and throw on .git to corrupt things .join(".git"); let mut files = Vec::new(); find_files(&dir, &mut files); assert!(!files.is_empty()); let log = "cargo::sources::git=trace"; for file in files { if !file.exists() { continue; } println!("deleting {}", file.display()); cargopaths::remove_file(&file).unwrap(); project.cargo("check -v").env("CARGO_LOG", log).run(); if !file.exists() { continue; } println!("truncating {}", file.display()); make_writable(&file); fs::OpenOptions::new() .write(true) .open(&file) .unwrap() .set_len(2) .unwrap(); project.cargo("check -v").env("CARGO_LOG", log).run(); } } fn make_writable(path: &Path) { let mut p = path.metadata().unwrap().permissions(); p.set_readonly(false); fs::set_permissions(path, p).unwrap(); } fn find_files(path: &Path, dst: &mut Vec) { for e in path.read_dir().unwrap() { let e = e.unwrap(); let path = e.path(); if e.file_type().unwrap().is_dir() { find_files(&path, dst); } else { dst.push(path); } } } cargo-0.86.0/tests/testsuite/credential_process.rs000064400000000000000000000561311046102023000204310ustar 00000000000000//! Tests for credential-process. use cargo_test_support::prelude::*; use cargo_test_support::registry::{Package, TestRegistry}; use cargo_test_support::{basic_manifest, cargo_process, paths, project, registry, str, Project}; fn toml_bin(proj: &Project, name: &str) -> String { proj.bin(name).display().to_string().replace('\\', "\\\\") } /// Setup for a test that will issue a command that needs to fetch a token. /// /// This does the following: /// /// * Spawn a thread that will act as an API server. /// * Create a simple credential-process that will generate a fake token. /// * Create a simple `foo` project to run the test against. /// * Configure the credential-process config. /// /// Returns the simple `foo` project to test against and the API server handle. fn get_token_test() -> (Project, TestRegistry) { // API server that checks that the token is included correctly. let server = registry::RegistryBuilder::new() .no_configure_token() .token(cargo_test_support::registry::Token::Plaintext( "sekrit".to_string(), )) .alternative() .http_api() .http_index() .auth_required() .build(); let provider = build_provider( "test-cred", r#"{"Ok":{"kind":"get","token":"sekrit","cache":"session","operation_independent":false}}"#, ); let p = project() .file( ".cargo/config.toml", &format!( r#" [registries.alternative] index = "{}" credential-provider = ["{provider}"] "#, server.index_url(), ), ) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" description = "foo" license = "MIT" homepage = "https://example.com/" "#, ) .file("src/lib.rs", "") .build(); (p, server) } #[cargo_test] fn publish() { // Checks that credential-process is used for `cargo publish`. let (p, _t) = get_token_test(); p.cargo("publish --no-verify --registry alternative") .with_stderr_data(str![[r#" [UPDATING] `alternative` index {"v":1,"registry":{"index-url":"[..]","name":"alternative","headers":[..]},"kind":"get","operation":"read"} [PACKAGING] foo v0.1.0 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.1.0 ([ROOT]/foo) {"v":1,"registry":{"index-url":"[..]","name":"alternative"},"kind":"get","operation":"publish","name":"foo","vers":"0.1.0","cksum":"[..]"} [UPLOADED] foo v0.1.0 to registry `alternative` [NOTE] waiting for `foo v0.1.0` to be available at registry `alternative`. You may press ctrl-c [..] [PUBLISHED] foo v0.1.0 at registry `alternative` "#]]) .run(); } #[cargo_test] fn basic_unsupported() { // Non-action commands don't support login/logout. let registry = registry::RegistryBuilder::new() .no_configure_token() .credential_provider(&["cargo:token-from-stdout", "false"]) .build(); cargo_process("login abcdefg") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] credential provider `cargo:token-from-stdout false` failed action `login` Caused by: requested operation not supported "#]]) .run(); cargo_process("logout") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] credential provider `cargo:token-from-stdout false` failed action `logout` Caused by: requested operation not supported "#]]) .run(); } #[cargo_test] fn login() { let registry = registry::RegistryBuilder::new() .no_configure_token() .credential_provider(&[ &build_provider("test-cred", r#"{"Ok": {"kind": "login"}}"#), "cfg1", "--cfg2", ]) .build(); cargo_process("login abcdefg -- cmd3 --cmd4") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index {"v":1,"registry":{"index-url":"https://github.com/rust-lang/crates.io-index","name":"crates-io"},"kind":"login","token":"abcdefg","login-url":"[ROOTURL]/api/me","args":["cfg1","--cfg2","cmd3","--cmd4"]} "#]]) .run(); } #[cargo_test] fn logout() { let server = registry::RegistryBuilder::new() .no_configure_token() .credential_provider(&[&build_provider( "test-cred", r#"{"Ok": {"kind": "logout"}}"#, )]) .build(); cargo_process("logout") .replace_crates_io(server.index_url()) .with_stderr_data(str![[r#" {"v":1,"registry":{"index-url":"https://github.com/rust-lang/crates.io-index","name":"crates-io"},"kind":"logout"} "#]]) .run(); } #[cargo_test] fn yank() { let (p, _t) = get_token_test(); p.cargo("yank --version 0.1.0 --registry alternative") .with_stderr_data(str![[r#" [UPDATING] `alternative` index {"v":1,"registry":{"index-url":"[..]","name":"alternative","headers":[..]},"kind":"get","operation":"read"} {"v":1,"registry":{"index-url":"[..]","name":"alternative"},"kind":"get","operation":"yank","name":"foo","vers":"0.1.0"} [YANK] foo@0.1.0 "#]]) .run(); } #[cargo_test] fn owner() { let (p, _t) = get_token_test(); p.cargo("owner --add username --registry alternative") .with_stderr_data(str![[r#" [UPDATING] `alternative` index {"v":1,"registry":{"index-url":"[..]","name":"alternative","headers":[..]},"kind":"get","operation":"read"} {"v":1,"registry":{"index-url":"[..]","name":"alternative"},"kind":"get","operation":"owners","name":"foo"} [OWNER] completed! "#]]) .run(); } #[cargo_test] fn invalid_token_output() { // Error when credential process does not output the expected format for a token. let cred_proj = project() .at("cred_proj") .file("Cargo.toml", &basic_manifest("test-cred", "1.0.0")) .file("src/main.rs", r#"fn main() { print!("a\nb\n"); } "#) .build(); cred_proj.cargo("build").run(); let _server = registry::RegistryBuilder::new() .alternative() .credential_provider(&[ "cargo:token-from-stdout", &toml_bin(&cred_proj, "test-cred"), ]) .no_configure_token() .build(); let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/lib.rs", "") .build(); p.cargo("publish --no-verify --registry alternative") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [ERROR] credential provider `[..]test-cred[EXE]` failed action `get` Caused by: process `[..]` returned more than one line of output; expected a single token "#]]) .run(); } /// Builds a credential provider that echos the request from cargo to stderr, /// and prints the `response` to stdout. fn build_provider(name: &str, response: &str) -> String { // The credential process to use. let cred_proj = project() .at(name) .file("Cargo.toml", &basic_manifest(name, "1.0.0")) .file( "src/main.rs", &r####" fn main() { println!(r#"{{"v":[1]}}"#); assert_eq!(std::env::args().skip(1).next().unwrap(), "--cargo-plugin"); let mut buffer = String::new(); std::io::stdin().read_line(&mut buffer).unwrap(); eprint!("{}", buffer); use std::io::Write; std::io::stdout().write_all(r###"[RESPONSE]"###.as_bytes()).unwrap(); println!(); } "#### .replace("[RESPONSE]", response), ) .build(); cred_proj.cargo("build").run(); toml_bin(&cred_proj, name) } #[cargo_test] fn not_found() { let registry = registry::RegistryBuilder::new() .no_configure_token() .http_index() .auth_required() .credential_provider(&[&build_provider( "not_found", r#"{"Err": {"kind": "not-found"}}"#, )]) .build(); // should not suggest a _TOKEN environment variable since the cargo:token provider isn't available. cargo_process("install -v foo") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [CREDENTIAL] [..]not_found[..] get crates-io {"v":1[..] [ERROR] no token found, please run `cargo login` "#]]) .run(); } #[cargo_test] fn all_not_found() { let server = registry::RegistryBuilder::new() .no_configure_token() .auth_required() .http_index() .build(); let not_found = build_provider("not_found", r#"{"Err": {"kind": "not-found"}}"#); cargo_util::paths::append( &paths::home().join(".cargo/config.toml"), format!( r#" [registry] global-credential-providers = ["not_found"] [credential-alias] not_found = ["{not_found}"] "#, ) .as_bytes(), ) .unwrap(); // should not suggest a _TOKEN environment variable since the cargo:token provider isn't available. cargo_process("install -v foo") .replace_crates_io(server.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [CREDENTIAL] [..]not_found[..] get crates-io {"v":1,"registry":{"index-url":"[..]","name":"crates-io","headers":[[..]"WWW-Authenticate: Cargo login_url=/"https://test-registry-login/me/""[..]]},"kind":"get","operation":"read"} [ERROR] no token found, please run `cargo login` "#]]) .run(); } #[cargo_test] fn all_not_supported() { let server = registry::RegistryBuilder::new() .no_configure_token() .auth_required() .http_index() .build(); let not_supported = build_provider("not_supported", r#"{"Err": {"kind": "url-not-supported"}}"#); cargo_util::paths::append( &paths::home().join(".cargo/config.toml"), format!( r#" [registry] global-credential-providers = ["not_supported"] [credential-alias] not_supported = ["{not_supported}"] "#, ) .as_bytes(), ) .unwrap(); cargo_process("install -v foo") .replace_crates_io(server.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [CREDENTIAL] [..]not_supported[..] get crates-io {"v":1,"registry":{"index-url":"[..]","name":"crates-io","headers":[[..]"WWW-Authenticate: Cargo login_url=/"https://test-registry-login/me/""[..]]},"kind":"get","operation":"read"} [ERROR] no credential providers could handle the request "#]]) .run(); } #[cargo_test] fn multiple_providers() { let server = registry::RegistryBuilder::new() .no_configure_token() .build(); // Set up two credential providers: the first will fail with "UrlNotSupported" // and Cargo should skip it. The second should succeed. let url_not_supported = build_provider( "url_not_supported", r#"{"Err": {"kind": "url-not-supported"}}"#, ); let success_provider = build_provider("success_provider", r#"{"Ok": {"kind": "login"}}"#); cargo_util::paths::append( &paths::home().join(".cargo/config.toml"), format!( r#" [registry] global-credential-providers = ["success_provider", "url_not_supported"] [credential-alias] success_provider = ["{success_provider}"] url_not_supported = ["{url_not_supported}"] "#, ) .as_bytes(), ) .unwrap(); cargo_process("login -v abcdefg") .replace_crates_io(server.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [CREDENTIAL] [..]url_not_supported[..] login crates-io {"v":1,"registry":{"index-url":"https://github.com/rust-lang/crates.io-index","name":"crates-io"},"kind":"login","token":"abcdefg","login-url":"[ROOTURL]/api/me"} [CREDENTIAL] [..]success_provider[..] login crates-io {"v":1,"registry":{"index-url":"https://github.com/rust-lang/crates.io-index","name":"crates-io"},"kind":"login","token":"abcdefg","login-url":"[ROOTURL]/api/me"} "#]]) .run(); } #[cargo_test] fn both_token_and_provider() { let server = registry::RegistryBuilder::new() .credential_provider(&["cargo:paseto"]) .build(); cargo_process("login -Z asymmetric-token") .masquerade_as_nightly_cargo(&["asymmetric-token"]) .replace_crates_io(server.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] registry `crates-io` has a token configured in [ROOT]/home/.cargo/credentials.toml that will be ignored because this registry is configured to use credential-provider `cargo:paseto` k3.public[..] "#]]) .run(); } #[cargo_test] fn registry_provider_overrides_global() { let server = registry::RegistryBuilder::new().build(); cargo_util::paths::append( &paths::home().join(".cargo/config.toml"), format!( r#" [registry] global-credential-providers = ["should-not-be-called"] "#, ) .as_bytes(), ) .unwrap(); cargo_process("login -v abcdefg") .env("CARGO_REGISTRY_CREDENTIAL_PROVIDER", "cargo:token") .replace_crates_io(server.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [CREDENTIAL] cargo:token login crates-io [LOGIN] token for `crates-io` saved "#]]) .run(); let credentials = std::fs::read_to_string(paths::home().join(".cargo/credentials.toml")).unwrap(); assert_eq!(credentials, "[registry]\ntoken = \"abcdefg\"\n"); } #[cargo_test] fn both_asymmetric_and_token() { let server = registry::RegistryBuilder::new().build(); cargo_util::paths::append( &paths::home().join(".cargo/config.toml"), format!( r#" [registry] token = "foo" secret-key = "bar" "#, ) .as_bytes(), ) .unwrap(); cargo_process("login -Zasymmetric-token -v abcdefg") .masquerade_as_nightly_cargo(&["asymmetric-token"]) .replace_crates_io(server.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] registry `crates-io` has a `secret_key` configured in [..]config.toml that will be ignored because a `token` is also configured, and the `cargo:token` provider is configured with higher precedence [CREDENTIAL] cargo:token login crates-io [LOGIN] token for `crates-io` saved "#]]) .run(); } #[cargo_test] fn token_caching() { let server = registry::RegistryBuilder::new() .no_configure_token() .no_configure_registry() .token(cargo_test_support::registry::Token::Plaintext( "sekrit".to_string(), )) .alternative() .http_api() .http_index() .build(); // Token should not be re-used if it is expired let expired_provider = build_provider( "expired_provider", r#"{"Ok":{"kind":"get","token":"sekrit","cache":"expires","expiration":0,"operation_independent":true}}"#, ); // Token should not be re-used for a different operation if it is not operation_independent let non_independent_provider = build_provider( "non_independent_provider", r#"{"Ok":{"kind":"get","token":"sekrit","cache":"session","operation_independent":false}}"#, ); let p = project() .file( ".cargo/config.toml", &format!( r#" [registries.alternative] index = "{}" credential-provider = ["{expired_provider}"] "#, server.index_url(), ), ) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" description = "foo" license = "MIT" homepage = "https://example.com/" "#, ) .file("src/lib.rs", "") .build(); let output = r#"[UPDATING] `alternative` index {"v":1,"registry":{"index-url":"[..]","name":"alternative"},"kind":"get","operation":"read"} [PACKAGING] foo v0.1.0 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.1.0 ([ROOT]/foo) {"v":1,"registry":{"index-url":"[..]","name":"alternative"},"kind":"get","operation":"publish","name":"foo","vers":"0.1.0","cksum":"[..]"} [UPLOADED] foo v0.1.0 to registry `alternative` [NOTE] waiting [..] You may press ctrl-c [..] [PUBLISHED] foo v0.1.0 at registry `alternative` "#; // The output should contain two JSON messages from the provider in both cases: // The first because the credential is expired, the second because the provider // indicated that the token was non-operation-independent. p.cargo("publish --registry alternative --no-verify") .with_stderr_data(output) .run(); let output_non_independent = r#"[UPDATING] `alternative` index {"v":1,"registry":{"index-url":"[..]","name":"alternative"},"kind":"get","operation":"read"} [PACKAGING] foo v0.1.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.1.1 ([ROOT]/foo) {"v":1,"registry":{"index-url":"[..]","name":"alternative"},"kind":"get","operation":"publish","name":"foo","vers":"0.1.1","cksum":"[..]"} [UPLOADED] foo v0.1.1 to registry `alternative` [NOTE] waiting [..] You may press ctrl-c [..] [PUBLISHED] foo v0.1.1 at registry `alternative` "#; p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.1" edition = "2015" description = "foo" license = "MIT" homepage = "https://example.com/" "#, ); p.change_file( ".cargo/config.toml", &format!( r#" [registries.alternative] index = "{}" credential-provider = ["{non_independent_provider}"] "#, server.index_url(), ), ); p.cargo("publish --registry alternative --no-verify") .with_stderr_data(output_non_independent) .run(); } #[cargo_test] fn basic_provider() { let cred_proj = project() .at("cred_proj") .file("Cargo.toml", &basic_manifest("test-cred", "1.0.0")) .file("src/main.rs", r#"fn main() { eprintln!("CARGO={:?}", std::env::var("CARGO").ok()); eprintln!("CARGO_REGISTRY_NAME_OPT={:?}", std::env::var("CARGO_REGISTRY_NAME_OPT").ok()); eprintln!("CARGO_REGISTRY_INDEX_URL={:?}", std::env::var("CARGO_REGISTRY_INDEX_URL").ok()); print!("sekrit"); }"#) .build(); cred_proj.cargo("build").run(); let _server = registry::RegistryBuilder::new() .no_configure_token() .credential_provider(&[ "cargo:token-from-stdout", &toml_bin(&cred_proj, "test-cred"), ]) .token(cargo_test_support::registry::Token::Plaintext( "sekrit".to_string(), )) .alternative() .http_api() .auth_required() .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] version = "0.0.1" registry = "alternative" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").alternative(true).publish(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOCKING] 1 package to latest compatible version CARGO=Some([..]) CARGO_REGISTRY_NAME_OPT=Some("alternative") CARGO_REGISTRY_INDEX_URL=Some("[ROOTURL]/alternative-registry") [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `alternative`) [CHECKING] bar v0.0.1 (registry `alternative`) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn unsupported_version() { let cred_proj = project() .at("new-vers") .file("Cargo.toml", &basic_manifest("new-vers", "1.0.0")) .file( "src/main.rs", &r####" fn main() { println!(r#"{{"v":[998, 999]}}"#); assert_eq!(std::env::args().skip(1).next().unwrap(), "--cargo-plugin"); let mut buffer = String::new(); std::io::stdin().read_line(&mut buffer).unwrap(); std::thread::sleep(std::time::Duration::from_secs(1)); panic!("child process should have been killed before getting here"); } "####, ) .build(); cred_proj.cargo("build").run(); let provider = toml_bin(&cred_proj, "new-vers"); let registry = registry::RegistryBuilder::new() .no_configure_token() .credential_provider(&[&provider]) .build(); cargo_process("login abcdefg") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] credential provider `[..]` failed action `login` Caused by: credential provider supports protocol versions [998, 999], while Cargo supports [1] "#]]) .run(); } #[cargo_test] fn alias_builtin_warning() { let registry = registry::RegistryBuilder::new() .credential_provider(&[&"cargo:token"]) .build(); cargo_util::paths::append( &paths::home().join(".cargo/config.toml"), format!( r#" [credential-alias] "cargo:token" = ["ignored"] "#, ) .as_bytes(), ) .unwrap(); cargo_process("login abcdefg") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] credential-alias `cargo:token` (defined in `[ROOT]/home/.cargo/config.toml`) will be ignored because it would shadow a built-in credential-provider [LOGIN] token for `crates-io` saved "#]]) .run(); } #[cargo_test] fn login_token_from_stdin() { // Test reading a token from stdin, ensuring newlines are trimmed. let registry = registry::RegistryBuilder::new() .no_configure_token() .credential_provider(&[&build_provider("test-cred", r#"{"Ok": {"kind": "login"}}"#)]) .build(); cargo_process("login") .replace_crates_io(registry.index_url()) .with_stdin("abcdefg\n") .with_stderr_data(str![[r#" [UPDATING] crates.io index {"v":1,"registry":{"index-url":"https://github.com/rust-lang/crates.io-index","name":"crates-io"},"kind":"login","token":"abcdefg","login-url":"[ROOTURL]/api/me"} "#]]) .run(); } cargo-0.86.0/tests/testsuite/cross_compile.rs000064400000000000000000001040071046102023000174160ustar 00000000000000//! Tests for cross compiling with --target. //! //! See `cargo_test_support::cross_compile` for more detail. use cargo_test_support::prelude::*; use cargo_test_support::rustc_host; use cargo_test_support::str; use cargo_test_support::{basic_bin_manifest, basic_manifest, cross_compile, project}; #[cargo_test] fn simple_cross() { if cross_compile::disabled() { return; } let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "build.rs", &format!( r#" fn main() {{ assert_eq!(std::env::var("TARGET").unwrap(), "{}"); }} "#, cross_compile::alternate() ), ) .file( "src/main.rs", &format!( r#" use std::env; fn main() {{ assert_eq!(env::consts::ARCH, "{}"); }} "#, cross_compile::alternate_arch() ), ) .build(); let target = cross_compile::alternate(); p.cargo("build -v --target").arg(&target).run(); assert!(p.target_bin(target, "foo").is_file()); if cross_compile::can_run_on_host() { p.process(&p.target_bin(target, "foo")).run(); } } #[cargo_test] fn simple_cross_config() { if cross_compile::disabled() { return; } let p = project() .file( ".cargo/config.toml", &format!( r#" [build] target = "{}" "#, cross_compile::alternate() ), ) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "build.rs", &format!( r#" fn main() {{ assert_eq!(std::env::var("TARGET").unwrap(), "{}"); }} "#, cross_compile::alternate() ), ) .file( "src/main.rs", &format!( r#" use std::env; fn main() {{ assert_eq!(env::consts::ARCH, "{}"); }} "#, cross_compile::alternate_arch() ), ) .build(); let target = cross_compile::alternate(); p.cargo("build -v").run(); assert!(p.target_bin(target, "foo").is_file()); if cross_compile::can_run_on_host() { p.process(&p.target_bin(target, "foo")).run(); } } #[cargo_test] fn simple_deps() { if cross_compile::disabled() { return; } let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" "#, ) .file("src/main.rs", "extern crate bar; fn main() { bar::bar(); }") .build(); let _p2 = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("src/lib.rs", "pub fn bar() {}") .build(); let target = cross_compile::alternate(); p.cargo("build --target").arg(&target).run(); assert!(p.target_bin(target, "foo").is_file()); if cross_compile::can_run_on_host() { p.process(&p.target_bin(target, "foo")).run(); } } /// Always take care of setting these so that /// `cross_compile::alternate()` is the actually-picked target fn per_crate_target_test( default_target: Option<&'static str>, forced_target: Option<&'static str>, arg_target: Option<&'static str>, ) { if cross_compile::disabled() { return; } let p = project() .file( "Cargo.toml", &format!( r#" cargo-features = ["per-package-target"] [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] build = "build.rs" {} {} "#, default_target .map(|t| format!(r#"default-target = "{}""#, t)) .unwrap_or(String::new()), forced_target .map(|t| format!(r#"forced-target = "{}""#, t)) .unwrap_or(String::new()), ), ) .file( "build.rs", &format!( r#" fn main() {{ assert_eq!(std::env::var("TARGET").unwrap(), "{}"); }} "#, cross_compile::alternate() ), ) .file( "src/main.rs", &format!( r#" use std::env; fn main() {{ assert_eq!(env::consts::ARCH, "{}"); }} "#, cross_compile::alternate_arch() ), ) .build(); let mut cmd = p.cargo("build -v"); if let Some(t) = arg_target { cmd.arg("--target").arg(&t); } cmd.masquerade_as_nightly_cargo(&["per-package-target"]) .run(); assert!(p.target_bin(cross_compile::alternate(), "foo").is_file()); if cross_compile::can_run_on_host() { p.process(&p.target_bin(cross_compile::alternate(), "foo")) .run(); } } #[cargo_test] fn per_crate_default_target_is_default() { per_crate_target_test(Some(cross_compile::alternate()), None, None); } #[cargo_test] fn per_crate_default_target_gets_overridden() { per_crate_target_test( Some(cross_compile::unused()), None, Some(cross_compile::alternate()), ); } #[cargo_test] fn per_crate_forced_target_is_default() { per_crate_target_test(None, Some(cross_compile::alternate()), None); } #[cargo_test] fn per_crate_forced_target_does_not_get_overridden() { per_crate_target_test( None, Some(cross_compile::alternate()), Some(cross_compile::unused()), ); } #[cargo_test] fn workspace_with_multiple_targets() { if cross_compile::disabled() { return; } let p = project() .file( "Cargo.toml", r#" [workspace] members = ["native", "cross"] "#, ) .file( "native/Cargo.toml", r#" cargo-features = ["per-package-target"] [package] name = "native" version = "0.0.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "native/build.rs", &format!( r#" fn main() {{ assert_eq!(std::env::var("TARGET").unwrap(), "{}"); }} "#, cross_compile::native() ), ) .file( "native/src/main.rs", &format!( r#" use std::env; fn main() {{ assert_eq!(env::consts::ARCH, "{}"); }} "#, cross_compile::native_arch() ), ) .file( "cross/Cargo.toml", &format!( r#" cargo-features = ["per-package-target"] [package] name = "cross" version = "0.0.0" edition = "2015" authors = [] build = "build.rs" default-target = "{}" "#, cross_compile::alternate(), ), ) .file( "cross/build.rs", &format!( r#" fn main() {{ assert_eq!(std::env::var("TARGET").unwrap(), "{}"); }} "#, cross_compile::alternate() ), ) .file( "cross/src/main.rs", &format!( r#" use std::env; fn main() {{ assert_eq!(env::consts::ARCH, "{}"); }} "#, cross_compile::alternate_arch() ), ) .build(); let mut cmd = p.cargo("build -v"); cmd.masquerade_as_nightly_cargo(&["per-package-target"]) .run(); assert!(p.bin("native").is_file()); assert!(p.target_bin(cross_compile::alternate(), "cross").is_file()); p.process(&p.bin("native")).run(); if cross_compile::can_run_on_host() { p.process(&p.target_bin(cross_compile::alternate(), "cross")) .run(); } } #[cargo_test] fn linker() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let p = project() .file( ".cargo/config.toml", &format!( r#" [target.{}] linker = "my-linker-tool" "#, target ), ) .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/foo.rs", &format!( r#" use std::env; fn main() {{ assert_eq!(env::consts::ARCH, "{}"); }} "#, cross_compile::alternate_arch() ), ) .build(); p.cargo("build -v --target") .arg(&target) .with_status(101) .with_stderr_data(str![[r#" [WARNING] path `src/foo.rs` was erroneously implicitly accepted for binary `foo`, please set bin.path in Cargo.toml [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/foo.rs [..]--crate-type bin --emit=[..]link[..]-C debuginfo=2 [..] -C metadata=[..] --out-dir [ROOT]/foo/target/[ALT_TARGET]/debug/deps --target [ALT_TARGET] -C linker=my-linker-tool -L dependency=[ROOT]/foo/target/[ALT_TARGET]/debug/deps -L dependency=[ROOT]/foo/target/debug/deps` [ERROR] linker `my-linker-tool` not found ... "#]]) .run(); } #[cargo_test] fn cross_tests() { if !cross_compile::can_run_on_host() { return; } let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.0" edition = "2015" [[bin]] name = "bar" "#, ) .file( "src/bin/bar.rs", &format!( r#" #[allow(unused_extern_crates)] extern crate foo; use std::env; fn main() {{ assert_eq!(env::consts::ARCH, "{}"); }} #[test] fn test() {{ main() }} "#, cross_compile::alternate_arch() ), ) .file( "src/lib.rs", &format!( r#" use std::env; pub fn foo() {{ assert_eq!(env::consts::ARCH, "{}"); }} #[test] fn test_foo() {{ foo() }} "#, cross_compile::alternate_arch() ), ) .build(); let target = cross_compile::alternate(); p.cargo("test --target") .arg(&target) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/[ALT_TARGET]/debug/deps/foo-[HASH][EXE]) [RUNNING] unittests src/bin/bar.rs (target/[ALT_TARGET]/debug/deps/bar-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test test_foo ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn no_cross_doctests() { if cross_compile::disabled() { return; } let p = project() .file( "src/lib.rs", r#" //! ``` //! extern crate foo; //! assert!(true); //! ``` "#, ) .build(); let host_output = "\ [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "; println!("a"); p.cargo("test").with_stderr_data(host_output).run(); println!("b"); let target = rustc_host(); p.cargo("test -v --target") .arg(&target) // Unordered since the two `rustc` invocations happen concurrently. .with_stderr_data( str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]--crate-type lib[..] [RUNNING] `rustc --crate-name foo [..]--test[..] [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/[HOST_TARGET]/debug/deps/foo-[HASH][EXE]` [DOCTEST] foo [RUNNING] `rustdoc [..]--target [HOST_TARGET][..]` "#]] .unordered(), ) .with_stdout_data(str![[r#" running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test src/lib.rs - (line 2) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); println!("c"); let target = cross_compile::alternate(); // This will build the library, but does not build or run doc tests. // This should probably be a warning or error. p.cargo("test -v --doc --target") .arg(&target) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [NOTE] skipping doctests for foo v0.0.1 ([ROOT]/foo) (lib), cross-compilation doctests are not yet supported See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#doctest-xcompile for more information. "#]]) .run(); if !cross_compile::can_run_on_host() { return; } // This tests the library, but does not run the doc tests. p.cargo("test -v --target") .arg(&target) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]--test[..] [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/[ALT_TARGET]/debug/deps/foo-[HASH][EXE]` [NOTE] skipping doctests for foo v0.0.1 ([ROOT]/foo) (lib), cross-compilation doctests are not yet supported See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#doctest-xcompile for more information. "#]]) .run(); } #[cargo_test] fn simple_cargo_run() { if !cross_compile::can_run_on_host() { return; } let p = project() .file( "src/main.rs", &format!( r#" use std::env; fn main() {{ assert_eq!(env::consts::ARCH, "{}"); }} "#, cross_compile::alternate_arch() ), ) .build(); let target = cross_compile::alternate(); p.cargo("run --target").arg(&target).run(); } #[cargo_test] fn cross_with_a_build_script() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] build = 'build.rs' "#, ) .file( "build.rs", &format!( r#" use std::env; use std::path::PathBuf; fn main() {{ assert_eq!(env::var("TARGET").unwrap(), "{0}"); let mut path = PathBuf::from(env::var_os("OUT_DIR").unwrap()); assert_eq!(path.file_name().unwrap().to_str().unwrap(), "out"); path.pop(); assert!(path.file_name().unwrap().to_str().unwrap() .starts_with("foo-")); path.pop(); assert_eq!(path.file_name().unwrap().to_str().unwrap(), "build"); path.pop(); assert_eq!(path.file_name().unwrap().to_str().unwrap(), "debug"); path.pop(); assert_eq!(path.file_name().unwrap().to_str().unwrap(), "{0}"); path.pop(); assert_eq!(path.file_name().unwrap().to_str().unwrap(), "target"); }} "#, target ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v --target") .arg(&target) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.0 ([ROOT]/foo) [RUNNING] `rustc [..] build.rs [..] --out-dir [ROOT]/foo/target/debug/build/foo-[HASH] [..] [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc [..] src/main.rs [..] --target [ALT_TARGET] [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_script_needed_for_host_and_target() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] build = 'build.rs' [dependencies.d1] path = "d1" [build-dependencies.d2] path = "d2" "#, ) .file( "build.rs", r#" #[allow(unused_extern_crates)] extern crate d2; fn main() { d2::d2(); } "#, ) .file( "src/main.rs", " #[allow(unused_extern_crates)] extern crate d1; fn main() { d1::d1(); } ", ) .file( "d1/Cargo.toml", r#" [package] name = "d1" version = "0.0.0" edition = "2015" authors = [] build = 'build.rs' "#, ) .file("d1/src/lib.rs", "pub fn d1() {}") .file( "d1/build.rs", r#" use std::env; fn main() { let target = env::var("TARGET").unwrap(); println!("cargo::rustc-flags=-L /path/to/{}", target); } "#, ) .file( "d2/Cargo.toml", r#" [package] name = "d2" version = "0.0.0" edition = "2015" authors = [] [dependencies.d1] path = "../d1" "#, ) .file( "d2/src/lib.rs", " #[allow(unused_extern_crates)] extern crate d1; pub fn d2() { d1::d1(); } ", ) .build(); p.cargo("build -v --target") .arg(&target) .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] d1 v0.0.0 ([ROOT]/foo/d1) [RUNNING] `rustc [..] d1/build.rs [..] --out-dir [ROOT]/foo/target/debug/build/d1-[HASH] [..] [RUNNING] `[ROOT]/foo/target/debug/build/d1-[HASH]/build-script-build` [RUNNING] `[ROOT]/foo/target/debug/build/d1-[HASH]/build-script-build` [RUNNING] `rustc [..] d1/src/lib.rs [..] --out-dir [ROOT]/foo/target/debug/deps [..] [RUNNING] `rustc [..] d1/src/lib.rs [..] --out-dir [ROOT]/foo/target/[ALT_TARGET]/debug/deps [..] [COMPILING] d2 v0.0.0 ([ROOT]/foo/d2) [RUNNING] `rustc [..] d2/src/lib.rs [..] --out-dir [ROOT]/foo/target/debug/deps [..] [COMPILING] foo v0.0.0 ([ROOT]/foo) [RUNNING] `rustc [..] build.rs [..] --out-dir [ROOT]/foo/target/debug/build/foo-[HASH] [..] [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc [..] src/main.rs [..] --out-dir [ROOT]/foo/target/[ALT_TARGET]/debug/deps --target [ALT_TARGET] [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]].unordered()) .run(); } #[cargo_test] fn build_deps_for_the_right_arch() { if cross_compile::disabled() { return; } let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies.d2] path = "d2" "#, ) .file("src/main.rs", "extern crate d2; fn main() {}") .file("d1/Cargo.toml", &basic_manifest("d1", "0.0.0")) .file("d1/src/lib.rs", "pub fn d1() {}") .file( "d2/Cargo.toml", r#" [package] name = "d2" version = "0.0.0" edition = "2015" authors = [] build = "build.rs" [build-dependencies.d1] path = "../d1" "#, ) .file("d2/build.rs", "extern crate d1; fn main() {}") .file("d2/src/lib.rs", "") .build(); let target = cross_compile::alternate(); p.cargo("build -v --target").arg(&target).run(); } #[cargo_test] fn build_script_only_host() { if cross_compile::disabled() { return; } let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] build = "build.rs" [build-dependencies.d1] path = "d1" "#, ) .file("src/main.rs", "fn main() {}") .file("build.rs", "extern crate d1; fn main() {}") .file( "d1/Cargo.toml", r#" [package] name = "d1" version = "0.0.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("d1/src/lib.rs", "pub fn d1() {}") .file( "d1/build.rs", r#" use std::env; fn main() { assert!(env::var("OUT_DIR").unwrap().replace("\\", "/") .contains("target/debug/build/d1-"), "bad: {:?}", env::var("OUT_DIR")); } "#, ) .build(); let target = cross_compile::alternate(); p.cargo("build -v --target").arg(&target).run(); } #[cargo_test] fn build_script_with_platform_specific_dependencies() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let host = rustc_host(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" [build-dependencies.d1] path = "d1" "#, ) .file( "build.rs", " #[allow(unused_extern_crates)] extern crate d1; fn main() {} ", ) .file("src/lib.rs", "") .file( "d1/Cargo.toml", &format!( r#" [package] name = "d1" version = "0.0.0" edition = "2015" authors = [] [target.{}.dependencies] d2 = {{ path = "../d2" }} "#, host ), ) .file( "d1/src/lib.rs", "#[allow(unused_extern_crates)] extern crate d2;", ) .file("d2/Cargo.toml", &basic_manifest("d2", "0.0.0")) .file("d2/src/lib.rs", "") .build(); p.cargo("build -v --target") .arg(&target) .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] d2 v0.0.0 ([ROOT]/foo/d2) [RUNNING] `rustc [..] d2/src/lib.rs [..]` [COMPILING] d1 v0.0.0 ([ROOT]/foo/d1) [RUNNING] `rustc [..] d1/src/lib.rs [..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] build.rs [..]` [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc [..] src/lib.rs [..] --target [ALT_TARGET] [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn platform_specific_dependencies_do_not_leak() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let host = rustc_host(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" [dependencies.d1] path = "d1" [build-dependencies.d1] path = "d1" "#, ) .file("build.rs", "extern crate d1; fn main() {}") .file("src/lib.rs", "") .file( "d1/Cargo.toml", &format!( r#" [package] name = "d1" version = "0.0.0" edition = "2015" authors = [] [target.{}.dependencies] d2 = {{ path = "../d2" }} "#, host ), ) .file("d1/src/lib.rs", "extern crate d2;") .file("d1/Cargo.toml", &basic_manifest("d1", "0.0.0")) .file("d2/src/lib.rs", "") .build(); p.cargo("build -v --target") .arg(&target) .with_status(101) .with_stderr_data(str![[r#" ... error[E0463]: can't find crate for `d2` ... "#]]) .run(); } #[cargo_test] fn platform_specific_variables_reflected_in_build_scripts() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let host = rustc_host(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" [target.{host}.dependencies] d1 = {{ path = "d1" }} [target.{target}.dependencies] d2 = {{ path = "d2" }} "#, host = host, target = target ), ) .file( "build.rs", &format!( r#" use std::env; fn main() {{ let platform = env::var("TARGET").unwrap(); let (expected, not_expected) = match &platform[..] {{ "{host}" => ("DEP_D1_VAL", "DEP_D2_VAL"), "{target}" => ("DEP_D2_VAL", "DEP_D1_VAL"), _ => panic!("unknown platform") }}; env::var(expected).ok() .expect(&format!("missing {{}}", expected)); env::var(not_expected).err() .expect(&format!("found {{}}", not_expected)); }} "#, host = host, target = target ), ) .file("src/lib.rs", "") .file( "d1/Cargo.toml", r#" [package] name = "d1" version = "0.0.0" edition = "2015" authors = [] links = "d1" build = "build.rs" "#, ) .file( "d1/build.rs", r#"fn main() { println!("cargo::metadata=val=1") }"#, ) .file("d1/src/lib.rs", "") .file( "d2/Cargo.toml", r#" [package] name = "d2" version = "0.0.0" edition = "2015" authors = [] links = "d2" build = "build.rs" "#, ) .file( "d2/build.rs", r#"fn main() { println!("cargo::metadata=val=1") }"#, ) .file("d2/src/lib.rs", "") .build(); p.cargo("build -v").run(); p.cargo("build -v --target").arg(&target).run(); } #[cargo_test] #[cfg_attr( target_os = "macos", ignore = "don't have a dylib cross target on macos" )] fn cross_test_dylib() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] name = "foo" crate-type = ["dylib"] [dependencies.bar] path = "bar" "#, ) .file( "src/lib.rs", r#" extern crate bar as the_bar; pub fn bar() { the_bar::baz(); } #[test] fn foo() { bar(); } "#, ) .file( "tests/test.rs", r#" extern crate foo as the_foo; #[test] fn foo() { the_foo::bar(); } "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [lib] name = "bar" crate-type = ["dylib"] "#, ) .file( "bar/src/lib.rs", &format!( r#" use std::env; pub fn baz() {{ assert_eq!(env::consts::ARCH, "{}"); }} "#, cross_compile::alternate_arch() ), ) .build(); p.cargo("test --target") .arg(&target) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/[ALT_TARGET]/debug/deps/foo-[HASH][EXE]) [RUNNING] tests/test.rs (target/[ALT_TARGET]/debug/deps/test-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test foo ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test foo ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "-Zdoctest-xcompile is unstable")] fn doctest_xcompile_linker() { if cross_compile::disabled() { return; } let target = cross_compile::alternate(); let p = project() .file( ".cargo/config.toml", &format!( r#" [target.{}] linker = "my-linker-tool" "#, target ), ) .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file( "src/lib.rs", r#" /// ``` /// assert_eq!(1, 1); /// ``` pub fn foo() {} "#, ) .build(); // Fails because `my-linker-tool` doesn't actually exist. p.cargo("test --doc -v -Zdoctest-xcompile --target") .arg(&target) .with_status(101) .masquerade_as_nightly_cargo(&["doctest-xcompile"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..] --out-dir [ROOT]/foo/target/[ALT_TARGET]/debug/deps --target [ALT_TARGET] [..] [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [DOCTEST] foo [RUNNING] `rustdoc [..] src/lib.rs [..] [ERROR] doctest failed, to rerun pass `--doc` "#]]) .run(); } cargo-0.86.0/tests/testsuite/cross_publish.rs000064400000000000000000000065721046102023000174440ustar 00000000000000//! Tests for publishing using the `--target` flag. use std::fs::File; use cargo_test_support::prelude::*; use cargo_test_support::{cross_compile, project, publish, registry, str}; #[cargo_test] fn simple_cross_package() { if cross_compile::disabled() { return; } let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] license = "MIT" description = "foo" repository = "bar" "#, ) .file( "src/main.rs", &format!( r#" use std::env; fn main() {{ assert_eq!(env::consts::ARCH, "{}"); }} "#, cross_compile::alternate_arch() ), ) .build(); let target = cross_compile::alternate(); p.cargo("package --target") .arg(&target) .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.0 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.0 ([ROOT]/foo) [COMPILING] foo v0.0.0 ([ROOT]/foo/target/package/foo-0.0.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Check that the tarball contains the files let f = File::open(&p.root().join("target/package/foo-0.0.0.crate")).unwrap(); publish::validate_crate_contents( f, "foo-0.0.0.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], (), ); } #[cargo_test] fn publish_with_target() { if cross_compile::disabled() { return; } // `publish` generally requires a remote registry let registry = registry::RegistryBuilder::new().http_api().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] license = "MIT" description = "foo" repository = "bar" "#, ) .file( "src/main.rs", &format!( r#" use std::env; fn main() {{ assert_eq!(env::consts::ARCH, "{}"); }} "#, cross_compile::alternate_arch() ), ) .build(); let target = cross_compile::alternate(); p.cargo("publish") .replace_crates_io(registry.index_url()) .arg("--target") .arg(&target) .with_stderr_data(str![[r#" [UPDATING] crates.io index [PACKAGING] foo v0.0.0 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.0 ([ROOT]/foo) [COMPILING] foo v0.0.0 ([ROOT]/foo/target/package/foo-0.0.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.0 ([ROOT]/foo) [UPLOADED] foo v0.0.0 to registry `crates-io` [NOTE] waiting for `foo v0.0.0` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.0 at registry `crates-io` "#]]) .run(); } cargo-0.86.0/tests/testsuite/custom_target.rs000064400000000000000000000173161046102023000174430ustar 00000000000000//! Tests for custom json target specifications. use std::fs; use cargo_test_support::prelude::*; use cargo_test_support::{basic_manifest, project, str}; const MINIMAL_LIB: &str = r#" #![allow(internal_features)] #![feature(no_core)] #![feature(lang_items)] #![no_core] #[lang = "sized"] pub trait Sized { // Empty. } #[lang = "copy"] pub trait Copy { // Empty. } "#; const SIMPLE_SPEC: &str = r#" { "llvm-target": "x86_64-unknown-none-gnu", "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "arch": "x86_64", "target-endian": "little", "target-pointer-width": "64", "target-c-int-width": "32", "os": "none", "linker-flavor": "ld.lld", "linker": "rust-lld", "executables": true } "#; #[cargo_test(nightly, reason = "requires features no_core, lang_items")] fn custom_target_minimal() { let p = project() .file( "src/lib.rs", &" __MINIMAL_LIB__ pub fn foo() -> u32 { 42 } " .replace("__MINIMAL_LIB__", MINIMAL_LIB), ) .file("custom-target.json", SIMPLE_SPEC) .build(); p.cargo("build --lib --target custom-target.json -v").run(); p.cargo("build --lib --target src/../custom-target.json -v") .run(); // Ensure that the correct style of flag is passed to --target with doc tests. p.cargo("test --doc --target src/../custom-target.json -v -Zdoctest-xcompile") .masquerade_as_nightly_cargo(&["doctest-xcompile", "no_core", "lang_items"]) .with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [DOCTEST] foo [RUNNING] `rustdoc [..]--target [..]foo/custom-target.json[..] "#]]) .run(); } #[cargo_test(nightly, reason = "requires features no_core, lang_items, auto_traits")] fn custom_target_dependency() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = ["author@example.com"] [dependencies] bar = { path = "bar" } "#, ) .file( "src/lib.rs", r#" #![allow(internal_features)] #![feature(no_core)] #![feature(lang_items)] #![feature(auto_traits)] #![no_core] extern crate bar; pub fn foo() -> u32 { bar::bar() } #[lang = "freeze"] unsafe auto trait Freeze {} "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file( "bar/src/lib.rs", &" __MINIMAL_LIB__ pub fn bar() -> u32 { 42 } " .replace("__MINIMAL_LIB__", MINIMAL_LIB), ) .file("custom-target.json", SIMPLE_SPEC) .build(); p.cargo("build --lib --target custom-target.json -v").run(); } #[cargo_test(nightly, reason = "requires features no_core, lang_items")] // This is randomly crashing in lld. See https://github.com/rust-lang/rust/issues/115985 #[cfg_attr(all(windows, target_env = "gnu"), ignore = "windows-gnu lld crashing")] fn custom_bin_target() { let p = project() .file( "src/main.rs", &" #![no_main] __MINIMAL_LIB__ " .replace("__MINIMAL_LIB__", MINIMAL_LIB), ) .file("custom-bin-target.json", SIMPLE_SPEC) .build(); p.cargo("build --target custom-bin-target.json -v").run(); } #[cargo_test(nightly, reason = "requires features no_core, lang_items")] fn changing_spec_rebuilds() { // Changing the .json file will trigger a rebuild. let p = project() .file( "src/lib.rs", &" __MINIMAL_LIB__ pub fn foo() -> u32 { 42 } " .replace("__MINIMAL_LIB__", MINIMAL_LIB), ) .file("custom-target.json", SIMPLE_SPEC) .build(); p.cargo("build --lib --target custom-target.json -v").run(); p.cargo("build --lib --target custom-target.json -v") .with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let spec_path = p.root().join("custom-target.json"); let spec = fs::read_to_string(&spec_path).unwrap(); // Some arbitrary change that I hope is safe. let spec = spec.replace('{', "{\n\"vendor\": \"unknown\",\n"); fs::write(&spec_path, spec).unwrap(); p.cargo("build --lib --target custom-target.json -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires features no_core, lang_items")] // This is randomly crashing in lld. See https://github.com/rust-lang/rust/issues/115985 #[cfg_attr(all(windows, target_env = "gnu"), ignore = "windows-gnu lld crashing")] fn changing_spec_relearns_crate_types() { // Changing the .json file will invalidate the cache of crate types. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] crate-type = ["cdylib"] "#, ) .file("src/lib.rs", MINIMAL_LIB) .file("custom-target.json", SIMPLE_SPEC) .build(); p.cargo("build --lib --target custom-target.json -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot produce cdylib for `foo v0.1.0 ([ROOT]/foo)` [..] "#]]) .run(); // Enable dynamic linking. let spec_path = p.root().join("custom-target.json"); let spec = fs::read_to_string(&spec_path).unwrap(); let spec = spec.replace('{', "{\n\"dynamic-linking\": true,\n"); fs::write(&spec_path, spec).unwrap(); p.cargo("build --lib --target custom-target.json -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires features no_core, lang_items")] fn custom_target_ignores_filepath() { // Changing the path of the .json file will not trigger a rebuild. let p = project() .file( "src/lib.rs", &" __MINIMAL_LIB__ pub fn foo() -> u32 { 42 } " .replace("__MINIMAL_LIB__", MINIMAL_LIB), ) .file("b/custom-target.json", SIMPLE_SPEC) .file("a/custom-target.json", SIMPLE_SPEC) .build(); // Should build the library the first time. p.cargo("build --lib --target a/custom-target.json") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // But not the second time, even though the path to the custom target is dfferent. p.cargo("build --lib --target b/custom-target.json") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/death.rs000064400000000000000000000062721046102023000156470ustar 00000000000000//! Tests for ctrl-C handling. use std::fs; use std::io::{self, Read}; use std::net::TcpListener; use std::process::{Child, Stdio}; use std::thread; use cargo_test_support::prelude::*; use cargo_test_support::{project, slow_cpu_multiplier}; #[cargo_test] fn ctrl_c_kills_everyone() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = listener.local_addr().unwrap(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", &format!( r#" use std::net::TcpStream; use std::io::Read; fn main() {{ let mut socket = TcpStream::connect("{}").unwrap(); let _ = socket.read(&mut [0; 10]); panic!("that read should never return"); }} "#, addr ), ) .build(); let mut cargo = p.cargo("check").build_command(); cargo .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .env("__CARGO_TEST_SETSID_PLEASE_DONT_USE_ELSEWHERE", "1"); let mut child = cargo.spawn().unwrap(); let mut sock = listener.accept().unwrap().0; ctrl_c(&mut child); assert!(!child.wait().unwrap().success()); match sock.read(&mut [0; 10]) { Ok(n) => assert_eq!(n, 0), Err(e) => assert_eq!(e.kind(), io::ErrorKind::ConnectionReset), } // Ok so what we just did was spawn cargo that spawned a build script, then // we killed cargo in hopes of it killing the build script as well. If all // went well the build script is now dead. On Windows, however, this is // enforced with job objects which means that it may actually be in the // *process* of being torn down at this point. // // Now on Windows we can't completely remove a file until all handles to it // have been closed. Including those that represent running processes. So if // we were to return here then there may still be an open reference to some // file in the build directory. What we want to actually do is wait for the // build script to *complete* exit. Take care of that by blowing away the // build directory here, and panicking if we eventually spin too long // without being able to. for i in 0..10 { match fs::remove_dir_all(&p.root().join("target")) { Ok(()) => return, Err(e) => println!("attempt {}: {}", i, e), } thread::sleep(slow_cpu_multiplier(100)); } panic!( "couldn't remove build directory after a few tries, seems like \ we won't be able to!" ); } #[cfg(unix)] pub fn ctrl_c(child: &mut Child) { let r = unsafe { libc::kill(-(child.id() as i32), libc::SIGINT) }; if r < 0 { panic!("failed to kill: {}", io::Error::last_os_error()); } } #[cfg(windows)] pub fn ctrl_c(child: &mut Child) { child.kill().unwrap(); } cargo-0.86.0/tests/testsuite/dep_info.rs000064400000000000000000000344571046102023000163530ustar 00000000000000//! Tests for dep-info files. This includes the dep-info file Cargo creates in //! the output directory, and the ones stored in the fingerprint. use std::path::Path; use cargo_test_support::compare::assert_e2e; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::{assert_deps, assert_deps_contains}; use cargo_test_support::{basic_bin_manifest, basic_manifest, main_file, project, rustc_host}; use filetime::FileTime; #[cargo_test] fn build_dep_info() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("build").run(); let depinfo_bin_path = &p.bin("foo").with_extension("d"); assert!(depinfo_bin_path.is_file()); let depinfo = p.read_file(depinfo_bin_path); let bin_path = p.bin("foo"); let src_path = p.root().join("src").join("foo.rs"); if !depinfo.lines().any(|line| { line.starts_with(&format!("{}:", bin_path.display())) && line.contains(src_path.to_str().unwrap()) }) { panic!( "Could not find {:?}: {:?} in {:?}", bin_path, src_path, depinfo_bin_path ); } } #[cargo_test] fn build_dep_info_lib() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [[example]] name = "ex" crate-type = ["lib"] "#, ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "") .file("examples/ex.rs", "") .build(); p.cargo("build --example=ex").run(); assert!(p.example_lib("ex", "lib").with_extension("d").is_file()); } #[cargo_test] fn build_dep_info_rlib() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [[example]] name = "ex" crate-type = ["rlib"] "#, ) .file("src/lib.rs", "") .file("examples/ex.rs", "") .build(); p.cargo("build --example=ex").run(); assert!(p.example_lib("ex", "rlib").with_extension("d").is_file()); } #[cargo_test] fn build_dep_info_dylib() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [[example]] name = "ex" crate-type = ["dylib"] "#, ) .file("src/lib.rs", "") .file("examples/ex.rs", "") .build(); p.cargo("build --example=ex").run(); assert!(p.example_lib("ex", "dylib").with_extension("d").is_file()); } #[cargo_test] fn dep_path_inside_target_has_correct_path() { let p = project() .file("Cargo.toml", &basic_bin_manifest("a")) .file("target/debug/blah", "") .file( "src/main.rs", r#" fn main() { let x = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/target/debug/blah")); } "#, ) .build(); p.cargo("build").run(); let depinfo_path = &p.bin("a").with_extension("d"); assert!(depinfo_path.is_file(), "{:?}", depinfo_path); let depinfo = p.read_file(depinfo_path); let bin_path = p.bin("a"); let target_debug_blah = Path::new("target").join("debug").join("blah"); if !depinfo.lines().any(|line| { line.starts_with(&format!("{}:", bin_path.display())) && line.contains(target_debug_blah.to_str().unwrap()) }) { panic!( "Could not find {:?}: {:?} in {:?}", bin_path, target_debug_blah, depinfo_path ); } } #[cargo_test] fn no_rewrite_if_no_change() { let p = project().file("src/lib.rs", "").build(); p.cargo("build").run(); let dep_info = p.root().join("target/debug/libfoo.d"); let metadata1 = dep_info.metadata().unwrap(); p.cargo("build").run(); let metadata2 = dep_info.metadata().unwrap(); assert_eq!( FileTime::from_last_modification_time(&metadata1), FileTime::from_last_modification_time(&metadata2), ); } #[cargo_test(nightly, reason = "-Z binary-dep-depinfo is unstable")] fn relative_depinfo_paths_ws() { // Test relative dep-info paths in a workspace with --target with // proc-macros and other dependency kinds. Package::new("regdep", "0.1.0") .file("src/lib.rs", "pub fn f() {}") .publish(); Package::new("pmdep", "0.1.0") .file("src/lib.rs", "pub fn f() {}") .publish(); Package::new("bdep", "0.1.0") .file("src/lib.rs", "pub fn f() {}") .publish(); let p = project() /*********** Workspace ***********/ .file( "Cargo.toml", r#" [workspace] members = ["foo"] "#, ) /*********** Main Project ***********/ .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] pm = {path = "../pm"} bar = {path = "../bar"} regdep = "0.1" [build-dependencies] bdep = "0.1" bar = {path = "../bar"} "#, ) .file( "foo/src/main.rs", r#" pm::noop!{} fn main() { bar::f(); regdep::f(); } "#, ) .file("foo/build.rs", "fn main() { bdep::f(); }") /*********** Proc Macro ***********/ .file( "pm/Cargo.toml", r#" [package] name = "pm" version = "0.1.0" edition = "2018" [lib] proc-macro = true [dependencies] pmdep = "0.1" "#, ) .file( "pm/src/lib.rs", r#" extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro] pub fn noop(_item: TokenStream) -> TokenStream { pmdep::f(); "".parse().unwrap() } "#, ) /*********** Path Dependency `bar` ***********/ .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn f() {}") .build(); let host = rustc_host(); p.cargo("build -Z binary-dep-depinfo --target") .arg(&host) .masquerade_as_nightly_cargo(&["binary-dep-depinfo"]) .with_stderr_data(str![[r#" ... [COMPILING] foo v0.1.0 ([ROOT]/foo/foo) ... "#]]) .run(); assert_deps_contains( &p, "target/debug/.fingerprint/pm-*/dep-lib-pm", &[(0, "src/lib.rs"), (1, "debug/deps/libpmdep-*.rlib")], ); assert_deps_contains( &p, &format!("target/{}/debug/.fingerprint/foo-*/dep-bin-foo", host), &[ (0, "src/main.rs"), ( 1, &format!( "debug/deps/{}pm-*.{}", paths::get_lib_prefix("proc-macro"), paths::get_lib_extension("proc-macro") ), ), (1, &format!("{}/debug/deps/libbar-*.rlib", host)), (1, &format!("{}/debug/deps/libregdep-*.rlib", host)), ], ); assert_deps_contains( &p, "target/debug/.fingerprint/foo-*/dep-build-script-build-script-build", &[(0, "build.rs"), (1, "debug/deps/libbdep-*.rlib")], ); // Make sure it stays fresh. p.cargo("build -Z binary-dep-depinfo --target") .arg(&host) .masquerade_as_nightly_cargo(&["binary-dep-depinfo"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "-Z binary-dep-depinfo is unstable")] fn relative_depinfo_paths_no_ws() { // Test relative dep-info paths without a workspace with proc-macros and // other dependency kinds. Package::new("regdep", "0.1.0") .file("src/lib.rs", "pub fn f() {}") .publish(); Package::new("pmdep", "0.1.0") .file("src/lib.rs", "pub fn f() {}") .publish(); Package::new("bdep", "0.1.0") .file("src/lib.rs", "pub fn f() {}") .publish(); let p = project() /*********** Main Project ***********/ .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] pm = {path = "pm"} bar = {path = "bar"} regdep = "0.1" [build-dependencies] bdep = "0.1" bar = {path = "bar"} "#, ) .file( "src/main.rs", r#" pm::noop!{} fn main() { bar::f(); regdep::f(); } "#, ) .file("build.rs", "fn main() { bdep::f(); }") /*********** Proc Macro ***********/ .file( "pm/Cargo.toml", r#" [package] name = "pm" version = "0.1.0" edition = "2018" [lib] proc-macro = true [dependencies] pmdep = "0.1" "#, ) .file( "pm/src/lib.rs", r#" extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro] pub fn noop(_item: TokenStream) -> TokenStream { pmdep::f(); "".parse().unwrap() } "#, ) /*********** Path Dependency `bar` ***********/ .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn f() {}") .build(); p.cargo("build -Z binary-dep-depinfo") .masquerade_as_nightly_cargo(&["binary-dep-depinfo"]) .with_stderr_data(str![[r#" ... [COMPILING] foo v0.1.0 ([ROOT]/foo) ... "#]]) .run(); assert_deps_contains( &p, "target/debug/.fingerprint/pm-*/dep-lib-pm", &[(0, "src/lib.rs"), (1, "debug/deps/libpmdep-*.rlib")], ); assert_deps_contains( &p, "target/debug/.fingerprint/foo-*/dep-bin-foo", &[ (0, "src/main.rs"), ( 1, &format!( "debug/deps/{}pm-*.{}", paths::get_lib_prefix("proc-macro"), paths::get_lib_extension("proc-macro") ), ), (1, "debug/deps/libbar-*.rlib"), (1, "debug/deps/libregdep-*.rlib"), ], ); assert_deps_contains( &p, "target/debug/.fingerprint/foo-*/dep-build-script-build-script-build", &[(0, "build.rs"), (1, "debug/deps/libbdep-*.rlib")], ); // Make sure it stays fresh. p.cargo("build -Z binary-dep-depinfo") .masquerade_as_nightly_cargo(&["binary-dep-depinfo"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn reg_dep_source_not_tracked() { // Make sure source files in dep-info file are not tracked for registry dependencies. Package::new("regdep", "0.1.0") .file("src/lib.rs", "pub fn f() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] regdep = "0.1" "#, ) .file("src/lib.rs", "pub fn f() { regdep::f(); }") .build(); p.cargo("check").run(); assert_deps( &p, "target/debug/.fingerprint/regdep-*/dep-lib-regdep", |info_path, entries| { for (kind, path) in entries { if *kind == 1 { panic!( "Did not expect package root relative path type: {:?} in {:?}", path, info_path ); } } }, ); } #[cargo_test(nightly, reason = "-Z binary-dep-depinfo is unstable")] fn canonical_path() { if !cargo_test_support::symlink_supported() { return; } Package::new("regdep", "0.1.0") .file("src/lib.rs", "pub fn f() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] regdep = "0.1" "#, ) .file("src/lib.rs", "pub fn f() { regdep::f(); }") .build(); let real = p.root().join("real_target"); real.mkdir_p(); p.symlink(real, "target"); p.cargo("check -Z binary-dep-depinfo") .masquerade_as_nightly_cargo(&["binary-dep-depinfo"]) .run(); assert_deps_contains( &p, "target/debug/.fingerprint/foo-*/dep-lib-foo", &[(0, "src/lib.rs"), (1, "debug/deps/libregdep-*.rmeta")], ); } #[cargo_test] fn non_local_build_script() { // Non-local build script information is not included. Package::new("bar", "1.0.0") .file( "build.rs", r#" fn main() { println!("cargo::rerun-if-changed=build.rs"); } "#, ) .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = "1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build").run(); let contents = p.read_file("target/debug/foo.d"); assert_e2e().eq( &contents, str![[r#" [ROOT]/foo/target/debug/foo[EXE]: [ROOT]/foo/src/main.rs "#]], ); } cargo-0.86.0/tests/testsuite/diagnostics.rs000064400000000000000000000010721046102023000170620ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; #[cargo_test] fn dont_panic_on_render() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2021" [[bench.foo]] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid type: map, expected a sequence --> Cargo.toml:6:3 | 6 | [[bench.foo]] | ^^^^^ | "#]]) .run(); } cargo-0.86.0/tests/testsuite/direct_minimal_versions.rs000064400000000000000000000150621046102023000214670ustar 00000000000000//! Tests for minimal-version resolution. //! //! Note: Some tests are located in the resolver-tests package. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry::Package; use cargo_test_support::str; #[cargo_test] fn simple() { Package::new("dep", "1.0.0").publish(); Package::new("dep", "1.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" [dependencies] dep = "1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("generate-lockfile -Zdirect-minimal-versions") .masquerade_as_nightly_cargo(&["direct-minimal-versions"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package [ADDING] dep v1.0.0 (available: v1.1.0) "#]]) .run(); let lock = p.read_lockfile(); assert!( lock.contains("1.0.0"), "dep minimal version must be present" ); assert!( !lock.contains("1.1.0"), "dep maximimal version cannot be present" ); } #[cargo_test] fn mixed_dependencies() { Package::new("dep", "1.0.0").publish(); Package::new("dep", "1.1.0").publish(); Package::new("dep", "1.2.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" [dependencies] dep = "1.0" [dev-dependencies] dep = "1.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("generate-lockfile -Zdirect-minimal-versions") .masquerade_as_nightly_cargo(&["direct-minimal-versions"]) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for `dep`. ... required by package `foo v0.0.1 ([ROOT]/foo)` versions that meet the requirements `^1.1` are: 1.1.0 all possible versions conflict with previously selected packages. previously selected package `dep v1.0.0` ... which satisfies dependency `dep = "^1.0"` of package `foo v0.0.1 ([ROOT]/foo)` failed to select a version for `dep` which could resolve this conflict "#]]) .run(); } #[cargo_test] fn yanked() { Package::new("dep", "1.0.0").yanked(true).publish(); Package::new("dep", "1.1.0").publish(); Package::new("dep", "1.2.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" [dependencies] dep = "1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("generate-lockfile -Zdirect-minimal-versions") .masquerade_as_nightly_cargo(&["direct-minimal-versions"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package [ADDING] dep v1.1.0 (available: v1.2.0) "#]]) .run(); let lock = p.read_lockfile(); assert!( lock.contains("1.1.0"), "dep minimal version must be present" ); assert!( !lock.contains("1.0.0"), "yanked minimal version must be skipped" ); assert!( !lock.contains("1.2.0"), "dep maximimal version cannot be present" ); } #[cargo_test] fn indirect() { Package::new("indirect", "2.0.0").publish(); Package::new("indirect", "2.1.0").publish(); Package::new("indirect", "2.2.0").publish(); Package::new("direct", "1.0.0") .dep("indirect", "2.1") .publish(); Package::new("direct", "1.1.0") .dep("indirect", "2.1") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" [dependencies] direct = "1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("generate-lockfile -Zdirect-minimal-versions") .masquerade_as_nightly_cargo(&["direct-minimal-versions"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages [ADDING] direct v1.0.0 (available: v1.1.0) "#]]) .run(); let lock = p.read_lockfile(); assert!( lock.contains("1.0.0"), "direct minimal version must be present" ); assert!( !lock.contains("1.1.0"), "direct maximimal version cannot be present" ); assert!( !lock.contains("2.0.0"), "indirect minimal version cannot be present" ); assert!( !lock.contains("2.1.0"), "indirect minimal version cannot be present" ); assert!( lock.contains("2.2.0"), "indirect maximal version must be present" ); } #[cargo_test] fn indirect_conflict() { Package::new("indirect", "2.0.0").publish(); Package::new("indirect", "2.1.0").publish(); Package::new("indirect", "2.2.0").publish(); Package::new("direct", "1.0.0") .dep("indirect", "2.1") .publish(); Package::new("direct", "1.1.0") .dep("indirect", "2.1") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" [dependencies] direct = "1.0" indirect = "2.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("generate-lockfile -Zdirect-minimal-versions") .masquerade_as_nightly_cargo(&["direct-minimal-versions"]) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for `indirect`. ... required by package `direct v1.0.0` ... which satisfies dependency `direct = "^1.0"` of package `foo v0.0.1 ([ROOT]/foo)` versions that meet the requirements `^2.1` are: 2.2.0, 2.1.0 all possible versions conflict with previously selected packages. previously selected package `indirect v2.0.0` ... which satisfies dependency `indirect = "^2.0"` of package `foo v0.0.1 ([ROOT]/foo)` failed to select a version for `indirect` which could resolve this conflict "#]]) .run(); } cargo-0.86.0/tests/testsuite/directory.rs000064400000000000000000000521111046102023000165570ustar 00000000000000//! Tests for directory sources. use std::collections::HashMap; use std::fs; use std::str; use cargo_test_support::cargo_process; use cargo_test_support::git; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::{cksum, Package}; use cargo_test_support::str; use cargo_test_support::{basic_manifest, project, t, ProjectBuilder}; use serde::Serialize; fn setup() { let root = paths::root(); t!(fs::create_dir(&root.join(".cargo"))); t!(fs::write( root.join(".cargo/config.toml"), r#" [source.crates-io] replace-with = 'my-awesome-local-registry' [source.my-awesome-local-registry] directory = 'index' "# )); } struct VendorPackage { p: Option, cksum: Checksum, } #[derive(Serialize)] struct Checksum { package: Option, files: HashMap, } impl VendorPackage { fn new(name: &str) -> VendorPackage { VendorPackage { p: Some(project().at(&format!("index/{}", name))), cksum: Checksum { package: Some(String::new()), files: HashMap::new(), }, } } fn file(&mut self, name: &str, contents: &str) -> &mut VendorPackage { self.p = Some(self.p.take().unwrap().file(name, contents)); self.cksum .files .insert(name.to_string(), cksum(contents.as_bytes())); self } fn disable_checksum(&mut self) -> &mut VendorPackage { self.cksum.package = None; self } fn no_manifest(mut self) -> Self { self.p = self.p.map(|pb| pb.no_manifest()); self } fn build(&mut self) { let p = self.p.take().unwrap(); let json = serde_json::to_string(&self.cksum).unwrap(); let p = p.file(".cargo-checksum.json", &json); let _ = p.build(); } } #[cargo_test] fn simple() { setup(); VendorPackage::new("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn bar() {}") .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn simple_install() { setup(); VendorPackage::new("foo") .file("src/lib.rs", "pub fn foo() {}") .build(); VendorPackage::new("bar") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] foo = "0.0.1" "#, ) .file( "src/main.rs", "extern crate foo; pub fn main() { foo::foo(); }", ) .build(); cargo_process("install bar") .with_stderr_data(str![[r#" [INSTALLING] bar v0.1.0 [LOCKING] 1 package to latest compatible version [COMPILING] foo v0.0.1 [COMPILING] bar v0.1.0 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [..]bar[..] [INSTALLED] package `bar v0.1.0` (executable `bar[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); } #[cargo_test] fn simple_install_fail() { setup(); VendorPackage::new("foo") .file("src/lib.rs", "pub fn foo() {}") .build(); VendorPackage::new("bar") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] foo = "0.1.0" baz = "9.8.7" "#, ) .file( "src/main.rs", "extern crate foo; pub fn main() { foo::foo(); }", ) .build(); cargo_process("install bar") .with_status(101) .with_stderr_data(str![[r#" [INSTALLING] bar v0.1.0 [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 searched package name: `baz` perhaps you meant: bar or foo location searched: directory source `[ROOT]/index` (which is replacing registry `crates-io`) required by package `bar v0.1.0` "#]]) .run(); } #[cargo_test] fn install_without_feature_dep() { setup(); VendorPackage::new("foo") .file("src/lib.rs", "pub fn foo() {}") .build(); VendorPackage::new("bar") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] foo = "0.0.1" baz = { version = "9.8.7", optional = true } [features] wantbaz = ["baz"] "#, ) .file( "src/main.rs", "extern crate foo; pub fn main() { foo::foo(); }", ) .build(); cargo_process("install bar") .with_stderr_data(str![[r#" [INSTALLING] bar v0.1.0 [LOCKING] 1 package to latest compatible version [COMPILING] foo v0.0.1 [COMPILING] bar v0.1.0 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [..]bar[..] [INSTALLED] package `bar v0.1.0` (executable `bar[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); } #[cargo_test] fn not_there() { setup(); let _ = project().at("index").build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no matching package named `bar` found location searched: directory source `[ROOT]/index` (which is replacing registry `crates-io`) required by package `foo v0.1.0 ([ROOT]/foo)` "#]]) .run(); } #[cargo_test] fn multiple() { setup(); VendorPackage::new("bar-0.1.0") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn bar() {}") .file(".cargo-checksum", "") .build(); VendorPackage::new("bar-0.2.0") .file("Cargo.toml", &basic_manifest("bar", "0.2.0")) .file("src/lib.rs", "pub fn bar() {}") .file(".cargo-checksum", "") .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [ADDING] bar v0.1.0 (available: v0.2.0) [CHECKING] bar v0.1.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn crates_io_then_directory() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); let cksum = Package::new("bar", "0.1.0") .file("src/lib.rs", "pub fn bar() -> u32 { 0 }") .publish(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [CHECKING] bar v0.1.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); setup(); let mut v = VendorPackage::new("bar"); v.file("Cargo.toml", &basic_manifest("bar", "0.1.0")); v.file("src/lib.rs", "pub fn bar() -> u32 { 1 }"); v.cksum.package = Some(cksum); v.build(); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] bar v0.1.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn crates_io_then_bad_checksum() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .build(); Package::new("bar", "0.1.0").publish(); p.cargo("check").run(); setup(); VendorPackage::new("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] checksum for `bar v0.1.0` changed between lock files this could be indicative of a few possible errors: * the lock file is corrupt * a replacement source in use (e.g., a mirror) returned a different checksum * the source itself may be corrupt in one way or another unable to verify that `bar v0.1.0` is the same as when the lockfile was generated "#]]) .run(); } #[cargo_test] fn bad_file_checksum() { setup(); VendorPackage::new("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "") .build(); t!(fs::write( paths::root().join("index/bar/src/lib.rs"), "fn bar() -> u32 { 0 }" )); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [ERROR] the listed checksum of `[ROOT]/index/bar/src/lib.rs` has changed: expected: [..] actual: [..] directory sources are not intended to be edited, if modifications are required then it is recommended that `[patch]` is used with a forked copy of the source "#]]) .run(); } #[cargo_test] fn only_dot_files_ok() { setup(); VendorPackage::new("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "") .build(); VendorPackage::new("foo") .no_manifest() .file(".bar", "") .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); } #[cargo_test] fn random_files_ok() { setup(); VendorPackage::new("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "") .build(); VendorPackage::new("foo") .no_manifest() .file("bar", "") .file("../test", "") .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); } #[cargo_test] fn git_lock_file_doesnt_change() { let git = git::new("git", |p| { p.file("Cargo.toml", &basic_manifest("git", "0.5.0")) .file("src/lib.rs", "") }); VendorPackage::new("git") .file("Cargo.toml", &basic_manifest("git", "0.5.0")) .file("src/lib.rs", "") .disable_checksum() .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] git = {{ git = '{0}' }} "#, git.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); let lock1 = p.read_lockfile(); let root = paths::root(); t!(fs::create_dir(&root.join(".cargo"))); t!(fs::write( root.join(".cargo/config.toml"), format!( r#" [source.my-git-repo] git = '{}' replace-with = 'my-awesome-local-registry' [source.my-awesome-local-registry] directory = 'index' "#, git.url() ) )); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] git v0.5.0 ([..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let lock2 = p.read_lockfile(); assert_eq!(lock1, lock2, "lock files changed"); } #[cargo_test] fn git_override_requires_lockfile() { VendorPackage::new("git") .file("Cargo.toml", &basic_manifest("git", "0.5.0")) .file("src/lib.rs", "") .disable_checksum() .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] git = { git = 'https://example.com/' } "#, ) .file("src/lib.rs", "") .build(); let root = paths::root(); t!(fs::create_dir(&root.join(".cargo"))); t!(fs::write( root.join(".cargo/config.toml"), r#" [source.my-git-repo] git = 'https://example.com/' replace-with = 'my-awesome-local-registry' [source.my-awesome-local-registry] directory = 'index' "# )); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to get `git` as a dependency of package `foo v0.0.1 ([ROOT]/foo)` Caused by: failed to load source for dependency `git` Caused by: Unable to update [..] Caused by: the source my-git-repo requires a lock file to be present first before it can be used against vendored source code remove the source replacement configuration, generate a lock file, and then restore the source replacement configuration to continue the build "#]]) .run(); } #[cargo_test] fn workspace_different_locations() { let p = project() .no_manifest() .file( "foo/Cargo.toml", r#" [package] name = 'foo' version = '0.1.0' edition = "2015" [dependencies] baz = "*" "#, ) .file("foo/src/lib.rs", "") .file("foo/vendor/baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("foo/vendor/baz/src/lib.rs", "") .file("foo/vendor/baz/.cargo-checksum.json", "{\"files\":{}}") .file( "bar/Cargo.toml", r#" [package] name = 'bar' version = '0.1.0' edition = "2015" [dependencies] baz = "*" "#, ) .file("bar/src/lib.rs", "") .file( ".cargo/config.toml", r#" [build] target-dir = './target' [source.crates-io] replace-with = 'my-awesome-local-registry' [source.my-awesome-local-registry] directory = 'foo/vendor' "#, ) .build(); p.cargo("check").cwd("foo").run(); p.cargo("check") .cwd("bar") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn version_missing() { setup(); VendorPackage::new("foo") .file("src/lib.rs", "pub fn foo() {}") .build(); VendorPackage::new("bar") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] foo = "2" "#, ) .file("src/main.rs", "fn main() {}") .build(); cargo_process("install bar") .with_stderr_data(str![[r#" [INSTALLING] bar v0.1.0 [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"` candidate versions found which didn't match: 0.0.1 location searched: directory source `[..] (which is replacing registry `[..]`) required by package `bar v0.1.0` perhaps a crate was updated and forgotten to be re-vendored? "#]]) .with_status(101) .run(); } #[cargo_test] fn root_dir_diagnostics() { let p = ProjectBuilder::new(paths::root()) .no_manifest() // we are placing it in a different dir .file( "ws_root/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] "#, ) .file("ws_root/src/lib.rs", "invalid;") .build(); // Crucially, the rustc error message below says `ws_root/...`, i.e. // it is relative to our fake home, not to the workspace root. p.cargo("check") .arg("-Zroot-dir=.") .arg("--manifest-path=ws_root/Cargo.toml") .masquerade_as_nightly_cargo(&["-Zroot-dir"]) .with_status(101) .with_stderr_data(str![[r#" [CHECKING] foo v0.1.0 ([ROOT]/ws_root) [ERROR] [..] --> ws_root/src/lib.rs:1:8 | 1 | invalid; | [..] [ERROR] could not compile `foo` (lib) due to 1 previous error "#]]) .run(); } #[cargo_test] fn root_dir_file_macro() { let p = ProjectBuilder::new(paths::root()) .no_manifest() // we are placing it in a different dir .file( "ws_root/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] "#, ) .file( "ws_root/src/main.rs", r#"fn main() { println!("{}", file!()); }"#, ) .build(); // Crucially, the path is relative to our fake home, not to the workspace root. p.cargo("run") .arg("-Zroot-dir=.") .arg("--manifest-path=ws_root/Cargo.toml") .masquerade_as_nightly_cargo(&["-Zroot-dir"]) .with_stdout_data(str![[r#" ws_root/src/main.rs "#]]) .run(); // Try again with an absolute path for `root-dir`. p.cargo("run") .arg(format!("-Zroot-dir={}", p.root().display())) .arg("--manifest-path=ws_root/Cargo.toml") .masquerade_as_nightly_cargo(&["-Zroot-dir"]) .with_stdout_data(str![[r#" ws_root/src/main.rs "#]]) .run(); } cargo-0.86.0/tests/testsuite/doc.rs000064400000000000000000002301731046102023000153260ustar 00000000000000//! Tests for the `cargo doc` command. use std::fs; use std::str; use cargo::core::compiler::RustDocFingerprint; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::{basic_lib_manifest, basic_manifest, git, project}; use cargo_test_support::{rustc_host, symlink_supported, tools}; #[cargo_test] fn simple() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "pub fn foo() {}") .build(); p.cargo("doc") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); assert!(p.root().join("target/doc").is_dir()); assert!(p.root().join("target/doc/foo/index.html").is_file()); } #[cargo_test] fn doc_no_libs() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[bin]] name = "foo" doc = false "#, ) .file("src/main.rs", "bad code") .build(); p.cargo("doc").run(); } #[cargo_test] fn doc_twice() { let p = project().file("src/lib.rs", "pub fn foo() {}").build(); p.cargo("doc") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); p.cargo("doc") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); } #[cargo_test] fn doc_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" "#, ) .file("src/lib.rs", "extern crate bar; pub fn foo() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("doc") .with_stderr_data( str![[r#" [LOCKING] 1 package to latest compatible version [DOCUMENTING] bar v0.0.1 ([ROOT]/foo/bar) [CHECKING] bar v0.0.1 ([ROOT]/foo/bar) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]] .unordered(), ) .run(); assert!(p.root().join("target/doc").is_dir()); assert!(p.root().join("target/doc/foo/index.html").is_file()); assert!(p.root().join("target/doc/bar/index.html").is_file()); // Verify that it only emits rmeta for the dependency. assert_eq!(p.glob("target/debug/**/*.rlib").count(), 0); assert_eq!(p.glob("target/debug/deps/libbar-*.rmeta").count(), 1); // Make sure it doesn't recompile. p.cargo("doc") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); assert!(p.root().join("target/doc").is_dir()); assert!(p.root().join("target/doc/foo/index.html").is_file()); assert!(p.root().join("target/doc/bar/index.html").is_file()); } #[cargo_test] fn doc_no_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" "#, ) .file("src/lib.rs", "extern crate bar; pub fn foo() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("doc --no-deps") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.0.1 ([ROOT]/foo/bar) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); assert!(p.root().join("target/doc").is_dir()); assert!(p.root().join("target/doc/foo/index.html").is_file()); assert!(!p.root().join("target/doc/bar/index.html").is_file()); } #[cargo_test] fn doc_only_bin() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" "#, ) .file("src/main.rs", "extern crate bar; pub fn foo() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("doc -v").run(); assert!(p.root().join("target/doc").is_dir()); assert!(p.root().join("target/doc/bar/index.html").is_file()); assert!(p.root().join("target/doc/foo/index.html").is_file()); } #[cargo_test] fn doc_multiple_targets_same_name_lib() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo", "bar"] "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] name = "foo_lib" "#, ) .file("foo/src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [lib] name = "foo_lib" "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("doc --workspace") .with_status(101) .with_stderr_data(str![[r#" [ERROR] document output filename collision The lib `foo_lib` in package `foo v0.1.0 ([ROOT]/foo/foo)` has the same name as the lib `foo_lib` in package `bar v0.1.0 ([ROOT]/foo/bar)`. Only one may be documented at once since they output to the same path. Consider documenting only one, renaming one, or marking one with `doc = false` in Cargo.toml. "#]]) .run(); } #[cargo_test] fn doc_multiple_targets_same_name() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo", "bar"] "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [[bin]] name = "foo_lib" path = "src/foo_lib.rs" "#, ) .file("foo/src/foo_lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [lib] name = "foo_lib" "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("doc --workspace") .with_stderr_data(str![[r#" [WARNING] output filename collision. The bin target `foo_lib` in package `foo v0.1.0 ([ROOT]/foo/foo)` has the same output filename as the lib target `foo_lib` in package `bar v0.1.0 ([ROOT]/foo/bar)`. Colliding filename is: [ROOT]/foo/target/doc/foo_lib/index.html The targets should have unique names. This is a known bug where multiple crates with the same name use the same path; see . [DOCUMENTING] bar v0.1.0 ([ROOT]/foo/bar) [DOCUMENTING] foo v0.1.0 ([ROOT]/foo/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo_lib/index.html and 1 other file "#]].unordered()) .run(); } #[cargo_test] fn doc_multiple_targets_same_name_bin() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo", "bar"] "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file("foo/src/bin/foo-cli.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" "#, ) .file("bar/src/bin/foo-cli.rs", "") .build(); p.cargo("doc --workspace") .with_status(101) .with_stderr_data(str![[r#" [ERROR] document output filename collision The bin `foo-cli` in package `foo v0.1.0 ([ROOT]/foo/foo)` has the same name as the bin `foo-cli` in package `bar v0.1.0 ([ROOT]/foo/bar)`. Only one may be documented at once since they output to the same path. Consider documenting only one, renaming one, or marking one with `doc = false` in Cargo.toml. "#]]) .run(); } #[cargo_test] fn doc_multiple_targets_same_name_undoced() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo", "bar"] "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [[bin]] name = "foo-cli" "#, ) .file("foo/src/foo-cli.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [[bin]] name = "foo-cli" doc = false "#, ) .file("bar/src/foo-cli.rs", "") .build(); p.cargo("doc --workspace").run(); } #[cargo_test] fn doc_lib_bin_same_name_documents_lib() { let p = project() .file( "src/main.rs", r#" //! Binary documentation extern crate foo; fn main() { foo::foo(); } "#, ) .file( "src/lib.rs", r#" //! Library documentation pub fn foo() {} "#, ) .build(); p.cargo("doc") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); let doc_html = p.read_file("target/doc/foo/index.html"); assert!(doc_html.contains("Library")); assert!(!doc_html.contains("Binary")); } #[cargo_test] fn doc_lib_bin_same_name_documents_lib_when_requested() { let p = project() .file( "src/main.rs", r#" //! Binary documentation extern crate foo; fn main() { foo::foo(); } "#, ) .file( "src/lib.rs", r#" //! Library documentation pub fn foo() {} "#, ) .build(); p.cargo("doc --lib") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); let doc_html = p.read_file("target/doc/foo/index.html"); assert!(doc_html.contains("Library")); assert!(!doc_html.contains("Binary")); } #[cargo_test] fn doc_lib_bin_same_name_with_dash() { // Checks `doc` behavior when there is a dash in the package name, and // there is a lib and bin, and the lib name is inferred. let p = project() .file("Cargo.toml", &basic_manifest("foo-bar", "1.0.0")) .file("src/lib.rs", "") .file("src/main.rs", "fn main() {}") .build(); p.cargo("doc") .with_stderr_data(str![[r#" [DOCUMENTING] foo-bar v1.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo_bar/index.html "#]]) .run(); assert!(p.build_dir().join("doc/foo_bar/index.html").exists()); assert!(!p.build_dir().join("doc/foo_bar/fn.main.html").exists()); } #[cargo_test] fn doc_lib_bin_same_name_documents_named_bin_when_requested() { let p = project() .file( "src/main.rs", r#" //! Binary documentation extern crate foo; fn main() { foo::foo(); } "#, ) .file( "src/lib.rs", r#" //! Library documentation pub fn foo() {} "#, ) .build(); p.cargo("doc --bin foo") // The checking/documenting lines are sometimes swapped since they run // concurrently. .with_stderr_data(str![[r#" [WARNING] output filename collision. The bin target `foo` in package `foo v0.0.1 ([ROOT]/foo)` has the same output filename as the lib target `foo` in package `foo v0.0.1 ([ROOT]/foo)`. Colliding filename is: [ROOT]/foo/target/doc/foo/index.html The targets should have unique names. This is a known bug where multiple crates with the same name use the same path; see . [CHECKING] foo v0.0.1 ([ROOT]/foo) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]].unordered()) .run(); let doc_html = p.read_file("target/doc/foo/index.html"); assert!(!doc_html.contains("Library")); assert!(doc_html.contains("Binary")); } #[cargo_test] fn doc_lib_bin_same_name_documents_bins_when_requested() { let p = project() .file( "src/main.rs", r#" //! Binary documentation extern crate foo; fn main() { foo::foo(); } "#, ) .file( "src/lib.rs", r#" //! Library documentation pub fn foo() {} "#, ) .build(); p.cargo("doc --bins") // The checking/documenting lines are sometimes swapped since they run // concurrently. .with_stderr_data(str![[r#" [WARNING] output filename collision. The bin target `foo` in package `foo v0.0.1 ([ROOT]/foo)` has the same output filename as the lib target `foo` in package `foo v0.0.1 ([ROOT]/foo)`. Colliding filename is: [ROOT]/foo/target/doc/foo/index.html The targets should have unique names. This is a known bug where multiple crates with the same name use the same path; see . [CHECKING] foo v0.0.1 ([ROOT]/foo) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]].unordered()) .run(); let doc_html = p.read_file("target/doc/foo/index.html"); assert!(!doc_html.contains("Library")); assert!(doc_html.contains("Binary")); } #[cargo_test] fn doc_lib_bin_example_same_name_documents_named_example_when_requested() { let p = project() .file( "src/main.rs", r#" //! Binary documentation extern crate foo; fn main() { foo::foo(); } "#, ) .file( "src/lib.rs", r#" //! Library documentation pub fn foo() {} "#, ) .file( "examples/ex1.rs", r#" //! Example1 documentation pub fn x() { f(); } "#, ) .build(); p.cargo("doc --example ex1") // The checking/documenting lines are sometimes swapped since they run // concurrently. .with_stderr_data( str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/ex1/index.html "#]] .unordered(), ) .run(); let doc_html = p.read_file("target/doc/ex1/index.html"); assert!(!doc_html.contains("Library")); assert!(!doc_html.contains("Binary")); assert!(doc_html.contains("Example1")); } #[cargo_test] fn doc_lib_bin_example_same_name_documents_examples_when_requested() { let p = project() .file( "src/main.rs", r#" //! Binary documentation extern crate foo; fn main() { foo::foo(); } "#, ) .file( "src/lib.rs", r#" //! Library documentation pub fn foo() {} "#, ) .file( "examples/ex1.rs", r#" //! Example1 documentation pub fn example1() { f(); } "#, ) .file( "examples/ex2.rs", r#" //! Example2 documentation pub fn example2() { f(); } "#, ) .build(); p.cargo("doc --examples") // The checking/documenting lines are sometimes swapped since they run // concurrently. .with_stderr_data( str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/ex1/index.html and 1 other file "#]] .unordered(), ) .run(); let example_doc_html_1 = p.read_file("target/doc/ex1/index.html"); let example_doc_html_2 = p.read_file("target/doc/ex2/index.html"); assert!(!example_doc_html_1.contains("Library")); assert!(!example_doc_html_1.contains("Binary")); assert!(!example_doc_html_2.contains("Library")); assert!(!example_doc_html_2.contains("Binary")); assert!(example_doc_html_1.contains("Example1")); assert!(example_doc_html_2.contains("Example2")); } #[cargo_test] fn doc_dash_p() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.a] path = "a" "#, ) .file("src/lib.rs", "extern crate a;") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [dependencies.b] path = "../b" "#, ) .file("a/src/lib.rs", "extern crate b;") .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/lib.rs", "") .build(); p.cargo("doc -p a") .with_stderr_data( str![[r#" [LOCKING] 2 packages to latest compatible versions [DOCUMENTING] b v0.0.1 ([ROOT]/foo/b) [CHECKING] b v0.0.1 ([ROOT]/foo/b) [DOCUMENTING] a v0.0.1 ([ROOT]/foo/a) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/a/index.html "#]] .unordered(), ) .run(); } #[cargo_test] fn doc_all_exclude() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() { break_the_build(); }") .build(); p.cargo("doc --workspace --exclude baz") .with_stderr_data(str![[r#" [DOCUMENTING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/bar/index.html "#]]) .run(); } #[cargo_test] fn doc_all_exclude_glob() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() { break_the_build(); }") .build(); p.cargo("doc --workspace --exclude '*z'") .with_stderr_data(str![[r#" [DOCUMENTING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/bar/index.html "#]]) .run(); } #[cargo_test] fn doc_same_name() { let p = project() .file("src/lib.rs", "") .file("src/bin/main.rs", "fn main() {}") .file("examples/main.rs", "fn main() {}") .file("tests/main.rs", "fn main() {}") .build(); p.cargo("doc").run(); } #[cargo_test(nightly, reason = "no_core, lang_items requires nightly")] fn doc_target() { const TARGET: &str = "arm-unknown-linux-gnueabihf"; let p = project() .file( "src/lib.rs", r#" #![allow(internal_features)] #![feature(no_core, lang_items)] #![no_core] #[lang = "sized"] trait Sized {} extern { pub static A: u32; } "#, ) .build(); p.cargo("doc --verbose --target").arg(TARGET).run(); assert!(p.root().join(&format!("target/{}/doc", TARGET)).is_dir()); assert!(p .root() .join(&format!("target/{}/doc/foo/index.html", TARGET)) .is_file()); } #[cargo_test] fn target_specific_not_documented() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [target.foo.dependencies] a = { path = "a" } "#, ) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/src/lib.rs", "not rust") .build(); p.cargo("doc").run(); } #[cargo_test] fn output_not_captured() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a" } "#, ) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file( "a/src/lib.rs", " /// ``` /// ` /// ``` pub fn foo() {} ", ) .build(); p.cargo("doc") .with_stderr_data(str![[r#" ... [..]unknown start of token: ` ... "#]]) .run(); } #[cargo_test] fn target_specific_documented() { let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [target.foo.dependencies] a = {{ path = "a" }} [target.{}.dependencies] a = {{ path = "a" }} "#, rustc_host() ), ) .file( "src/lib.rs", " extern crate a; /// test pub fn foo() {} ", ) .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file( "a/src/lib.rs", " /// test pub fn foo() {} ", ) .build(); p.cargo("doc").run(); } #[cargo_test] fn no_document_build_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [build-dependencies] a = { path = "a" } "#, ) .file("src/lib.rs", "pub fn foo() {}") .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file( "a/src/lib.rs", " /// ``` /// β˜ƒ /// ``` pub fn foo() {} ", ) .build(); p.cargo("doc").run(); } #[cargo_test] fn doc_release() { let p = project().file("src/lib.rs", "").build(); p.cargo("check --release").run(); p.cargo("doc --release -v") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustdoc [..] src/lib.rs [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); } #[cargo_test] fn doc_multiple_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" [dependencies.baz] path = "baz" "#, ) .file("src/lib.rs", "extern crate bar; pub fn foo() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("doc -p bar -p baz -v").run(); assert!(p.root().join("target/doc").is_dir()); assert!(p.root().join("target/doc/bar/index.html").is_file()); assert!(p.root().join("target/doc/baz/index.html").is_file()); } #[cargo_test] fn features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" [features] foo = ["bar/bar"] "#, ) .file("src/lib.rs", r#"#[cfg(feature = "foo")] pub fn foo() {}"#) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [features] bar = [] "#, ) .file( "bar/build.rs", r#" fn main() { println!("cargo::rustc-cfg=bar"); } "#, ) .file( "bar/src/lib.rs", r#"#[cfg(feature = "bar")] pub fn bar() {}"#, ) .build(); p.cargo("doc --features foo") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [DOCUMENTING] bar v0.0.1 ([ROOT]/foo/bar) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); assert!(p.root().join("target/doc").is_dir()); assert!(p.root().join("target/doc/foo/fn.foo.html").is_file()); assert!(p.root().join("target/doc/bar/fn.bar.html").is_file()); // Check that turning the feature off will remove the files. p.cargo("doc") .with_stderr_data(str![[r#" [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [DOCUMENTING] bar v0.0.1 ([ROOT]/foo/bar) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); assert!(!p.root().join("target/doc/foo/fn.foo.html").is_file()); assert!(!p.root().join("target/doc/bar/fn.bar.html").is_file()); // And switching back will rebuild and bring them back. p.cargo("doc --features foo") .with_stderr_data(str![[r#" [DOCUMENTING] bar v0.0.1 ([ROOT]/foo/bar) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); assert!(p.root().join("target/doc/foo/fn.foo.html").is_file()); assert!(p.root().join("target/doc/bar/fn.bar.html").is_file()); } #[cargo_test] fn rerun_when_dir_removed() { let p = project() .file( "src/lib.rs", r#" /// dox pub fn foo() {} "#, ) .build(); p.cargo("doc").run(); assert!(p.root().join("target/doc/foo/index.html").is_file()); fs::remove_dir_all(p.root().join("target/doc/foo")).unwrap(); p.cargo("doc").run(); assert!(p.root().join("target/doc/foo/index.html").is_file()); } #[cargo_test] fn document_only_lib() { let p = project() .file( "src/lib.rs", r#" /// dox pub fn foo() {} "#, ) .file( "src/bin/bar.rs", r#" /// ``` /// β˜ƒ /// ``` pub fn foo() {} fn main() { foo(); } "#, ) .build(); p.cargo("doc --lib").run(); assert!(p.root().join("target/doc/foo/index.html").is_file()); } #[cargo_test] fn plugins_no_use_target() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] proc-macro = true "#, ) .file("src/lib.rs", "") .build(); p.cargo("doc --target=x86_64-unknown-openbsd -v").run(); } #[cargo_test] fn doc_all_workspace() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } [workspace] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); // The order in which bar is compiled or documented is not deterministic p.cargo("doc --workspace") .with_stderr_data( str![[r#" [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [DOCUMENTING] bar v0.1.0 ([ROOT]/foo/bar) [DOCUMENTING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/bar/index.html and 1 other file "#]] .unordered(), ) .run(); } #[cargo_test] fn doc_all_workspace_verbose() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } [workspace] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); // The order in which bar is compiled or documented is not deterministic p.cargo("doc --workspace -v") .with_stderr_data( str![[r#" [DOCUMENTING] bar v0.1.0 ([ROOT]/foo/bar) [DOCUMENTING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustdoc [..] [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [RUNNING] `rustc [..] [RUNNING] `rustdoc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/bar/index.html [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]] .unordered(), ) .run(); } #[cargo_test] fn doc_all_virtual_manifest() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); // The order in which bar and baz are documented is not guaranteed p.cargo("doc --workspace") .with_stderr_data( str![[r#" [DOCUMENTING] baz v0.1.0 ([ROOT]/foo/baz) [DOCUMENTING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/bar/index.html and 1 other file "#]] .unordered(), ) .run(); } #[cargo_test] fn doc_virtual_manifest_all_implied() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); // The order in which bar and baz are documented is not guaranteed p.cargo("doc") .with_stderr_data( str![[r#" [GENERATED] [ROOT]/foo/target/doc/bar/index.html and 1 other file [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [DOCUMENTING] bar v0.1.0 ([ROOT]/foo/bar) [DOCUMENTING] baz v0.1.0 ([ROOT]/foo/baz) "#]] .unordered(), ) .run(); } #[cargo_test] fn doc_virtual_manifest_one_project() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() { break_the_build(); }") .build(); p.cargo("doc -p bar") .with_stderr_data(str![[r#" [DOCUMENTING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/bar/index.html "#]]) .run(); } #[cargo_test] fn doc_virtual_manifest_glob() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() { break_the_build(); }") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("doc -p '*z'") .with_stderr_data(str![[r#" [DOCUMENTING] baz v0.1.0 ([ROOT]/foo/baz) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/baz/index.html "#]]) .run(); } #[cargo_test] fn doc_all_member_dependency_same_name() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1.0" "#, ) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); Package::new("bar", "0.1.0").publish(); p.cargo("doc --workspace") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [WARNING] output filename collision. The lib target `bar` in package `bar v0.1.0` has the same output filename as the lib target `bar` in package `bar v0.1.0 ([ROOT]/foo/bar)`. Colliding filename is: [ROOT]/foo/target/doc/bar/index.html The targets should have unique names. This is a known bug where multiple crates with the same name use the same path; see . [DOCUMENTING] bar v0.1.0 [CHECKING] bar v0.1.0 [DOCUMENTING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/bar/index.html "#]].unordered()) .run(); } #[cargo_test] fn doc_workspace_open_help_message() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo", "bar"] "#, ) .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "") .build(); // The order in which bar is compiled or documented is not deterministic p.cargo("doc --workspace --open") .env("BROWSER", tools::echo()) .with_stderr_data( str![[r#" [DOCUMENTING] foo v0.1.0 ([ROOT]/foo/foo) [DOCUMENTING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [OPENING] [ROOT]/foo/target/doc/bar/index.html "#]] .unordered(), ) .run(); } #[cargo_test(nightly, reason = "-Zextern-html-root-url is unstable")] fn doc_extern_map_local() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file("src/lib.rs", "") .file(".cargo/config.toml", "doc.extern-map.std = 'local'") .build(); p.cargo("doc -v --no-deps -Zrustdoc-map --open") .env("BROWSER", tools::echo()) .masquerade_as_nightly_cargo(&["rustdoc-map"]) .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustdoc --edition=2015 --crate-type lib --crate-name foo src/lib.rs [..]--crate-version 0.1.0` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [OPENING] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); } #[cargo_test] fn open_no_doc_crate() { let p = project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [lib] doc = false "#, ) .file("src/lib.rs", "#[cfg(feature)] pub fn f();") .build(); p.cargo("doc --open") .env("BROWSER", "do_not_run_me") .with_status(101) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [ERROR] cannot open specified crate's documentation: no documentation generated "#]]) .run(); } #[cargo_test] fn doc_workspace_open_different_library_and_package_names() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo"] "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] name = "foolib" "#, ) .file("foo/src/lib.rs", "") .build(); p.cargo("doc --open") .env("BROWSER", tools::echo()) .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.1.0 ([ROOT]/foo/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [OPENING] [ROOT]/foo/target/doc/foolib/index.html "#]]) .with_stdout_data(str![[r#" [ROOT]/foo/target/doc/foolib/index.html "#]]) .run(); p.change_file( ".cargo/config.toml", &format!( r#" [doc] browser = ["{}", "a"] "#, tools::echo().display().to_string().replace('\\', "\\\\") ), ); // check that the cargo config overrides the browser env var p.cargo("doc --open") .env("BROWSER", "do_not_run_me") .with_stdout_data(str![[r#" a [ROOT]/foo/target/doc/foolib/index.html "#]]) .run(); } #[cargo_test] fn doc_workspace_open_binary() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo"] "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [[bin]] name = "foobin" path = "src/main.rs" "#, ) .file("foo/src/main.rs", "") .build(); p.cargo("doc --open") .env("BROWSER", tools::echo()) .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.1.0 ([ROOT]/foo/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [OPENING] [ROOT]/foo/target/doc/foobin/index.html "#]]) .run(); } #[cargo_test] fn doc_workspace_open_binary_and_library() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo"] "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] name = "foolib" [[bin]] name = "foobin" path = "src/main.rs" "#, ) .file("foo/src/lib.rs", "") .file("foo/src/main.rs", "") .build(); p.cargo("doc --open") .env("BROWSER", tools::echo()) .with_stderr_data( str![[r#" [DOCUMENTING] foo v0.1.0 ([ROOT]/foo/foo) [CHECKING] foo v0.1.0 ([ROOT]/foo/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [OPENING] [ROOT]/foo/target/doc/foolib/index.html "#]] .unordered(), ) .run(); } #[cargo_test] fn doc_edition() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2018" "#, ) .file("src/lib.rs", "") .build(); p.cargo("doc -v") .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..]--edition=2018[..] ... "#]]) .run(); p.cargo("test -v") .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..]--edition=2018[..] ... "#]]) .run(); } #[cargo_test] fn doc_target_edition() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] edition = "2018" "#, ) .file("src/lib.rs", "") .build(); p.cargo("doc -v") .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..]--edition=2018[..] ... "#]]) .run(); p.cargo("test -v") .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..]--edition=2018[..] ... "#]]) .run(); } // Tests an issue where depending on different versions of the same crate depending on `cfg`s // caused `cargo doc` to fail. #[cargo_test] fn issue_5345() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [target.'cfg(all(windows, target_arch = "x86"))'.dependencies] bar = "0.1" [target.'cfg(not(all(windows, target_arch = "x86")))'.dependencies] bar = "0.2" "#, ) .file("src/lib.rs", "extern crate bar;") .build(); Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.2.0").publish(); foo.cargo("check").run(); foo.cargo("doc").run(); } #[cargo_test] fn doc_private_items() { let foo = project() .file("src/lib.rs", "mod private { fn private_item() {} }") .build(); foo.cargo("doc --document-private-items").run(); assert!(foo.root().join("target/doc").is_dir()); assert!(foo .root() .join("target/doc/foo/private/index.html") .is_file()); } #[cargo_test] fn doc_private_ws() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/src/lib.rs", "fn p() {}") .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/lib.rs", "fn p2() {}") .file("b/src/bin/b-cli.rs", "fn main() {}") .build(); p.cargo("doc --workspace --bins --lib --document-private-items -v") .with_stderr_data( str![[r#" [DOCUMENTING] b v0.0.1 ([ROOT]/foo/b) [CHECKING] b v0.0.1 ([ROOT]/foo/b) [DOCUMENTING] a v0.0.1 ([ROOT]/foo/a) [RUNNING] `rustdoc [..] a/src/lib.rs [..]--document-private-items[..] [RUNNING] `rustc [..] [WARNING] function `p2` is never used ... [RUNNING] `rustdoc [..] b/src/lib.rs [..]--document-private-items[..] [WARNING] `b` (lib) generated 1 warning [RUNNING] `rustdoc [..] b/src/bin/b-cli.rs [..]--document-private-items[..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/a/index.html [GENERATED] [ROOT]/foo/target/doc/b/index.html [GENERATED] [ROOT]/foo/target/doc/b_cli/index.html "#]] .unordered(), ) .run(); } const BAD_INTRA_LINK_LIB: &str = r#" #![deny(rustdoc::broken_intra_doc_links)] /// [bad_link] pub fn foo() {} "#; #[cargo_test] fn doc_cap_lints() { let a = git::new("a", |p| { p.file("Cargo.toml", &basic_lib_manifest("a")) .file("src/lib.rs", BAD_INTRA_LINK_LIB) }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = {{ git = '{}' }} "#, a.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("doc") .with_stderr_data( str![[r#" [LOCKING] 1 package to latest compatible version [UPDATING] git repository `[..]` [DOCUMENTING] a v0.5.0 ([..]) [CHECKING] a v0.5.0 ([..]) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]] .unordered(), ) .run(); p.root().join("target").rm_rf(); p.cargo("doc -vv") .with_stderr_data(str![[r#" ... [WARNING] [..]`bad_link`[..] ... "#]]) .run(); } #[cargo_test] fn doc_message_format() { let p = project().file("src/lib.rs", BAD_INTRA_LINK_LIB).build(); p.cargo("doc --message-format=json") .with_status(101) .with_stdout_data( str![[r##" [ { "manifest_path": "[ROOT]/foo/Cargo.toml", "message": { "$message_type": "diagnostic", "level": "error", "...": "{...}" }, "package_id": "path+[ROOTURL]/foo#0.0.1", "reason": "compiler-message", "target": "{...}" }, "{...}" ] "##]] .is_json() .against_jsonlines(), ) .run(); } #[cargo_test] fn doc_json_artifacts() { // Checks the output of json artifact messages. let p = project() .file("src/lib.rs", "") .file("src/bin/somebin.rs", "fn main() {}") .build(); p.cargo("doc --message-format=json") .with_stdout_data( str![[r#" [ { "executable": null, "features": [], "filenames": [ "[ROOT]/foo/target/debug/deps/libfoo-[HASH].rmeta" ], "fresh": false, "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.0.1", "profile": "{...}", "reason": "compiler-artifact", "target": { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } }, { "executable": null, "features": [], "filenames": [ "[ROOT]/foo/target/doc/foo/index.html" ], "fresh": false, "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.0.1", "profile": "{...}", "reason": "compiler-artifact", "target": { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } }, { "executable": null, "features": [], "filenames": [ "[ROOT]/foo/target/doc/somebin/index.html" ], "fresh": false, "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.0.1", "profile": "{...}", "reason": "compiler-artifact", "target": { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "somebin", "src_path": "[ROOT]/foo/src/bin/somebin.rs", "test": true } }, { "reason": "build-finished", "success": true } ] "#]] .is_json() .against_jsonlines() .unordered(), ) .run(); } #[cargo_test] fn short_message_format() { let p = project().file("src/lib.rs", BAD_INTRA_LINK_LIB).build(); p.cargo("doc --message-format=short") .with_status(101) .with_stderr_data(str![[r#" ... src/lib.rs:4:6: [ERROR] [..]`bad_link`[..] ... "#]]) .run(); } #[cargo_test] fn doc_example() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [[example]] crate-type = ["lib"] name = "ex1" doc = true "#, ) .file("src/lib.rs", "pub fn f() {}") .file( "examples/ex1.rs", r#" use foo::f; /// Example pub fn x() { f(); } "#, ) .build(); p.cargo("doc").run(); assert!(p .build_dir() .join("doc") .join("ex1") .join("fn.x.html") .exists()); } #[cargo_test] fn doc_example_with_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [[example]] crate-type = ["lib"] name = "ex" doc = true [dev-dependencies] a = {path = "a"} b = {path = "b"} "#, ) .file("src/lib.rs", "") .file( "examples/ex.rs", r#" use a::fun; /// Example pub fn x() { fun(); } "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" [dependencies] b = {path = "../b"} "#, ) .file("a/src/fun.rs", "pub fn fun() {}") .file("a/src/lib.rs", "pub mod fun;") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.0.1" edition = "2015" "#, ) .file("b/src/lib.rs", "") .build(); p.cargo("doc --examples").run(); assert!(p .build_dir() .join("doc") .join("ex") .join("fn.x.html") .exists()); } #[cargo_test] fn bin_private_items() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] "#, ) .file( "src/main.rs", " pub fn foo_pub() {} fn foo_priv() {} struct FooStruct; enum FooEnum {} trait FooTrait {} type FooType = u32; mod foo_mod {} ", ) .build(); p.cargo("doc") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); assert!(p.root().join("target/doc/foo/index.html").is_file()); assert!(p.root().join("target/doc/foo/fn.foo_pub.html").is_file()); assert!(p.root().join("target/doc/foo/fn.foo_priv.html").is_file()); assert!(p .root() .join("target/doc/foo/struct.FooStruct.html") .is_file()); assert!(p.root().join("target/doc/foo/enum.FooEnum.html").is_file()); assert!(p .root() .join("target/doc/foo/trait.FooTrait.html") .is_file()); assert!(p.root().join("target/doc/foo/type.FooType.html").is_file()); assert!(p.root().join("target/doc/foo/foo_mod/index.html").is_file()); } #[cargo_test] fn bin_private_items_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" "#, ) .file( "src/main.rs", " fn foo_priv() {} pub fn foo_pub() {} ", ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file( "bar/src/lib.rs", " #[allow(dead_code)] fn bar_priv() {} pub fn bar_pub() {} ", ) .build(); p.cargo("doc") .with_stderr_data( str![[r#" [LOCKING] 1 package to latest compatible version [DOCUMENTING] bar v0.0.1 ([ROOT]/foo/bar) [CHECKING] bar v0.0.1 ([ROOT]/foo/bar) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]] .unordered(), ) .run(); assert!(p.root().join("target/doc/foo/index.html").is_file()); assert!(p.root().join("target/doc/foo/fn.foo_pub.html").is_file()); assert!(p.root().join("target/doc/foo/fn.foo_priv.html").is_file()); assert!(p.root().join("target/doc/bar/index.html").is_file()); assert!(p.root().join("target/doc/bar/fn.bar_pub.html").is_file()); assert!(!p.root().join("target/doc/bar/fn.bar_priv.html").exists()); } #[cargo_test] fn crate_versions() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.2.4" edition = "2015" authors = [] "#, ) .file("src/lib.rs", "") .build(); p.cargo("doc -v") .with_stderr_data(str![[r#" [DOCUMENTING] foo v1.2.4 ([ROOT]/foo) [RUNNING] `rustdoc --edition=2015 --crate-type lib --crate-name foo src/lib.rs [..]--crate-version 1.2.4` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); let output_path = p.root().join("target/doc/foo/index.html"); let output_documentation = fs::read_to_string(&output_path).unwrap(); assert!(output_documentation.contains("1.2.4")); } #[cargo_test] fn crate_versions_flag_is_overridden() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.2.4" edition = "2015" authors = [] "#, ) .file("src/lib.rs", "") .build(); let output_documentation = || { let output_path = p.root().join("target/doc/foo/index.html"); fs::read_to_string(&output_path).unwrap() }; let asserts = |html: String| { assert!(!html.contains("1.2.4")); assert!(html.contains("2.0.3")); }; p.cargo("doc") .env("RUSTDOCFLAGS", "--crate-version 2.0.3") .run(); asserts(output_documentation()); p.build_dir().rm_rf(); p.cargo("rustdoc -- --crate-version 2.0.3").run(); asserts(output_documentation()); } #[cargo_test] fn doc_test_in_workspace() { let p = project() .file( "Cargo.toml", r#" [workspace] members = [ "crate-a", "crate-b", ] "#, ) .file( "crate-a/Cargo.toml", r#" [package] name = "crate-a" version = "0.1.0" edition = "2015" "#, ) .file( "crate-a/src/lib.rs", "\ //! ``` //! assert_eq!(1, 1); //! ``` ", ) .file( "crate-b/Cargo.toml", r#" [package] name = "crate-b" version = "0.1.0" edition = "2015" "#, ) .file( "crate-b/src/lib.rs", "\ //! ``` //! assert_eq!(1, 1); //! ``` ", ) .build(); p.cargo("test --doc -vv") .with_stderr_data(str![[r#" ... [DOCTEST] crate_a ... "#]]) .with_stdout_data(str![[r#" 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; finished in [ELAPSED]s 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; finished in [ELAPSED]s "#]]) .run(); } /// This is a test for . /// 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" edition = "2015" "#, ) .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" edition = "2015" "#, ) .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_data(str![[r#" ... [DOCTEST] child ... [DOCTEST] root ... "#]]) .with_stdout_data(str![[r#" 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; finished in [ELAPSED]s 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; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn doc_fingerprint_is_versioning_consistent() { // Random rustc verbose version let old_rustc_verbose_version = format!( "\ rustc 1.41.1 (f3e1a954d 2020-02-24) binary: rustc commit-hash: f3e1a954d2ead4e2fc197c7da7d71e6c61bad196 commit-date: 2020-02-24 host: {} release: 1.41.1 LLVM version: 9.0 ", rustc_host() ); // Create the dummy project. let dummy_project = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.2.4" edition = "2015" authors = [] "#, ) .file("src/lib.rs", "//! These are the docs!") .build(); dummy_project.cargo("doc").run(); let fingerprint: RustDocFingerprint = serde_json::from_str(&dummy_project.read_file("target/.rustdoc_fingerprint.json")) .expect("JSON Serde fail"); // Check that the fingerprint contains the actual rustc version // which has been used to compile the docs. let output = std::process::Command::new("rustc") .arg("-vV") .output() .expect("Failed to get actual rustc verbose version"); assert_eq!( fingerprint.rustc_vv, (String::from_utf8_lossy(&output.stdout).as_ref()) ); // As the test shows above. Now we have generated the `doc/` folder and inside // the rustdoc fingerprint file is located with the correct rustc version. // So we will remove it and create a new fingerprint with an old rustc version // inside it. We will also place a bogus file inside of the `doc/` folder to ensure // it gets removed as we expect on the next doc compilation. dummy_project.change_file( "target/.rustdoc_fingerprint.json", &old_rustc_verbose_version, ); fs::write( dummy_project.build_dir().join("doc/bogus_file"), String::from("This is a bogus file and should be removed!"), ) .expect("Error writing test bogus file"); // Now if we trigger another compilation, since the fingerprint contains an old version // of rustc, cargo should remove the entire `/doc` folder (including the fingerprint) // and generating another one with the actual version. // It should also remove the bogus file we created above. dummy_project.cargo("doc").run(); assert!(!dummy_project.build_dir().join("doc/bogus_file").exists()); let fingerprint: RustDocFingerprint = serde_json::from_str(&dummy_project.read_file("target/.rustdoc_fingerprint.json")) .expect("JSON Serde fail"); // Check that the fingerprint contains the actual rustc version // which has been used to compile the docs. assert_eq!( fingerprint.rustc_vv, (String::from_utf8_lossy(&output.stdout).as_ref()) ); } #[cargo_test] fn doc_fingerprint_respects_target_paths() { // Random rustc verbose version let old_rustc_verbose_version = format!( "\ rustc 1.41.1 (f3e1a954d 2020-02-24) binary: rustc commit-hash: f3e1a954d2ead4e2fc197c7da7d71e6c61bad196 commit-date: 2020-02-24 host: {} release: 1.41.1 LLVM version: 9.0 ", rustc_host() ); // Create the dummy project. let dummy_project = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.2.4" edition = "2015" authors = [] "#, ) .file("src/lib.rs", "//! These are the docs!") .build(); dummy_project.cargo("doc --target").arg(rustc_host()).run(); let fingerprint: RustDocFingerprint = serde_json::from_str(&dummy_project.read_file("target/.rustdoc_fingerprint.json")) .expect("JSON Serde fail"); // Check that the fingerprint contains the actual rustc version // which has been used to compile the docs. let output = std::process::Command::new("rustc") .arg("-vV") .output() .expect("Failed to get actual rustc verbose version"); assert_eq!( fingerprint.rustc_vv, (String::from_utf8_lossy(&output.stdout).as_ref()) ); // As the test shows above. Now we have generated the `doc/` folder and inside // the rustdoc fingerprint file is located with the correct rustc version. // So we will remove it and create a new fingerprint with an old rustc version // inside it. We will also place a bogus file inside of the `doc/` folder to ensure // it gets removed as we expect on the next doc compilation. dummy_project.change_file( "target/.rustdoc_fingerprint.json", &old_rustc_verbose_version, ); fs::write( dummy_project .build_dir() .join(rustc_host()) .join("doc/bogus_file"), String::from("This is a bogus file and should be removed!"), ) .expect("Error writing test bogus file"); // Now if we trigger another compilation, since the fingerprint contains an old version // of rustc, cargo should remove the entire `/doc` folder (including the fingerprint) // and generating another one with the actual version. // It should also remove the bogus file we created above. dummy_project.cargo("doc --target").arg(rustc_host()).run(); assert!(!dummy_project .build_dir() .join(rustc_host()) .join("doc/bogus_file") .exists()); let fingerprint: RustDocFingerprint = serde_json::from_str(&dummy_project.read_file("target/.rustdoc_fingerprint.json")) .expect("JSON Serde fail"); // Check that the fingerprint contains the actual rustc version // which has been used to compile the docs. assert_eq!( fingerprint.rustc_vv, (String::from_utf8_lossy(&output.stdout).as_ref()) ); } #[cargo_test] fn doc_fingerprint_unusual_behavior() { // Checks for some unusual circumstances with clearing the doc directory. if !symlink_supported() { return; } let p = project().file("src/lib.rs", "").build(); p.build_dir().mkdir_p(); let real_doc = p.root().join("doc"); real_doc.mkdir_p(); let build_doc = p.build_dir().join("doc"); p.symlink(&real_doc, &build_doc); fs::write(real_doc.join("somefile"), "test").unwrap(); fs::write(real_doc.join(".hidden"), "test").unwrap(); p.cargo("doc").run(); // Make sure for the first run, it does not delete any files and does not // break the symlink. assert!(build_doc.join("somefile").exists()); assert!(real_doc.join("somefile").exists()); assert!(real_doc.join(".hidden").exists()); assert!(real_doc.join("foo/index.html").exists()); // Pretend that the last build was generated by an older version. p.change_file( "target/.rustdoc_fingerprint.json", "{\"rustc_vv\": \"I am old\"}", ); // Change file to trigger a new build. p.change_file("src/lib.rs", "// changed"); p.cargo("doc") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); // This will delete somefile, but not .hidden. assert!(!real_doc.join("somefile").exists()); assert!(real_doc.join(".hidden").exists()); assert!(real_doc.join("foo/index.html").exists()); // And also check the -Z flag behavior. p.change_file( "target/.rustdoc_fingerprint.json", "{\"rustc_vv\": \"I am old\"}", ); // Change file to trigger a new build. p.change_file("src/lib.rs", "// changed2"); fs::write(real_doc.join("somefile"), "test").unwrap(); p.cargo("doc -Z skip-rustdoc-fingerprint") .masquerade_as_nightly_cargo(&["skip-rustdoc-fingerprint"]) .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); // Should not have deleted anything. assert!(build_doc.join("somefile").exists()); assert!(real_doc.join("somefile").exists()); } #[cargo_test] fn lib_before_bin() { // Checks that the library is documented before the binary. // Previously they were built concurrently, which can cause issues // if the bin has intra-doc links to the lib. let p = project() .file( "src/lib.rs", r#" /// Hi pub fn abc() {} "#, ) .file( "src/bin/somebin.rs", r#" //! See [`foo::abc`] fn main() {} "#, ) .build(); // Run check first. This just helps ensure that the test clearly shows the // order of the rustdoc commands. p.cargo("check").run(); // The order of output here should be deterministic. p.cargo("doc -v") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustdoc --edition=2015 --crate-type lib --crate-name foo src/lib.rs [..] [RUNNING] `rustdoc --edition=2015 --crate-type bin --crate-name somebin src/bin/somebin.rs [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html [GENERATED] [ROOT]/foo/target/doc/somebin/index.html "#]]) .run(); // And the link should exist. let bin_html = p.read_file("target/doc/somebin/index.html"); assert!(bin_html.contains("../foo/fn.abc.html")); } #[cargo_test] fn doc_lib_false() { // doc = false for a library let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] doc = false [dependencies] bar = {path = "bar"} "#, ) .file("src/lib.rs", "extern crate bar;") .file("src/bin/some-bin.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [lib] doc = false "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("doc") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.1.0 ([ROOT]/foo) [DOCUMENTING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/some_bin/index.html "#]]) .run(); assert!(!p.build_dir().join("doc/foo").exists()); assert!(!p.build_dir().join("doc/bar").exists()); assert!(p.build_dir().join("doc/some_bin").exists()); } #[cargo_test] fn doc_lib_false_dep() { // doc = false for a dependency // Ensures that the rmeta gets produced let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } "#, ) .file("src/lib.rs", "extern crate bar;") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [lib] doc = false "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("doc") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [DOCUMENTING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); assert!(p.build_dir().join("doc/foo").exists()); assert!(!p.build_dir().join("doc/bar").exists()); } #[cargo_test] fn link_to_private_item() { let main = r#" //! [bar] #[allow(dead_code)] fn bar() {} "#; let p = project().file("src/lib.rs", main).build(); p.cargo("doc") .with_stderr_data(str![[r#" ... [..]documentation for `foo` links to private item `bar` ... "#]]) .run(); // Check that binaries don't emit a private_intra_doc_links warning. fs::rename(p.root().join("src/lib.rs"), p.root().join("src/main.rs")).unwrap(); p.cargo("doc") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); } #[cargo_test] fn rustdoc_failure_hides_command_line_by_default() { let p = project().file("src/lib.rs", "invalid rust code").build(); // `cargo doc` doesn't print the full command line on failures by default p.cargo("doc") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [ERROR] expected one of `!` or `::`, found `rust` --> src/lib.rs:1:9 | 1 | invalid rust code | ^^^^ expected one of `!` or `::` [ERROR] could not document `foo` "#]]) .with_status(101) .run(); // ... but it still does so if requested with `--verbose`. p.cargo("doc --verbose") .with_stderr_data(str![[r#" ... Caused by: process didn't exit successfully[..]rustdoc[..] "#]]) .with_status(101) .run(); } cargo-0.86.0/tests/testsuite/docscrape.rs000064400000000000000000000551641046102023000165310ustar 00000000000000//! Tests for the `cargo doc` command with `-Zrustdoc-scrape-examples`. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; #[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")] fn basic() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("examples/ex.rs", "fn main() { foo::foo(); }") .file("src/lib.rs", "pub fn foo() {}\npub fn bar() { foo(); }") .build(); p.cargo("doc -Zunstable-options -Zrustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [SCRAPING] foo v0.0.1 ([ROOT]/foo) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); p.cargo("doc -Zunstable-options -Z rustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); let doc_html = p.read_file("target/doc/foo/fn.foo.html"); assert!(doc_html.contains("Examples found in repository")); assert!(!doc_html.contains("More examples")); // Ensure that the reverse-dependency has its sources generated assert!(p.build_dir().join("doc/src/ex/ex.rs.html").exists()); } // This test ensures that even if there is no `[workspace]` in the top-level `Cargo.toml` file, the // dependencies will get their examples scraped and that they appear in the generated documentation. #[cargo_test(nightly, reason = "-Zrustdoc-scrape-examples is unstable")] fn scrape_examples_for_non_workspace_reexports() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2021" authors = [] [dependencies] a = { path = "crates/a" } "#, ) .file("src/lib.rs", "pub use a::*;") // Example .file( "examples/one.rs", r#"use foo::*; fn main() { let foo = Foo::new("yes".into()); foo.maybe(); }"#, ) // `a` crate .file( "crates/a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] "#, ) .file( "crates/a/src/lib.rs", r#" #[derive(Debug)] pub struct Foo { foo: String, yes: bool, } impl Foo { pub fn new(foo: String) -> Self { Self { foo, yes: true } } pub fn maybe(&self) { if self.yes { println!("{}", self.foo) } } }"#, ) .build(); p.cargo("doc -Zunstable-options -Zrustdoc-scrape-examples --no-deps") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .with_stderr_data( str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] a v0.0.1 ([ROOT]/foo/crates/a) [CHECKING] foo v0.0.1 ([ROOT]/foo) [SCRAPING] foo v0.0.1 ([ROOT]/foo) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]] .unordered(), ) .run(); let doc_html = p.read_file("target/doc/foo/struct.Foo.html"); assert!(doc_html.contains("Examples found in repository")); } #[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")] fn avoid_build_script_cycle() { let p = project() // package with build dependency .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] links = "foo" [workspace] members = ["bar"] [build-dependencies] bar = {path = "bar"} "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main(){}") // dependency .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] links = "bar" "#, ) .file("bar/src/lib.rs", "") .file("bar/build.rs", "fn main(){}") .build(); p.cargo("doc --workspace -Zunstable-options -Zrustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .run(); } #[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")] fn complex_reverse_dependencies() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dev-dependencies] a = {path = "a", features = ["feature"]} b = {path = "b"} [workspace] members = ["b"] "#, ) .file("src/lib.rs", "") .file("examples/ex.rs", "fn main() {}") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [lib] proc-macro = true [dependencies] b = {path = "../b"} [features] feature = [] "#, ) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("b/src/lib.rs", "") .build(); p.cargo("doc --workspace --examples -Zunstable-options -Zrustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .run(); } #[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")] fn crate_with_dash() { let p = project() .file( "Cargo.toml", r#" [package] name = "da-sh" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("src/lib.rs", "pub fn foo() {}") .file("examples/a.rs", "fn main() { da_sh::foo(); }") .build(); p.cargo("doc -Zunstable-options -Zrustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .run(); let doc_html = p.read_file("target/doc/da_sh/fn.foo.html"); assert!(doc_html.contains("Examples found in repository")); } #[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")] fn configure_target() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] doc-scrape-examples = true [[bin]] name = "a_bin" doc-scrape-examples = true [[example]] name = "a" doc-scrape-examples = false "#, ) .file( "src/lib.rs", "pub fn foo() {} fn lib_must_appear() { foo(); }", ) .file( "examples/a.rs", "fn example_must_not_appear() { foo::foo(); }", ) .file( "src/bin/a_bin.rs", "fn bin_must_appear() { foo::foo(); } fn main(){}", ) .build(); p.cargo("doc -Zunstable-options -Zrustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .run(); let doc_html = p.read_file("target/doc/foo/fn.foo.html"); assert!(doc_html.contains("lib_must_appear")); assert!(doc_html.contains("bin_must_appear")); assert!(!doc_html.contains("example_must_not_appear")); } #[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")] fn configure_profile_issue_10500() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [profile.dev] panic = "abort" "#, ) .file("examples/ex.rs", "fn main() { foo::foo(); }") .file("src/lib.rs", "pub fn foo() {}\npub fn bar() { foo(); }") .build(); p.cargo("doc -Zunstable-options -Zrustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .run(); let doc_html = p.read_file("target/doc/foo/fn.foo.html"); assert!(doc_html.contains("Examples found in repository")); } #[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")] fn issue_10545() { let p = project() .file( "Cargo.toml", r#" [workspace] resolver = "2" members = ["a", "b"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" authors = [] edition = "2021" [features] default = ["foo"] foo = [] "#, ) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.0.1" authors = [] edition = "2021" [lib] proc-macro = true "#, ) .file("b/src/lib.rs", "") .build(); p.cargo("doc --workspace -Zunstable-options -Zrustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .run(); } #[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")] fn cache() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("examples/ex.rs", "fn main() { foo::foo(); }") .file("src/lib.rs", "pub fn foo() {}\npub fn bar() { foo(); }") .build(); p.cargo("doc -Zunstable-options -Zrustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [SCRAPING] foo v0.0.1 ([ROOT]/foo) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); p.cargo("doc -Zunstable-options -Zrustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); } #[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")] fn no_fail_bad_lib() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("src/lib.rs", "pub fn foo() { CRASH_THE_BUILD() }") .file("examples/ex.rs", "fn main() { foo::foo(); }") .file("examples/ex2.rs", "fn main() { foo::foo(); }") .build(); p.cargo("doc -Zunstable-options -Z rustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [SCRAPING] foo v0.0.1 ([ROOT]/foo) [WARNING] failed to check lib in package `foo` as a prerequisite for scraping examples from: example "ex", example "ex2" Try running with `--verbose` to see the error message. If an example should not be scanned, then consider adding `doc-scrape-examples = false` to its `[[example]]` definition in Cargo.toml [WARNING] `foo` (lib) generated 1 warning [WARNING] failed to scan example "ex" in package `foo` for example code usage Try running with `--verbose` to see the error message. If an example should not be scanned, then consider adding `doc-scrape-examples = false` to its `[[example]]` definition in Cargo.toml [WARNING] `foo` (example "ex") generated 1 warning [WARNING] failed to scan example "ex2" in package `foo` for example code usage Try running with `--verbose` to see the error message. If an example should not be scanned, then consider adding `doc-scrape-examples = false` to its `[[example]]` definition in Cargo.toml [WARNING] `foo` (example "ex2") generated 1 warning [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]].unordered()) .run(); } #[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")] fn fail_bad_build_script() { // See rust-lang/cargo#11623 let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() { panic!(\"You shall not pass\")}") .file("examples/ex.rs", "fn main() {}") .build(); // `cargo doc` fails p.cargo("doc") .with_status(101) .with_stderr_data(str![[r#" ... [..]You shall not pass[..] ... "#]]) .run(); // scrape examples should fail whenever `cargo doc` fails. p.cargo("doc -Zunstable-options -Z rustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .with_status(101) .with_stderr_data(str![[r#" ... [..]You shall not pass[..] ... "#]]) .run(); } #[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")] fn no_fail_bad_example() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("examples/ex1.rs", "DOES NOT COMPILE") .file("examples/ex2.rs", "fn main() { foo::foo(); }") .file("src/lib.rs", "pub fn foo(){}") .build(); p.cargo("doc -Zunstable-options -Z rustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [SCRAPING] foo v0.0.1 ([ROOT]/foo) [WARNING] failed to scan example "ex1" in package `foo` for example code usage Try running with `--verbose` to see the error message. If an example should not be scanned, then consider adding `doc-scrape-examples = false` to its `[[example]]` definition in Cargo.toml [WARNING] `foo` (example "ex1") generated 1 warning [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); p.cargo("clean").run(); p.cargo("doc -v -Zunstable-options -Z rustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .with_stderr_data( str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo[..] [SCRAPING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustdoc[..] --crate-name ex1[..] [RUNNING] `rustdoc[..] --crate-name ex2[..] [RUNNING] `rustdoc[..] --crate-name foo[..] [ERROR] expected one of `!` or `::`, found `NOT` --> examples/ex1.rs:1:6 | 1 | DOES NOT COMPILE | ^^^ expected one of `!` or `::` [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]] .unordered(), ) .run(); let doc_html = p.read_file("target/doc/foo/fn.foo.html"); assert!(doc_html.contains("Examples found in repository")); } #[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")] fn no_scrape_with_dev_deps() { // Tests that a crate with dev-dependencies does not have its examples // scraped unless explicitly prompted to check them. See // `UnitGenerator::create_docscrape_proposals` for details on why. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dev-dependencies] a = {path = "a"} "#, ) .file("src/lib.rs", "") .file("examples/ex.rs", "fn main() { a::f(); }") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("a/src/lib.rs", "pub fn f() {}") .build(); // If --examples is not provided, then the example is not scanned, and a warning // should be raised. p.cargo("doc -Zunstable-options -Z rustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [WARNING] Rustdoc did not scrape the following examples because they require dev-dependencies: ex If you want Rustdoc to scrape these examples, then add `doc-scrape-examples = true` to the [[example]] target configuration of at least one example. [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); // If --examples is provided, then the example is scanned. p.cargo("doc --examples -Zunstable-options -Z rustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .with_stderr_data( str![[r#" [CHECKING] a v0.0.1 ([ROOT]/foo/a) [CHECKING] foo v0.0.1 ([ROOT]/foo) [DOCUMENTING] a v0.0.1 ([ROOT]/foo/a) [SCRAPING] foo v0.0.1 ([ROOT]/foo) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/ex/index.html "#]] .unordered(), ) .run(); } #[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")] fn use_dev_deps_if_explicitly_enabled() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[example]] name = "ex" doc-scrape-examples = true [dev-dependencies] a = {path = "a"} "#, ) .file("src/lib.rs", "") .file("examples/ex.rs", "fn main() { a::f(); }") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("a/src/lib.rs", "pub fn f() {}") .build(); // If --examples is not provided, then the example is never scanned. p.cargo("doc -Zunstable-options -Z rustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .with_stderr_data( str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] a v0.0.1 ([ROOT]/foo/a) [CHECKING] foo v0.0.1 ([ROOT]/foo) [SCRAPING] foo v0.0.1 ([ROOT]/foo) [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..] [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]] .unordered(), ) .run(); } #[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")] fn only_scrape_documented_targets() { // package bar has doc = false and should not be eligible for documtation. let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [lib] doc = false [workspace] members = ["foo"] [dependencies] foo = {{ path = "foo" }} "# ), ) .file("src/lib.rs", "") .file("examples/ex.rs", "pub fn main() { foo::foo(); }") .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("foo/src/lib.rs", "pub fn foo() {}") .build(); p.cargo("doc --workspace -Zunstable-options -Zrustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .run(); let doc_html = p.read_file("target/doc/foo/fn.foo.html"); let example_found = doc_html.contains("Examples found in repository"); assert!(!example_found); } #[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")] fn issue_11496() { let p = project() .file( "Cargo.toml", r#" [package] name = "repro" version = "0.1.0" edition = "2021" [lib] proc-macro = true "#, ) .file("src/lib.rs", "") .file("examples/ex.rs", "fn main(){}") .build(); p.cargo("doc -Zunstable-options -Zrustdoc-scrape-examples") .masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"]) .run(); } cargo-0.86.0/tests/testsuite/edition.rs000064400000000000000000000122771046102023000162170ustar 00000000000000//! Tests for edition setting. use cargo::core::Edition; use cargo_test_support::prelude::*; use cargo_test_support::{basic_lib_manifest, project, str}; #[cargo_test] fn edition_works_for_build_script() { let p = project() .file( "Cargo.toml", r#" [package] name = 'foo' version = '0.1.0' edition = '2018' [build-dependencies] a = { path = 'a' } "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { a::foo(); } "#, ) .file("a/Cargo.toml", &basic_lib_manifest("a")) .file("a/src/lib.rs", "pub fn foo() {}") .build(); p.cargo("check -v").run(); } #[cargo_test] fn edition_unstable_gated() { // During the period where a new edition is coming up, but not yet stable, // this test will verify that it cannot be used on stable. If there is no // next edition, it does nothing. let next = match Edition::LATEST_UNSTABLE { Some(next) => next, None => { eprintln!("Next edition is currently not available, skipping test."); return; } }; let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "{}" "#, next ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(format!( "\ [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `edition{next}` is required The package requires the Cargo feature called `edition{next}`, but that feature is not stabilized in this version of Cargo (1.[..]). Consider trying a newer version of Cargo (this may require the nightly release). See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#edition-{next} for more information about the status of this feature. ")) .run(); } #[cargo_test(nightly, reason = "fundamentally always nightly")] fn edition_unstable() { // During the period where a new edition is coming up, but not yet stable, // this test will verify that it can be used with `cargo-features`. If // there is no next edition, it does nothing. let next = match Edition::LATEST_UNSTABLE { Some(next) => next, None => { eprintln!("Next edition is currently not available, skipping test."); return; } }; let p = project() .file( "Cargo.toml", &format!( r#" cargo-features = ["edition{next}"] [package] name = "foo" version = "0.1.0" edition = "{next}" "#, next = next ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .masquerade_as_nightly_cargo(&["always_nightly"]) .with_stderr_data(str![[r#" [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn unset_edition_with_unset_rust_version() { let p = project() .file( "Cargo.toml", r#" [package] name = 'foo' version = '0.1.0' "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -v") .with_stderr_data(str![[r#" [WARNING] no edition set: defaulting to the 2015 edition while the latest is [..] [CHECKING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] --edition=2015 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn unset_edition_works_with_no_newer_compatible_edition() { let p = project() .file( "Cargo.toml", r#" [package] name = 'foo' version = '0.1.0' rust-version = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -v") .with_stderr_data(str![[r#" [CHECKING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] --edition=2015 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn unset_edition_works_on_old_msrv() { let p = project() .file( "Cargo.toml", r#" [package] name = 'foo' version = '0.1.0' rust-version = "1.50" # contains 2018 edition "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -v") .with_stderr_data(str![[r#" [WARNING] no edition set: defaulting to the 2015 edition while 2018 is compatible with `rust-version` [CHECKING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] --edition=2015 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/error.rs000064400000000000000000000010601046102023000157010ustar 00000000000000//! General error tests that don't belong anywhere else. use cargo_test_support::cargo_process; use cargo_test_support::prelude::*; #[cargo_test] fn internal_error() { cargo_process("init") .env("__CARGO_TEST_INTERNAL_ERROR", "1") .with_status(101) .with_stderr_data(format!( "\ [ERROR] internal error test [NOTE] this is an unexpected cargo internal error [NOTE] we would appreciate a bug report: https://github.com/rust-lang/cargo/issues/ [NOTE] cargo {} ", cargo::version() )) .run(); } cargo-0.86.0/tests/testsuite/features.rs000064400000000000000000001570771046102023000164120ustar 00000000000000//! Tests for `[features]` table. use cargo_test_support::prelude::*; use cargo_test_support::registry::{Dependency, Package}; use cargo_test_support::str; use cargo_test_support::{basic_manifest, project}; #[cargo_test] fn invalid1() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] bar = ["baz"] "#, ) .file("src/main.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `bar` includes `baz` which is neither a dependency nor another feature "#]]) .run(); } #[cargo_test] fn empty_feature_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] "" = [] "#, ) .file("src/main.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] feature name cannot be empty --> Cargo.toml:9:17 | 9 | "" = [] | ^^ | "#]]) .run(); } #[cargo_test] fn same_name() { // Feature with the same name as a dependency. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] bar = ["baz"] baz = [] [dependencies.bar] path = "bar" "#, ) .file("src/main.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "1.0.0")) .file("bar/src/lib.rs", "") .build(); p.cargo("tree -f") .arg("{p} [{f}]") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version "#]]) .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) [] └── bar v1.0.0 ([ROOT]/foo/bar) [] "#]]) .run(); p.cargo("tree --features bar -f") .arg("{p} [{f}]") .with_stderr_data("") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) [bar,baz] └── bar v1.0.0 ([ROOT]/foo/bar) [] "#]]) .run(); } #[cargo_test] fn invalid3() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] bar = ["baz"] [dependencies.baz] path = "foo" "#, ) .file("src/main.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `bar` includes `baz`, but `baz` is not an optional dependency A non-optional dependency of the same name is defined; consider adding `optional = true` to its definition. "#]]) .run(); } #[cargo_test] fn invalid4() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" features = ["bar"] "#, ) .file("src/main.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to select a version for `bar`. ... required by package `foo v0.0.1 ([ROOT]/foo)` versions that meet the requirements `*` are: 0.0.1 the package `foo` depends on `bar`, with features: `bar` but `bar` does not have these features. failed to select a version for `bar` which could resolve this conflict "#]]) .run(); p.change_file("Cargo.toml", &basic_manifest("foo", "0.0.1")); p.cargo("check --features test") .with_status(101) .with_stderr_data(str![[r#" [ERROR] Package `foo v0.0.1 ([ROOT]/foo)` does not have the feature `test` "#]]) .run(); } #[cargo_test] fn invalid5() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dev-dependencies.bar] path = "bar" optional = true "#, ) .file("src/main.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: dev-dependencies are not allowed to be optional: `bar` "#]]) .run(); } #[cargo_test] fn invalid6() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] foo = ["bar/baz"] "#, ) .file("src/main.rs", "") .build(); p.cargo("check --features foo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] feature `foo` includes `bar/baz`, but `bar` is not a dependency --> Cargo.toml:9:23 | 9 | foo = ["bar/baz"] | ^^^^^^^^^^^ | [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` "#]]) .run(); } #[cargo_test] fn invalid7() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] foo = ["bar/baz"] bar = [] "#, ) .file("src/main.rs", "") .build(); p.cargo("check --features foo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] feature `foo` includes `bar/baz`, but `bar` is not a dependency --> Cargo.toml:9:23 | 9 | foo = ["bar/baz"] | ^^^^^^^^^^^ | [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` "#]]) .run(); } #[cargo_test] fn invalid8() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" features = ["foo/bar"] "#, ) .file("src/main.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("check --features foo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `foo/bar` in dependency `bar` is not allowed to contain slashes If you want to enable features [..] "#]]) .run(); } #[cargo_test] fn invalid9() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("check --features bar") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [ERROR] Package `foo v0.0.1 ([ROOT]/foo)` does not have feature `bar`. It has a required dependency with that name, but only optional dependencies can be used as features. "#]]) .with_status(101) .run(); } #[cargo_test] fn invalid10() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" features = ["baz"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies.baz] path = "baz" "#, ) .file("bar/src/lib.rs", "") .file("bar/baz/Cargo.toml", &basic_manifest("baz", "0.0.1")) .file("bar/baz/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [ERROR] failed to select a version for `bar`. ... required by package `foo v0.0.1 ([ROOT]/foo)` versions that meet the requirements `*` are: 0.0.1 the package `foo` depends on `bar`, with features: `baz` but `bar` does not have these features. It has a required dependency with that name, but only optional dependencies can be used as features. failed to select a version for `bar` which could resolve this conflict "#]]) .with_status(101) .run(); } #[cargo_test] fn no_transitive_dep_feature_requirement() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.derived] path = "derived" [features] default = ["derived/bar/qux"] "#, ) .file( "src/main.rs", r#" extern crate derived; fn main() { derived::test(); } "#, ) .file( "derived/Cargo.toml", r#" [package] name = "derived" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" "#, ) .file("derived/src/lib.rs", "extern crate bar; pub use bar::test;") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [features] qux = [] "#, ) .file( "bar/src/lib.rs", r#" #[cfg(feature = "qux")] pub fn test() { print!("test"); } "#, ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: multiple slashes in feature `derived/bar/qux` (included by feature `default`) are not allowed "#]]) .run(); } #[cargo_test] fn no_feature_doesnt_build() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" optional = true "#, ) .file( "src/main.rs", r#" #[cfg(feature = "bar")] extern crate bar; #[cfg(feature = "bar")] fn main() { bar::bar(); println!("bar") } #[cfg(not(feature = "bar"))] fn main() {} "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("build") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.process(&p.bin("foo")).with_stdout_data("").run(); let expected = if cfg!(target_os = "windows") && cfg!(target_env = "msvc") { str![[r#" [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar [..]` [DIRTY] foo v0.0.1 ([ROOT]/foo): the list of features changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] } else { str![[r#" [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar [..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] }; p.cargo("build --features bar -v") .with_stderr_data(expected) .run(); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" bar "#]]) .run(); } #[cargo_test] fn default_feature_pulled_in() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] default = ["bar"] [dependencies.bar] path = "bar" optional = true "#, ) .file( "src/main.rs", r#" #[cfg(feature = "bar")] extern crate bar; #[cfg(feature = "bar")] fn main() { bar::bar(); println!("bar") } #[cfg(not(feature = "bar"))] fn main() {} "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("build") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" bar "#]]) .run(); let expected = if cfg!(target_os = "windows") && cfg!(target_env = "msvc") { str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the list of features changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] } else { str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] }; p.cargo("build --no-default-features -v") .with_stderr_data(expected) .run(); p.process(&p.bin("foo")).with_stdout_data("").run(); } #[cargo_test] fn cyclic_feature() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] default = ["default"] "#, ) .file("src/main.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cyclic feature dependency: feature `default` depends on itself "#]]) .run(); } #[cargo_test] fn cyclic_feature2() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] foo = ["bar"] bar = ["foo"] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn groups_on_groups_on_groups() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] default = ["f1"] f1 = ["f2", "bar"] f2 = ["f3", "f4"] f3 = ["f5", "f6", "baz"] f4 = ["f5", "f7"] f5 = ["f6"] f6 = ["f7"] f7 = ["bar"] [dependencies.bar] path = "bar" optional = true [dependencies.baz] path = "baz" optional = true "#, ) .file( "src/main.rs", r#" #[allow(unused_extern_crates)] extern crate bar; #[allow(unused_extern_crates)] extern crate baz; fn main() {} "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("check") .with_stderr_data( str![[r#" [LOCKING] 2 packages to latest compatible versions [CHECKING] bar v0.0.1 ([ROOT]/foo/bar) [CHECKING] baz v0.0.1 ([ROOT]/foo/baz) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn many_cli_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" optional = true [dependencies.baz] path = "baz" optional = true "#, ) .file( "src/main.rs", r#" #[allow(unused_extern_crates)] extern crate bar; #[allow(unused_extern_crates)] extern crate baz; fn main() {} "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("check --features") .arg("bar baz") .with_stderr_data( str![[r#" [LOCKING] 2 packages to latest compatible versions [CHECKING] bar v0.0.1 ([ROOT]/foo/bar) [CHECKING] baz v0.0.1 ([ROOT]/foo/baz) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn union_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.d1] path = "d1" features = ["f1"] [dependencies.d2] path = "d2" features = ["f2"] "#, ) .file( "src/main.rs", r#" #[allow(unused_extern_crates)] extern crate d1; extern crate d2; fn main() { d2::f1(); d2::f2(); } "#, ) .file( "d1/Cargo.toml", r#" [package] name = "d1" version = "0.0.1" edition = "2015" authors = [] [features] f1 = ["d2"] [dependencies.d2] path = "../d2" features = ["f1"] optional = true "#, ) .file("d1/src/lib.rs", "") .file( "d2/Cargo.toml", r#" [package] name = "d2" version = "0.0.1" edition = "2015" authors = [] [features] f1 = [] f2 = [] "#, ) .file( "d2/src/lib.rs", r#" #[cfg(feature = "f1")] pub fn f1() {} #[cfg(feature = "f2")] pub fn f2() {} "#, ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [CHECKING] d2 v0.0.1 ([ROOT]/foo/d2) [CHECKING] d1 v0.0.1 ([ROOT]/foo/d1) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn many_features_no_rebuilds() { let p = project() .file( "Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2015" authors = [] [dependencies.a] path = "a" features = ["fall"] "#, ) .file("src/main.rs", "fn main() {}") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" authors = [] [features] ftest = [] ftest2 = [] fall = ["ftest", "ftest2"] "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] a v0.1.0 ([ROOT]/foo/a) [CHECKING] b v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.root().move_into_the_past(); p.cargo("check -v") .with_stderr_data(str![[r#" [FRESH] a v0.1.0 ([ROOT]/foo/a) [FRESH] b v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } // Tests that all cmd lines work with `--features ""` #[cargo_test] fn empty_features() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("check --features").arg("").run(); } // Tests that all cmd lines work with `--features ""` #[cargo_test] fn transitive_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] foo = ["bar/baz"] [dependencies.bar] path = "bar" "#, ) .file("src/main.rs", "extern crate bar; fn main() { bar::baz(); }") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [features] baz = [] "#, ) .file( "bar/src/lib.rs", r#"#[cfg(feature = "baz")] pub fn baz() {}"#, ) .build(); p.cargo("check --features foo").run(); } #[cargo_test] fn everything_in_the_lockfile() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] f1 = ["d1/f1"] f2 = ["d2"] [dependencies.d1] path = "d1" [dependencies.d2] path = "d2" optional = true [dependencies.d3] path = "d3" optional = true "#, ) .file("src/main.rs", "fn main() {}") .file( "d1/Cargo.toml", r#" [package] name = "d1" version = "0.0.1" edition = "2015" authors = [] [features] f1 = [] "#, ) .file("d1/src/lib.rs", "") .file("d2/Cargo.toml", &basic_manifest("d2", "0.0.2")) .file("d2/src/lib.rs", "") .file( "d3/Cargo.toml", r#" [package] name = "d3" version = "0.0.3" edition = "2015" authors = [] [features] f3 = [] "#, ) .file("d3/src/lib.rs", "") .build(); p.cargo("fetch").run(); let lockfile = p.read_lockfile(); assert!( lockfile.contains(r#"name = "d1""#), "d1 not found\n{}", lockfile ); assert!( lockfile.contains(r#"name = "d2""#), "d2 not found\n{}", lockfile ); assert!( lockfile.contains(r#"name = "d3""#), "d3 not found\n{}", lockfile ); } #[cargo_test] fn no_rebuild_when_frobbing_default_feature() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] a = { path = "a" } b = { path = "b" } "#, ) .file("src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2015" authors = [] [dependencies] a = { path = "../a", features = ["f1"], default-features = false } "#, ) .file("b/src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" authors = [] [features] default = ["f1"] f1 = [] "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("check").run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn unions_work_with_no_default_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] a = { path = "a" } b = { path = "b" } "#, ) .file("src/lib.rs", "extern crate a; pub fn foo() { a::a(); }") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2015" authors = [] [dependencies] a = { path = "../a", features = [], default-features = false } "#, ) .file("b/src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" authors = [] [features] default = ["f1"] f1 = [] "#, ) .file("a/src/lib.rs", r#"#[cfg(feature = "f1")] pub fn a() {}"#) .build(); p.cargo("check").run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn optional_and_dev_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.1.0" edition = "2015" authors = [] [dependencies] foo = { path = "foo", optional = true } [dev-dependencies] foo = { path = "foo" } "#, ) .file("src/lib.rs", "") .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] test v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn activating_feature_activates_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.1.0" edition = "2015" authors = [] [dependencies] foo = { path = "foo", optional = true } [features] a = ["foo/a"] "#, ) .file( "src/lib.rs", "extern crate foo; pub fn bar() { foo::bar(); }", ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [features] a = [] "#, ) .file("foo/src/lib.rs", r#"#[cfg(feature = "a")] pub fn bar() {}"#) .build(); p.cargo("check --features a -v").run(); } #[cargo_test] fn activating_feature_does_not_activate_transitive_dev_dependency() { let p = project() .no_manifest() .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.0" edition = "2021" [features] f = ["b/f"] [dependencies] b = { path = "../b" } "#, ) .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.0.0" edition = "2021" [features] f = ["c/f"] [dev-dependencies] c = { path = "../c" } "#, ) .file( "c/Cargo.toml", r#" [package] name = "c" version = "0.0.0" edition = "2021" [features] f = [] "#, ) .file("a/src/lib.rs", "") .file("b/src/lib.rs", "") .file("c/src/lib.rs", "compile_error!") .build(); p.cargo("check --manifest-path a/Cargo.toml --features f") .run(); } #[cargo_test] fn dep_feature_in_cmd_line() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.derived] path = "derived" "#, ) .file( "src/main.rs", r#" extern crate derived; fn main() { derived::test(); } "#, ) .file( "derived/Cargo.toml", r#" [package] name = "derived" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" [features] default = [] derived-feat = ["bar/some-feat"] "#, ) .file("derived/src/lib.rs", "extern crate bar; pub use bar::test;") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [features] some-feat = [] "#, ) .file( "bar/src/lib.rs", r#" #[cfg(feature = "some-feat")] pub fn test() { print!("test"); } "#, ) .build(); // The foo project requires that feature "some-feat" in "bar" is enabled. // Building without any features enabled should fail: p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" ... error[E0432]: unresolved import `bar::test` ... "#]]) .run(); // We should be able to enable the feature "derived-feat", which enables "some-feat", // on the command line. The feature is enabled, thus building should be successful: p.cargo("check --features derived/derived-feat").run(); // Trying to enable features of transitive dependencies is an error p.cargo("check --features bar/some-feat") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package `foo v0.0.1 ([ROOT]/foo)` does not have a dependency named `bar` "#]]) .run(); // Hierarchical feature specification should still be disallowed p.cargo("check --features derived/bar/some-feat") .with_status(101) .with_stderr_data(str![[r#" [ERROR] multiple slashes in feature `derived/bar/some-feat` is not allowed "#]]) .run(); } #[cargo_test] fn all_features_flag_enables_all_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] foo = [] bar = [] [dependencies.baz] path = "baz" optional = true "#, ) .file( "src/main.rs", r#" #[cfg(feature = "foo")] pub fn foo() {} #[cfg(feature = "bar")] pub fn bar() { extern crate baz; baz::baz(); } fn main() { foo(); bar(); } "#, ) .file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("check --all-features").run(); } #[cargo_test] fn many_cli_features_comma_delimited() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" optional = true [dependencies.baz] path = "baz" optional = true "#, ) .file( "src/main.rs", r#" #[allow(unused_extern_crates)] extern crate bar; #[allow(unused_extern_crates)] extern crate baz; fn main() {} "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("check --features bar,baz") .with_stderr_data( str![[r#" [LOCKING] 2 packages to latest compatible versions [CHECKING] bar v0.0.1 ([ROOT]/foo/bar) [CHECKING] baz v0.0.1 ([ROOT]/foo/baz) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn many_cli_features_comma_and_space_delimited() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" optional = true [dependencies.baz] path = "baz" optional = true [dependencies.bam] path = "bam" optional = true [dependencies.bap] path = "bap" optional = true "#, ) .file( "src/main.rs", r#" #[allow(unused_extern_crates)] extern crate bar; #[allow(unused_extern_crates)] extern crate baz; #[allow(unused_extern_crates)] extern crate bam; #[allow(unused_extern_crates)] extern crate bap; fn main() {} "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1")) .file("baz/src/lib.rs", "pub fn baz() {}") .file("bam/Cargo.toml", &basic_manifest("bam", "0.0.1")) .file("bam/src/lib.rs", "pub fn bam() {}") .file("bap/Cargo.toml", &basic_manifest("bap", "0.0.1")) .file("bap/src/lib.rs", "pub fn bap() {}") .build(); p.cargo("check --features") .arg("bar,baz bam bap") .with_stderr_data( str![[r#" [LOCKING] 4 packages to latest compatible versions [CHECKING] bam v0.0.1 ([ROOT]/foo/bam) [CHECKING] bap v0.0.1 ([ROOT]/foo/bap) [CHECKING] bar v0.0.1 ([ROOT]/foo/bar) [CHECKING] baz v0.0.1 ([ROOT]/foo/baz) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn only_dep_is_optional() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] foo = ['bar'] [dependencies] bar = { version = "0.1", optional = true } [dev-dependencies] bar = "0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check").run(); } #[cargo_test] fn all_features_all_crates() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [workspace] members = ['bar'] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [features] foo = [] "#, ) .file("bar/src/main.rs", "#[cfg(feature = \"foo\")] fn main() {}") .build(); p.cargo("check --all-features --workspace").run(); } #[cargo_test] fn feature_off_dylib() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] [package] name = "foo" version = "0.0.1" edition = "2015" [lib] crate-type = ["dylib"] [features] f1 = [] "#, ) .file( "src/lib.rs", r#" pub fn hello() -> &'static str { if cfg!(feature = "f1") { "f1" } else { "no f1" } } "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" [dependencies] foo = { path = ".." } "#, ) .file( "bar/src/main.rs", r#" extern crate foo; fn main() { assert_eq!(foo::hello(), "no f1"); } "#, ) .build(); // Build the dylib with `f1` feature. p.cargo("check --features f1").run(); // Check that building without `f1` uses a dylib without `f1`. p.cargo("run -p bar").run(); } #[cargo_test] fn warn_if_default_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" optional = true [features] default-features = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] `default-features = [".."]` was found in [features]. Did you mean to use `default = [".."]`? [LOCKING] 1 package to latest compatible version [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn no_feature_for_non_optional_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = { path = "bar" } "#, ) .file( "src/main.rs", r#" #[cfg(not(feature = "bar"))] fn main() { } "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [features] a = [] "#, ) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("check --features bar/a").run(); } #[cargo_test] fn features_option_given_twice() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] a = [] b = [] "#, ) .file( "src/main.rs", r#" #[cfg(all(feature = "a", feature = "b"))] fn main() {} "#, ) .build(); p.cargo("check --features a --features b").run(); } #[cargo_test] fn multi_multi_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] a = [] b = [] c = [] "#, ) .file( "src/main.rs", r#" #[cfg(all(feature = "a", feature = "b", feature = "c"))] fn main() {} "#, ) .build(); p.cargo("check --features a --features").arg("b c").run(); } #[cargo_test] fn cli_parse_ok() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] a = [] "#, ) .file( "src/main.rs", r#" #[cfg(feature = "a")] fn main() { assert_eq!(std::env::args().nth(1).unwrap(), "b"); } "#, ) .build(); p.cargo("run --features a b").run(); } #[cargo_test] fn all_features_virtual_ws() { // What happens with `--all-features` in the root of a virtual workspace. // Some of this behavior is a little strange (member dependencies also // have all features enabled, one might expect `f4` to be disabled). let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2018" [dependencies] b = {path="../b", optional=true} [features] default = ["f1"] f1 = [] f2 = [] "#, ) .file( "a/src/main.rs", r#" fn main() { if cfg!(feature="f1") { println!("f1"); } if cfg!(feature="f2") { println!("f2"); } #[cfg(feature="b")] b::f(); } "#, ) .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2015" [features] default = ["f3"] f3 = [] f4 = [] "#, ) .file( "b/src/lib.rs", r#" pub fn f() { if cfg!(feature="f3") { println!("f3"); } if cfg!(feature="f4") { println!("f4"); } } "#, ) .build(); p.cargo("run") .with_stdout_data(str![[r#" f1 "#]]) .run(); p.cargo("run --all-features") .with_stdout_data(str![[r#" f1 f2 f3 f4 "#]]) .run(); // In `a`, it behaves differently. :( p.cargo("run --all-features") .cwd("a") .with_stdout_data(str![[r#" f1 f2 f3 "#]]) .run(); } #[cargo_test] fn slash_optional_enables() { // --features dep/feat will enable `dep` and set its feature. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] dep = {path="dep", optional=true} "#, ) .file( "src/lib.rs", r#" #[cfg(not(feature="dep"))] compile_error!("dep not set"); "#, ) .file( "dep/Cargo.toml", r#" [package] name = "dep" version = "0.1.0" edition = "2015" [features] feat = [] "#, ) .file( "dep/src/lib.rs", r#" #[cfg(not(feature="feat"))] compile_error!("feat not set"); "#, ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] dep not set ... "#]]) .run(); p.cargo("check --features dep/feat").run(); } #[cargo_test] fn registry_summary_order_doesnt_matter() { // Checks for an issue where the resolver depended on the order of entries // in the registry summary. If there was a non-optional dev-dependency // that appeared before an optional normal dependency, then the resolver // would not activate the optional dependency with a pkg/featname feature // syntax. Package::new("dep", "0.1.0") .feature("feat1", &[]) .file( "src/lib.rs", r#" #[cfg(feature="feat1")] pub fn work() { println!("it works"); } "#, ) .publish(); Package::new("bar", "0.1.0") .feature("bar_feat", &["dep/feat1"]) .add_dep(Dependency::new("dep", "0.1.0").dev()) .add_dep(Dependency::new("dep", "0.1.0").optional(true)) .file( "src/lib.rs", r#" // This will fail to compile without `dep` optional dep activated. extern crate dep; pub fn doit() { dep::work(); } "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] bar = { version="0.1", features = ["bar_feat"] } "#, ) .file( "src/main.rs", r#" fn main() { bar::doit(); } "#, ) .build(); p.cargo("run") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] dep v0.1.0 (registry `dummy-registry`) [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [COMPILING] dep v0.1.0 [COMPILING] bar v0.1.0 [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .with_stdout_data(str![[r#" it works "#]]) .run(); } #[cargo_test] fn nonexistent_required_features() { Package::new("required_dependency", "0.1.0") .feature("simple", &[]) .publish(); Package::new("optional_dependency", "0.2.0") .feature("optional", &[]) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [features] existing = [] fancy = ["optional_dependency"] [dependencies] required_dependency = { version = "0.1", optional = false} optional_dependency = { version = "0.2", optional = true} [[example]] name = "ololo" required-features = ["not_present", "existing", "fancy", "required_dependency/not_existing", "required_dependency/simple", "optional_dependency/optional", "not_specified_dependency/some_feature"] "#, ) .file("src/main.rs", "fn main() {}") .file("examples/ololo.rs", "fn main() {}") .build(); p.cargo("check --examples").with_stderr_data(str![[r#" ... [WARNING] invalid feature `not_present` in required-features of target `ololo`: `not_present` is not present in [features] section [WARNING] invalid feature `required_dependency/not_existing` in required-features of target `ololo`: feature `not_existing` does not exist in package `required_dependency v0.1.0` [WARNING] invalid feature `not_specified_dependency/some_feature` in required-features of target `ololo`: dependency `not_specified_dependency` does not exist ... "#]]).run(); } #[cargo_test] fn invalid_feature_names_error() { // Errors for more restricted feature syntax. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [features] # Invalid start character. "+foo" = [] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid character `+` in feature name: `+foo`, the first character must be a Unicode XID start character or digit (most letters or `_` or `0` to `9`) --> Cargo.toml:9:17 | 9 | "+foo" = [] | ^^^^^^ | "#]]) .run(); p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [features] # Invalid continue character. "a&b" = [] "#, ); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid character `&` in feature name: `a&b`, characters must be Unicode XID characters, '-', `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters) --> Cargo.toml:9:13 | 9 | "a&b" = [] | ^^^^^ | "#]]) .run(); } #[cargo_test] fn invalid_feature_name_slash_error() { // Errors for more restricted feature syntax. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [features] "foo/bar" = [] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid character `/` in feature name: `foo/bar`, feature name is not allowed to contain slashes --> Cargo.toml:8:17 | 8 | "foo/bar" = [] | ^^^^^^^^^ | "#]]) .run(); } cargo-0.86.0/tests/testsuite/features2.rs000064400000000000000000002245401046102023000164620ustar 00000000000000//! Tests for the new feature resolver. use std::fs::File; use cargo_test_support::cross_compile::{self, alternate}; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::publish::validate_crate_contents; use cargo_test_support::registry::{Dependency, Package}; use cargo_test_support::str; use cargo_test_support::{basic_manifest, cargo_process, project, rustc_host, Project}; /// Switches Cargo.toml to use `resolver = "2"`. pub fn switch_to_resolver_2(p: &Project) { let mut manifest = p.read_file("Cargo.toml"); if manifest.contains("resolver =") { panic!("did not expect manifest to already contain a resolver setting"); } if let Some(index) = manifest.find("[workspace]\n") { manifest.insert_str(index + 12, "resolver = \"2\"\n"); } else if let Some(index) = manifest.find("[package]\n") { manifest.insert_str(index + 10, "resolver = \"2\"\n"); } else { panic!("expected [package] or [workspace] in manifest"); } p.change_file("Cargo.toml", &manifest); } #[cargo_test] fn inactivate_targets() { // Basic test of `itarget`. A shared dependency where an inactive [target] // changes the features. Package::new("common", "1.0.0") .feature("f1", &[]) .file( "src/lib.rs", r#" #[cfg(feature = "f1")] compile_error!("f1 should not activate"); "#, ) .publish(); Package::new("bar", "1.0.0") .add_dep( Dependency::new("common", "1.0") .target("cfg(whatever)") .enable_features(&["f1"]), ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] common = "1.0" bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data( str![[r#" ... [ERROR] f1 should not activate ... "#]] .unordered(), ) .run(); switch_to_resolver_2(&p); p.cargo("check").run(); } #[cargo_test] fn inactive_target_optional() { // Activating optional [target] dependencies for inactivate target. Package::new("common", "1.0.0") .feature("f1", &[]) .feature("f2", &[]) .feature("f3", &[]) .feature("f4", &[]) .file( "src/lib.rs", r#" pub fn f() { if cfg!(feature="f1") { println!("f1"); } if cfg!(feature="f2") { println!("f2"); } if cfg!(feature="f3") { println!("f3"); } if cfg!(feature="f4") { println!("f4"); } } "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] common = "1.0" [target.'cfg(whatever)'.dependencies] dep1 = {path='dep1', optional=true} dep2 = {path='dep2', optional=true, features=["f3"]} common = {version="1.0", optional=true, features=["f4"]} [features] foo1 = ["dep1/f2"] foo2 = ["dep2"] "#, ) .file( "src/main.rs", r#" fn main() { if cfg!(feature="foo1") { println!("foo1"); } if cfg!(feature="foo2") { println!("foo2"); } if cfg!(feature="dep1") { println!("dep1"); } if cfg!(feature="dep2") { println!("dep2"); } if cfg!(feature="common") { println!("common"); } common::f(); } "#, ) .file( "dep1/Cargo.toml", r#" [package] name = "dep1" version = "0.1.0" edition = "2015" [dependencies] common = {version="1.0", features=["f1"]} [features] f2 = ["common/f2"] "#, ) .file( "dep1/src/lib.rs", r#"compile_error!("dep1 should not build");"#, ) .file( "dep2/Cargo.toml", r#" [package] name = "dep2" version = "0.1.0" edition = "2015" [dependencies] common = "1.0" [features] f3 = ["common/f3"] "#, ) .file( "dep2/src/lib.rs", r#"compile_error!("dep2 should not build");"#, ) .build(); p.cargo("run --all-features") .with_stdout_data(str![[r#" foo1 foo2 dep1 dep2 common f1 f2 f3 f4 "#]]) .run(); p.cargo("run --features dep1") .with_stdout_data(str![[r#" dep1 f1 "#]]) .run(); p.cargo("run --features foo1") .with_stdout_data(str![[r#" foo1 dep1 f1 f2 "#]]) .run(); p.cargo("run --features dep2") .with_stdout_data(str![[r#" dep2 f3 "#]]) .run(); p.cargo("run --features common") .with_stdout_data(str![[r#" common f4 "#]]) .run(); switch_to_resolver_2(&p); p.cargo("run --all-features") .with_stdout_data(str![[r#" foo1 foo2 dep1 dep2 common "#]]) .run(); p.cargo("run --features dep1") .with_stdout_data(str![[r#" dep1 "#]]) .run(); p.cargo("run --features foo1") .with_stdout_data(str![[r#" foo1 "#]]) .run(); p.cargo("run --features dep2") .with_stdout_data(str![[r#" dep2 "#]]) .run(); p.cargo("run --features common") .with_stdout_data(str![[r#" common "#]]) .run(); } #[cargo_test] fn itarget_proc_macro() { // itarget inside a proc-macro while cross-compiling if cross_compile::disabled() { return; } Package::new("hostdep", "1.0.0").publish(); Package::new("pm", "1.0.0") .proc_macro(true) .target_dep("hostdep", "1.0", rustc_host()) .file("src/lib.rs", "extern crate hostdep;") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] pm = "1.0" "#, ) .file("src/lib.rs", "") .build(); // Old behavior p.cargo("check").run(); p.cargo("check --target").arg(alternate()).run(); // New behavior switch_to_resolver_2(&p); p.cargo("check").run(); p.cargo("check --target").arg(alternate()).run(); // For good measure, just make sure things don't break. p.cargo("check --target").arg(alternate()).run(); } #[cargo_test] fn decouple_host_deps() { // Basic test for `host_dep` decouple. Package::new("common", "1.0.0") .feature("f1", &[]) .file( "src/lib.rs", r#" #[cfg(feature = "f1")] pub fn foo() {} #[cfg(not(feature = "f1"))] pub fn bar() {} "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [build-dependencies] common = {version="1.0", features=["f1"]} [dependencies] common = "1.0" "#, ) .file( "build.rs", r#" use common::foo; fn main() {} "#, ) .file("src/lib.rs", "use common::bar;") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" ... error[E0432]: unresolved import `common::bar` ... "#]]) .run(); switch_to_resolver_2(&p); p.cargo("check").run(); } #[cargo_test] fn decouple_host_deps_nested() { // `host_dep` decouple of transitive dependencies. Package::new("common", "1.0.0") .feature("f1", &[]) .file( "src/lib.rs", r#" #[cfg(feature = "f1")] pub fn foo() {} #[cfg(not(feature = "f1"))] pub fn bar() {} "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [build-dependencies] bdep = {path="bdep"} [dependencies] common = "1.0" "#, ) .file( "build.rs", r#" use bdep::foo; fn main() {} "#, ) .file("src/lib.rs", "use common::bar;") .file( "bdep/Cargo.toml", r#" [package] name = "bdep" version = "0.1.0" edition = "2018" [dependencies] common = {version="1.0", features=["f1"]} "#, ) .file("bdep/src/lib.rs", "pub use common::foo;") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" ... error[E0432]: unresolved import `common::bar` ... "#]]) .run(); switch_to_resolver_2(&p); p.cargo("check").run(); } #[cargo_test] fn decouple_dev_deps() { // Basic test for `dev_dep` decouple. Package::new("common", "1.0.0") .feature("f1", &[]) .feature("f2", &[]) .file( "src/lib.rs", r#" // const ensures it uses the correct dependency at *build time* // compared to *link time*. #[cfg(all(feature="f1", not(feature="f2")))] pub const X: u32 = 1; #[cfg(all(feature="f1", feature="f2"))] pub const X: u32 = 3; pub fn foo() -> u32 { let mut res = 0; if cfg!(feature = "f1") { res |= 1; } if cfg!(feature = "f2") { res |= 2; } res } "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] common = {version="1.0", features=["f1"]} [dev-dependencies] common = {version="1.0", features=["f2"]} "#, ) .file( "src/main.rs", r#" fn main() { let expected: u32 = std::env::args().skip(1).next().unwrap().parse().unwrap(); assert_eq!(foo::foo(), expected); assert_eq!(foo::build_time(), expected); assert_eq!(common::foo(), expected); assert_eq!(common::X, expected); } #[test] fn test_bin() { assert_eq!(foo::foo(), 3); assert_eq!(common::foo(), 3); assert_eq!(common::X, 3); assert_eq!(foo::build_time(), 3); } "#, ) .file( "src/lib.rs", r#" pub fn foo() -> u32 { common::foo() } pub fn build_time() -> u32 { common::X } #[test] fn test_lib() { assert_eq!(foo(), 3); assert_eq!(common::foo(), 3); assert_eq!(common::X, 3); } "#, ) .file( "tests/t1.rs", r#" #[test] fn test_t1() { assert_eq!(foo::foo(), 3); assert_eq!(common::foo(), 3); assert_eq!(common::X, 3); assert_eq!(foo::build_time(), 3); } #[test] fn test_main() { // Features are unified for main when run with `cargo test`, // even with the new resolver. let s = std::process::Command::new("target/debug/foo") .arg("3") .status().unwrap(); assert!(s.success()); } "#, ) .build(); // Old behavior p.cargo("run 3").run(); p.cargo("test").run(); // New behavior switch_to_resolver_2(&p); p.cargo("run 1").run(); p.cargo("test").run(); } #[cargo_test] fn build_script_runtime_features() { // Check that the CARGO_FEATURE_* environment variable is set correctly. // // This has a common dependency between build/normal/dev-deps, and it // queries which features it was built with in different circumstances. Package::new("common", "1.0.0") .feature("normal", &[]) .feature("dev", &[]) .feature("build", &[]) .file( "build.rs", r#" fn is_set(name: &str) -> bool { std::env::var(name) == Ok("1".to_string()) } fn main() { let mut res = 0; if is_set("CARGO_FEATURE_NORMAL") { res |= 1; } if is_set("CARGO_FEATURE_DEV") { res |= 2; } if is_set("CARGO_FEATURE_BUILD") { res |= 4; } println!("cargo::rustc-cfg=RunCustomBuild=\"{}\"", res); let mut res = 0; if cfg!(feature = "normal") { res |= 1; } if cfg!(feature = "dev") { res |= 2; } if cfg!(feature = "build") { res |= 4; } println!("cargo::rustc-cfg=CustomBuild=\"{}\"", res); } "#, ) .file( "src/lib.rs", r#" pub fn foo() -> u32 { let mut res = 0; if cfg!(feature = "normal") { res |= 1; } if cfg!(feature = "dev") { res |= 2; } if cfg!(feature = "build") { res |= 4; } res } pub fn build_time() -> u32 { #[cfg(RunCustomBuild="1")] return 1; #[cfg(RunCustomBuild="3")] return 3; #[cfg(RunCustomBuild="4")] return 4; #[cfg(RunCustomBuild="5")] return 5; #[cfg(RunCustomBuild="7")] return 7; } "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [build-dependencies] common = {version="1.0", features=["build"]} [dependencies] common = {version="1.0", features=["normal"]} [dev-dependencies] common = {version="1.0", features=["dev"]} "#, ) .file( "build.rs", r#" fn main() { assert_eq!(common::foo(), common::build_time()); println!("cargo::rustc-cfg=from_build=\"{}\"", common::foo()); } "#, ) .file( "src/lib.rs", r#" pub fn foo() -> u32 { common::foo() } pub fn build_time() -> u32 { common::build_time() } #[test] fn test_lib() { assert_eq!(common::foo(), common::build_time()); assert_eq!(common::foo(), std::env::var("CARGO_FEATURE_EXPECT").unwrap().parse().unwrap()); } "#, ) .file( "src/main.rs", r#" fn main() { assert_eq!(common::foo(), common::build_time()); assert_eq!(common::foo(), std::env::var("CARGO_FEATURE_EXPECT").unwrap().parse().unwrap()); } #[test] fn test_bin() { assert_eq!(common::foo(), common::build_time()); assert_eq!(common::foo(), std::env::var("CARGO_FEATURE_EXPECT").unwrap().parse().unwrap()); } "#, ) .file( "tests/t1.rs", r#" #[test] fn test_t1() { assert_eq!(common::foo(), common::build_time()); assert_eq!(common::foo(), std::env::var("CARGO_FEATURE_EXPECT").unwrap().parse().unwrap()); } #[test] fn test_main() { // Features are unified for main when run with `cargo test`, // even with the new resolver. let s = std::process::Command::new("target/debug/foo") .status().unwrap(); assert!(s.success()); } "#, ) .build(); // Old way, unifies all 3. p.cargo("run").env("CARGO_FEATURE_EXPECT", "7").run(); p.cargo("test").env("CARGO_FEATURE_EXPECT", "7").run(); // New behavior. switch_to_resolver_2(&p); // normal + build unify p.cargo("run").env("CARGO_FEATURE_EXPECT", "1").run(); // dev_deps are still unified with `cargo test` p.cargo("test").env("CARGO_FEATURE_EXPECT", "3").run(); } #[cargo_test] fn cyclical_dev_dep() { // Check how a cyclical dev-dependency will work. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [features] dev = [] [dev-dependencies] foo = { path = '.', features = ["dev"] } "#, ) .file( "src/lib.rs", r#" pub fn assert_dev(enabled: bool) { assert_eq!(enabled, cfg!(feature="dev")); } #[test] fn test_in_lib() { assert_dev(true); } "#, ) .file( "src/main.rs", r#" fn main() { let expected: bool = std::env::args().skip(1).next().unwrap().parse().unwrap(); foo::assert_dev(expected); } "#, ) .file( "tests/t1.rs", r#" #[test] fn integration_links() { foo::assert_dev(true); // The lib linked with main.rs will also be unified. let s = std::process::Command::new("target/debug/foo") .arg("true") .status().unwrap(); assert!(s.success()); } "#, ) .build(); // Old way unifies features. p.cargo("run true").run(); // dev feature should always be enabled in tests. p.cargo("test").run(); // New behavior. switch_to_resolver_2(&p); // Should decouple main. p.cargo("run false").run(); // And this should be no different. p.cargo("test").run(); } #[cargo_test] fn all_feature_opts() { // All feature options at once. Package::new("common", "1.0.0") .feature("normal", &[]) .feature("build", &[]) .feature("dev", &[]) .feature("itarget", &[]) .file( "src/lib.rs", r#" pub fn feats() -> u32 { let mut res = 0; if cfg!(feature="normal") { res |= 1; } if cfg!(feature="build") { res |= 2; } if cfg!(feature="dev") { res |= 4; } if cfg!(feature="itarget") { res |= 8; } res } "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] common = {version = "1.0", features=["normal"]} [dev-dependencies] common = {version = "1.0", features=["dev"]} [build-dependencies] common = {version = "1.0", features=["build"]} [target.'cfg(whatever)'.dependencies] common = {version = "1.0", features=["itarget"]} "#, ) .file( "src/main.rs", r#" fn main() { expect(); } fn expect() { let expected: u32 = std::env::var("EXPECTED_FEATS").unwrap().parse().unwrap(); assert_eq!(expected, common::feats()); } #[test] fn from_test() { expect(); } "#, ) .build(); p.cargo("run").env("EXPECTED_FEATS", "15").run(); p.cargo("test").env("EXPECTED_FEATS", "15").run(); // New behavior. switch_to_resolver_2(&p); // Only normal feature. p.cargo("run").env("EXPECTED_FEATS", "1").run(); // only normal+dev p.cargo("test").env("EXPECTED_FEATS", "5").run(); } #[cargo_test] fn required_features_host_dep() { // Check that required-features handles build-dependencies correctly. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [[bin]] name = "x" required-features = ["bdep/f1"] [build-dependencies] bdep = {path="bdep"} "#, ) .file("build.rs", "fn main() {}") .file( "src/bin/x.rs", r#" fn main() {} "#, ) .file( "bdep/Cargo.toml", r#" [package] name = "bdep" version = "0.1.0" edition = "2015" [features] f1 = [] "#, ) .file("bdep/src/lib.rs", "") .build(); p.cargo("run") .with_status(101) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [ERROR] target `x` in package `foo` requires the features: `bdep/f1` Consider enabling them by passing, e.g., `--features="bdep/f1"` "#]]) .run(); // New behavior. switch_to_resolver_2(&p); p.cargo("run --features bdep/f1").run(); } #[cargo_test] fn disabled_shared_host_dep() { // Check for situation where an optional dep of a shared dep is enabled in // a normal dependency, but disabled in an optional one. The unit tree is: // foo // β”œβ”€β”€ foo build.rs // | └── common (BUILD dependency, NO FEATURES) // └── common (Normal dependency, default features) // └── somedep Package::new("somedep", "1.0.0") .file( "src/lib.rs", r#" pub fn f() { println!("hello from somedep"); } "#, ) .publish(); Package::new("common", "1.0.0") .feature("default", &["somedep"]) .add_dep(Dependency::new("somedep", "1.0").optional(true)) .file( "src/lib.rs", r#" pub fn check_somedep() -> bool { #[cfg(feature="somedep")] { extern crate somedep; somedep::f(); true } #[cfg(not(feature="somedep"))] { println!("no somedep"); false } } "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2018" resolver = "2" [dependencies] common = "1.0" [build-dependencies] common = {version = "1.0", default-features = false} "#, ) .file( "src/main.rs", "fn main() { assert!(common::check_somedep()); }", ) .file( "build.rs", "fn main() { assert!(!common::check_somedep()); }", ) .build(); p.cargo("run -v") .with_stdout_data(str![[r#" hello from somedep "#]]) .run(); } #[cargo_test] fn required_features_inactive_dep() { // required-features with an inactivated dep. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" resolver = "2" [target.'cfg(whatever)'.dependencies] bar = {path="bar"} [[bin]] name = "foo" required-features = ["feat1"] [features] feat1 = [] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check --features=feat1") .with_stderr_data(str![[r#" [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn decouple_proc_macro() { // proc macro features are not shared Package::new("common", "1.0.0") .feature("somefeat", &[]) .file( "src/lib.rs", r#" pub const fn foo() -> bool { cfg!(feature="somefeat") } #[cfg(feature="somefeat")] pub const FEAT_ONLY_CONST: bool = true; "#, ) .publish(); Package::new("pm", "1.0.0") .proc_macro(true) .feature_dep("common", "1.0", &["somefeat"]) .file( "src/lib.rs", r#" extern crate proc_macro; extern crate common; #[proc_macro] pub fn foo(input: proc_macro::TokenStream) -> proc_macro::TokenStream { assert!(common::foo()); "".parse().unwrap() } "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2018" [dependencies] pm = "1.0" common = "1.0" "#, ) .file( "src/lib.rs", r#" //! Test with docs. //! //! ```rust //! pm::foo!{} //! fn main() { //! let expected = std::env::var_os("TEST_EXPECTS_ENABLED").is_some(); //! assert_eq!(expected, common::foo(), "common is wrong"); //! } //! ``` "#, ) .file( "src/main.rs", r#" pm::foo!{} fn main() { println!("it is {}", common::foo()); } "#, ) .build(); p.cargo("run") .env("TEST_EXPECTS_ENABLED", "1") .with_stdout_data(str![[r#" it is true "#]]) .run(); // Make sure the test is fallible. p.cargo("test --doc") .with_status(101) .with_stdout_data("...\n[..]common is wrong[..]\n...") .run(); p.cargo("test --doc").env("TEST_EXPECTS_ENABLED", "1").run(); p.cargo("doc").run(); assert!(p .build_dir() .join("doc/common/constant.FEAT_ONLY_CONST.html") .exists()); // cargo doc should clean in-between runs, but it doesn't, and leaves stale files. // https://github.com/rust-lang/cargo/issues/6783 (same for removed items) p.build_dir().join("doc").rm_rf(); // New behavior. switch_to_resolver_2(&p); p.cargo("run") .with_stdout_data(str![[r#" it is false "#]]) .run(); p.cargo("test --doc").run(); p.cargo("doc").run(); assert!(!p .build_dir() .join("doc/common/constant.FEAT_ONLY_CONST.html") .exists()); } #[cargo_test] fn proc_macro_ws() { // Checks for bug with proc-macro in a workspace with dependency (shouldn't panic). // // Note, debuginfo is explicitly requested here to preserve the intent of this non-regression // test: that will disable the debuginfo build dependencies optimization. Otherwise, it would // initially trigger when the crates are built independently, but rebuild them with debuginfo // when it sees the shared build/runtime dependency when checking the complete workspace. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo", "pm"] resolver = "2" [profile.dev.build-override] debug = true "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [features] feat1 = [] "#, ) .file("foo/src/lib.rs", "") .file( "pm/Cargo.toml", r#" [package] name = "pm" version = "0.1.0" edition = "2015" [lib] proc-macro = true [dependencies] foo = { path = "../foo", features=["feat1"] } "#, ) .file("pm/src/lib.rs", "") .build(); p.cargo("check -p pm -v") .with_stderr_data(str![[r#" ... [RUNNING] `rustc --crate-name foo [..]--cfg[..]feat1[..]` ... "#]]) .run(); // This may be surprising that `foo` doesn't get built separately. It is // because pm might have other units (binaries, tests, etc.), and so the // feature resolver must assume that normal deps get unified with it. This // is related to the bigger issue where the features selected in a // workspace depend on which packages are selected. p.cargo("check --workspace -v") .with_stderr_data(str![[r#" [FRESH] foo v0.1.0 ([ROOT]/foo/foo) [FRESH] pm v0.1.0 ([ROOT]/foo/pm) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Selecting just foo will build without unification. p.cargo("check -p foo -v") // Make sure `foo` is built without feat1 .with_stderr_line_without( &["[RUNNING] `rustc --crate-name foo --edition=2015"], &["--cfg[..]feat1"], ) .run(); } #[cargo_test] fn has_dev_dep_for_test() { // Check for a bug where the decision on whether or not "dev dependencies" // should be used did not consider `check --profile=test`. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dev-dependencies] dep = { path = 'dep', features = ['f1'] } "#, ) .file( "src/lib.rs", r#" #[test] fn t1() { dep::f(); } "#, ) .file( "dep/Cargo.toml", r#" [package] name = "dep" version = "0.1.0" edition = "2015" [features] f1 = [] "#, ) .file( "dep/src/lib.rs", r#" #[cfg(feature = "f1")] pub fn f() {} "#, ) .build(); p.cargo("check -v") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check -v --profile=test") .with_stderr_data(str![[r#" [CHECKING] dep v0.1.0 ([ROOT]/foo/dep) [RUNNING] `rustc --crate-name dep [..]` [CHECKING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // New resolver should not be any different. switch_to_resolver_2(&p); p.cargo("check -v --profile=test") .with_stderr_data(str![[r#" [FRESH] dep v0.1.0 ([ROOT]/foo/dep) [FRESH] foo v0.1.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_dep_activated() { // Build dependencies always match the host for [target.*.build-dependencies]. if cross_compile::disabled() { return; } Package::new("somedep", "1.0.0") .file("src/lib.rs", "") .publish(); Package::new("targetdep", "1.0.0").publish(); Package::new("hostdep", "1.0.0") // Check that "for_host" is sticky. .target_dep("somedep", "1.0", rustc_host()) .feature("feat1", &[]) .file( "src/lib.rs", r#" extern crate somedep; #[cfg(not(feature="feat1"))] compile_error!{"feat1 missing"} "#, ) .publish(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" # This should never be selected. [target.'{}'.build-dependencies] targetdep = "1.0" [target.'{}'.build-dependencies] hostdep = {{version="1.0", features=["feat1"]}} "#, alternate(), rustc_host() ), ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); p.cargo("check").run(); p.cargo("check --target").arg(alternate()).run(); // New behavior. switch_to_resolver_2(&p); p.cargo("check").run(); p.cargo("check --target").arg(alternate()).run(); } #[cargo_test] fn resolver_bad_setting() { // Unknown setting in `resolver` let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" resolver = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `resolver` setting `foo` is not valid, valid options are "1" or "2" "#]]) .run(); } #[cargo_test] fn resolver_original() { // resolver="1" uses old unification behavior. Package::new("common", "1.0.0") .feature("f1", &[]) .file( "src/lib.rs", r#" #[cfg(feature = "f1")] compile_error!("f1 should not activate"); "#, ) .publish(); Package::new("bar", "1.0.0") .add_dep( Dependency::new("common", "1.0") .target("cfg(whatever)") .enable_features(&["f1"]), ) .publish(); let manifest = |resolver| { format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" resolver = "{}" [dependencies] common = "1.0" bar = "1.0" "#, resolver ) }; let p = project() .file("Cargo.toml", &manifest("1")) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data( str![[r#" ... [ERROR] f1 should not activate ... "#]] .unordered(), ) .run(); p.change_file("Cargo.toml", &manifest("2")); p.cargo("check").run(); } #[cargo_test] fn resolver_not_both() { // Can't specify resolver in both workspace and package. let p = project() .file( "Cargo.toml", r#" [workspace] resolver = "2" [package] name = "foo" version = "0.1.0" edition = "2015" resolver = "2" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: cannot specify `resolver` field in both `[workspace]` and `[package]` "#]]) .run(); } #[cargo_test] fn resolver_ws_member() { // Can't specify `resolver` in a ws member. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" resolver = "2" "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] resolver for the non root package will be ignored, specify resolver at the workspace root: package: [ROOT]/foo/a/Cargo.toml workspace: [ROOT]/foo/Cargo.toml [CHECKING] a v0.1.0 ([ROOT]/foo/a) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[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_data(str![[r#" [WARNING] virtual workspace defaulting to `resolver = "1"` despite one or more workspace members being on edition 2021 which implies `resolver = "2"` [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 [NOTE] for more details see https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions [CHECKING] a v0.1.0 ([ROOT]/foo/a) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn resolver_ws_root_and_member() { // Check when specified in both ws root and member. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a"] resolver = "2" "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" resolver = "2" "#, ) .file("a/src/lib.rs", "") .build(); // Ignores if they are the same. p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] a v0.1.0 ([ROOT]/foo/a) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn resolver_enables_new_features() { // resolver="2" enables all the things. Package::new("common", "1.0.0") .feature("normal", &[]) .feature("build", &[]) .feature("dev", &[]) .feature("itarget", &[]) .file( "src/lib.rs", r#" pub fn feats() -> u32 { let mut res = 0; if cfg!(feature="normal") { res |= 1; } if cfg!(feature="build") { res |= 2; } if cfg!(feature="dev") { res |= 4; } if cfg!(feature="itarget") { res |= 8; } res } "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] resolver = "2" "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2018" [dependencies] common = {version = "1.0", features=["normal"]} [dev-dependencies] common = {version = "1.0", features=["dev"]} [build-dependencies] common = {version = "1.0", features=["build"]} [target.'cfg(whatever)'.dependencies] common = {version = "1.0", features=["itarget"]} "#, ) .file( "a/src/main.rs", r#" fn main() { expect(); } fn expect() { let expected: u32 = std::env::var("EXPECTED_FEATS").unwrap().parse().unwrap(); assert_eq!(expected, common::feats()); } #[test] fn from_test() { expect(); } "#, ) .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2015" [features] ping = [] "#, ) .file( "b/src/main.rs", r#" fn main() { if cfg!(feature="ping") { println!("pong"); } } "#, ) .build(); // Only normal. p.cargo("run --bin a") .env("EXPECTED_FEATS", "1") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] common v1.0.0 (registry `dummy-registry`) [COMPILING] common v1.0.0 [COMPILING] a v0.1.0 ([ROOT]/foo/a) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/a[EXE]` "#]]) .run(); // only normal+dev p.cargo("test").cwd("a").env("EXPECTED_FEATS", "5").run(); // Can specify features of packages from a different directory. p.cargo("run -p b --features=ping") .cwd("a") .with_stdout_data(str![[r#" pong "#]]) .run(); } #[cargo_test] fn install_resolve_behavior() { // install honors the resolver behavior. Package::new("common", "1.0.0") .feature("f1", &[]) .file( "src/lib.rs", r#" #[cfg(feature = "f1")] compile_error!("f1 should not activate"); "#, ) .publish(); Package::new("bar", "1.0.0").dep("common", "1.0").publish(); Package::new("foo", "1.0.0") .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" resolver = "2" [target.'cfg(whatever)'.dependencies] common = {version="1.0", features=["f1"]} [dependencies] bar = "1.0" "#, ) .file("src/main.rs", "fn main() {}") .publish(); cargo_process("install foo").run(); } #[cargo_test] fn package_includes_resolve_behavior() { // `cargo package` will inherit the correct resolve behavior. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a"] resolver = "2" "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" authors = ["Zzz"] description = "foo" license = "MIT" homepage = "https://example.com/" "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("package").cwd("a").run(); let rewritten_toml = str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "a" version = "0.1.0" authors = ["Zzz"] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" homepage = "https://example.com/" readme = false license = "MIT" resolver = "2" [lib] name = "a" path = "src/lib.rs" "##]]; let f = File::open(&p.root().join("target/package/a-0.1.0.crate")).unwrap(); validate_crate_contents( f, "a-0.1.0.crate", &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "Cargo.lock"], [("Cargo.toml", rewritten_toml)], ); } #[cargo_test] fn tree_all() { // `cargo tree` with the new feature resolver. Package::new("log", "0.4.8").feature("serde", &[]).publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" resolver = "2" [target.'cfg(whatever)'.dependencies] log = {version="*", features=["serde"]} "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree --target=all") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── log v0.4.8 "#]]) .run(); } #[cargo_test] fn shared_dep_same_but_dependencies() { // Checks for a bug of nondeterminism. This scenario creates a shared // dependency `dep` which needs to be built twice (once as normal, and // once as a build dep). However, in both cases the flags to `dep` are the // same, the only difference is what it links to. The normal dependency // should link to `subdep` with the feature disabled, and the build // dependency should link to it with it enabled. Crucially, the `--target` // flag should not be specified, otherwise Unit.kind would be different // and avoid the collision, and this bug won't manifest. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bin1", "bin2"] resolver = "2" "#, ) .file( "bin1/Cargo.toml", r#" [package] name = "bin1" version = "0.1.0" edition = "2015" [dependencies] dep = { path = "../dep" } "#, ) .file("bin1/src/main.rs", "fn main() { dep::feat_func(); }") .file( "bin2/Cargo.toml", r#" [package] name = "bin2" version = "0.1.0" edition = "2015" [build-dependencies] dep = { path = "../dep" } subdep = { path = "../subdep", features = ["feat"] } "#, ) .file("bin2/build.rs", "fn main() { dep::feat_func(); }") .file("bin2/src/main.rs", "fn main() {}") .file( "dep/Cargo.toml", r#" [package] name = "dep" version = "0.1.0" edition = "2015" [dependencies] subdep = { path = "../subdep" } "#, ) .file( "dep/src/lib.rs", "pub fn feat_func() { subdep::feat_func(); }", ) .file( "subdep/Cargo.toml", r#" [package] name = "subdep" version = "0.1.0" edition = "2015" [features] feat = [] "#, ) .file( "subdep/src/lib.rs", r#" pub fn feat_func() { #[cfg(feature = "feat")] println!("cargo::warning=feat: enabled"); #[cfg(not(feature = "feat"))] println!("cargo::warning=feat: not enabled"); } "#, ) .build(); p.cargo("build --bin bin1 --bin bin2") // unordered because bin1 and bin2 build at the same time .with_stderr_data( str![[r#" [COMPILING] subdep v0.1.0 ([ROOT]/foo/subdep) [COMPILING] dep v0.1.0 ([ROOT]/foo/dep) [COMPILING] bin1 v0.1.0 ([ROOT]/foo/bin1) [COMPILING] bin2 v0.1.0 ([ROOT]/foo/bin2) [WARNING] bin2@0.1.0: feat: enabled [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); p.process(p.bin("bin1")) .with_stdout_data(str![[r#" cargo::warning=feat: not enabled "#]]) .run(); // Make sure everything stays cached. p.cargo("build -v --bin bin1 --bin bin2") .with_stderr_data( str![[r#" [FRESH] subdep v0.1.0 ([ROOT]/foo/subdep) [FRESH] dep v0.1.0 ([ROOT]/foo/dep) [FRESH] bin1 v0.1.0 ([ROOT]/foo/bin1) [WARNING] bin2@0.1.0: feat: enabled [FRESH] bin2 v0.1.0 ([ROOT]/foo/bin2) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn test_proc_macro() { // Running `cargo test` on a proc-macro, with a shared dependency that has // different features. // // There was a bug where `shared` was built twice (once with feature "B" // and once without), and both copies linked into the unit test. This // would cause a type failure when used in an intermediate dependency // (the-macro-support). let p = project() .file( "Cargo.toml", r#" [package] name = "runtime" version = "0.1.0" edition = "2015" resolver = "2" [dependencies] the-macro = { path = "the-macro", features = ['a'] } [build-dependencies] shared = { path = "shared", features = ['b'] } "#, ) .file("src/lib.rs", "") .file( "the-macro/Cargo.toml", r#" [package] name = "the-macro" version = "0.1.0" edition = "2015" [lib] proc-macro = true test = false [dependencies] the-macro-support = { path = "../the-macro-support" } shared = { path = "../shared" } [dev-dependencies] runtime = { path = ".." } [features] a = [] "#, ) .file( "the-macro/src/lib.rs", " fn _test() { the_macro_support::foo(shared::Foo); } ", ) .file( "the-macro-support/Cargo.toml", r#" [package] name = "the-macro-support" version = "0.1.0" edition = "2015" [dependencies] shared = { path = "../shared" } "#, ) .file( "the-macro-support/src/lib.rs", " pub fn foo(_: shared::Foo) {} ", ) .file( "shared/Cargo.toml", r#" [package] name = "shared" version = "0.1.0" edition = "2015" [features] b = [] "#, ) .file("shared/src/lib.rs", "pub struct Foo;") .build(); p.cargo("test --manifest-path the-macro/Cargo.toml").run(); } #[cargo_test] fn doc_optional() { // Checks for a bug where `cargo doc` was failing with an inactive target // that enables a shared optional dependency. Package::new("spin", "1.0.0").publish(); Package::new("bar", "1.0.0") .add_dep(Dependency::new("spin", "1.0").optional(true)) .publish(); // The enabler package enables the `spin` feature, which we don't want. Package::new("enabler", "1.0.0") .feature_dep("bar", "1.0", &["spin"]) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" resolver = "2" [target.'cfg(whatever)'.dependencies] enabler = "1.0" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("doc") .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 3 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] spin v1.0.0 (registry `dummy-registry`) [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [DOCUMENTING] bar v1.0.0 [CHECKING] bar v1.0.0 [DOCUMENTING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]] .unordered(), ) .run(); } #[cargo_test] fn minimal_download() { // Various checks that it only downloads the minimum set of dependencies // needed in various situations. // // This checks several permutations of the different // host_dep/dev_dep/itarget settings. These 3 are planned to be stabilized // together, so there isn't much need to be concerned about how the behave // independently. However, there are some cases where they do behave // independently. Specifically: // // * `cargo test` forces dev_dep decoupling to be disabled. // * `cargo tree --target=all` forces ignore_inactive_targets off and decouple_dev_deps off. // * `cargo tree --target=all -e normal` forces ignore_inactive_targets off. // // However, `cargo tree` is a little weird because it downloads everything // anyways. // // So to summarize the different permutations: // // dev_dep | host_dep | itarget | Notes // --------|----------|---------|---------------------------- // | | | -Zfeatures=compare (new resolver should behave same as old) // | | βœ“ | This scenario should not happen. // | βœ“ | | `cargo tree --target=all -Zfeatures=all`† // | βœ“ | βœ“ | `cargo test` // βœ“ | | | This scenario should not happen. // βœ“ | | βœ“ | This scenario should not happen. // βœ“ | βœ“ | | `cargo tree --target=all -e normal -Z features=all`† // βœ“ | βœ“ | βœ“ | A normal build. // // † β€” However, `cargo tree` downloads everything. Package::new("normal", "1.0.0").publish(); Package::new("normal_pm", "1.0.0").publish(); Package::new("normal_opt", "1.0.0").publish(); Package::new("dev_dep", "1.0.0").publish(); Package::new("dev_dep_pm", "1.0.0").publish(); Package::new("build_dep", "1.0.0").publish(); Package::new("build_dep_pm", "1.0.0").publish(); Package::new("build_dep_opt", "1.0.0").publish(); Package::new("itarget_normal", "1.0.0").publish(); Package::new("itarget_normal_pm", "1.0.0").publish(); Package::new("itarget_dev_dep", "1.0.0").publish(); Package::new("itarget_dev_dep_pm", "1.0.0").publish(); Package::new("itarget_build_dep", "1.0.0").publish(); Package::new("itarget_build_dep_pm", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] normal = "1.0" normal_pm = "1.0" normal_opt = { version = "1.0", optional = true } [dev-dependencies] dev_dep = "1.0" dev_dep_pm = "1.0" [build-dependencies] build_dep = "1.0" build_dep_pm = "1.0" build_dep_opt = { version = "1.0", optional = true } [target.'cfg(whatever)'.dependencies] itarget_normal = "1.0" itarget_normal_pm = "1.0" [target.'cfg(whatever)'.dev-dependencies] itarget_dev_dep = "1.0" itarget_dev_dep_pm = "1.0" [target.'cfg(whatever)'.build-dependencies] itarget_build_dep = "1.0" itarget_build_dep_pm = "1.0" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); let clear = || { paths::cargo_home().join("registry/cache").rm_rf(); paths::cargo_home().join("registry/src").rm_rf(); p.build_dir().rm_rf(); }; // none // Should be the same as `-Zfeatures=all` p.cargo("check -Zfeatures=compare") .masquerade_as_nightly_cargo(&["features=compare"]) .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 14 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] normal_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] normal v1.0.0 (registry `dummy-registry`) [DOWNLOADED] build_dep_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] build_dep v1.0.0 (registry `dummy-registry`) [COMPILING] build_dep v1.0.0 [COMPILING] build_dep_pm v1.0.0 [CHECKING] normal_pm v1.0.0 [CHECKING] normal v1.0.0 [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); clear(); // New behavior switch_to_resolver_2(&p); // all p.cargo("check") .with_stderr_data( str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] normal_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] normal v1.0.0 (registry `dummy-registry`) [DOWNLOADED] build_dep_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] build_dep v1.0.0 (registry `dummy-registry`) [COMPILING] build_dep_pm v1.0.0 [COMPILING] build_dep v1.0.0 [CHECKING] normal_pm v1.0.0 [CHECKING] normal v1.0.0 [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); clear(); // This disables decouple_dev_deps. p.cargo("test --no-run") .with_stderr_data( str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] normal_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] normal v1.0.0 (registry `dummy-registry`) [DOWNLOADED] dev_dep_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] dev_dep v1.0.0 (registry `dummy-registry`) [DOWNLOADED] build_dep_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] build_dep v1.0.0 (registry `dummy-registry`) [COMPILING] build_dep_pm v1.0.0 [COMPILING] build_dep v1.0.0 [COMPILING] normal_pm v1.0.0 [COMPILING] normal v1.0.0 [COMPILING] dev_dep v1.0.0 [COMPILING] dev_dep_pm v1.0.0 [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) "#]] .unordered(), ) .run(); clear(); // This disables itarget, but leaves decouple_dev_deps enabled. p.cargo("tree -e normal --target=all") .with_stderr_data( str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] normal_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] normal v1.0.0 (registry `dummy-registry`) [DOWNLOADED] itarget_normal_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] itarget_normal v1.0.0 (registry `dummy-registry`) [DOWNLOADED] itarget_build_dep_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] itarget_build_dep v1.0.0 (registry `dummy-registry`) [DOWNLOADED] build_dep_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] build_dep v1.0.0 (registry `dummy-registry`) "#]] .unordered(), ) .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ itarget_normal v1.0.0 β”œβ”€β”€ itarget_normal_pm v1.0.0 β”œβ”€β”€ normal v1.0.0 └── normal_pm v1.0.0 "#]]) .run(); clear(); // This disables itarget and decouple_dev_deps. p.cargo("tree --target=all") .with_stderr_data( str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] normal_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] normal v1.0.0 (registry `dummy-registry`) [DOWNLOADED] itarget_normal_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] itarget_normal v1.0.0 (registry `dummy-registry`) [DOWNLOADED] itarget_dev_dep_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] itarget_dev_dep v1.0.0 (registry `dummy-registry`) [DOWNLOADED] itarget_build_dep_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] itarget_build_dep v1.0.0 (registry `dummy-registry`) [DOWNLOADED] dev_dep_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] dev_dep v1.0.0 (registry `dummy-registry`) [DOWNLOADED] build_dep_pm v1.0.0 (registry `dummy-registry`) [DOWNLOADED] build_dep v1.0.0 (registry `dummy-registry`) "#]] .unordered(), ) .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ itarget_normal v1.0.0 β”œβ”€β”€ itarget_normal_pm v1.0.0 β”œβ”€β”€ normal v1.0.0 └── normal_pm v1.0.0 [build-dependencies] β”œβ”€β”€ build_dep v1.0.0 β”œβ”€β”€ build_dep_pm v1.0.0 β”œβ”€β”€ itarget_build_dep v1.0.0 └── itarget_build_dep_pm v1.0.0 [dev-dependencies] β”œβ”€β”€ dev_dep v1.0.0 β”œβ”€β”€ dev_dep_pm v1.0.0 β”œβ”€β”€ itarget_dev_dep v1.0.0 └── itarget_dev_dep_pm v1.0.0 "#]]) .run(); clear(); } #[cargo_test] fn pm_with_int_shared() { // This is a somewhat complex scenario of a proc-macro in a workspace with // an integration test where the proc-macro is used for other things, and // *everything* is built at once (`--workspace --all-targets // --all-features`). There was a bug where the UnitFor settings were being // incorrectly computed based on the order that the graph was traversed. // // There are some uncertainties about exactly how proc-macros should behave // with `--workspace`, see https://github.com/rust-lang/cargo/issues/8312. // // This uses a const-eval hack to do compile-time feature checking. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo", "pm", "shared"] resolver = "2" "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] pm = { path = "../pm" } shared = { path = "../shared", features = ["norm-feat"] } "#, ) .file( "foo/src/lib.rs", r#" // foo->shared always has both features set const _CHECK: [(); 0] = [(); 0-!(shared::FEATS==3) as usize]; "#, ) .file( "pm/Cargo.toml", r#" [package] name = "pm" version = "0.1.0" edition = "2015" [lib] proc-macro = true [dependencies] shared = { path = "../shared", features = ["host-feat"] } "#, ) .file( "pm/src/lib.rs", r#" // pm->shared always has just host const _CHECK: [(); 0] = [(); 0-!(shared::FEATS==1) as usize]; "#, ) .file( "pm/tests/pm_test.rs", r#" // integration test gets both set const _CHECK: [(); 0] = [(); 0-!(shared::FEATS==3) as usize]; "#, ) .file( "shared/Cargo.toml", r#" [package] name = "shared" version = "0.1.0" edition = "2015" [features] norm-feat = [] host-feat = [] "#, ) .file( "shared/src/lib.rs", r#" pub const FEATS: u32 = { if cfg!(feature="norm-feat") && cfg!(feature="host-feat") { 3 } else if cfg!(feature="norm-feat") { 2 } else if cfg!(feature="host-feat") { 1 } else { 0 } }; "#, ) .build(); p.cargo("build --workspace --all-targets --all-features -v") .with_stderr_data( str![[r#" [COMPILING] shared v0.1.0 ([ROOT]/foo/shared) [RUNNING] `rustc --crate-name shared [..]--crate-type lib [..]` [RUNNING] `rustc --crate-name shared [..]--crate-type lib [..]` [RUNNING] `rustc --crate-name shared [..]--test[..]` [COMPILING] pm v0.1.0 ([ROOT]/foo/pm) [RUNNING] `rustc --crate-name pm [..]--crate-type proc-macro[..]` [RUNNING] `rustc --crate-name pm [..]--test[..]` [COMPILING] foo v0.1.0 ([ROOT]/foo/foo) [RUNNING] `rustc --crate-name foo [..]--crate-type lib [..]` [RUNNING] `rustc --crate-name foo [..]--test[..]` [RUNNING] `rustc --crate-name pm_test [..]--test[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); // And again, should stay fresh. p.cargo("build --workspace --all-targets --all-features -v") .with_stderr_data( str![[r#" [FRESH] pm v0.1.0 ([ROOT]/foo/pm) [FRESH] foo v0.1.0 ([ROOT]/foo/foo) [FRESH] shared v0.1.0 ([ROOT]/foo/shared) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn doc_proc_macro() { // Checks for a bug when documenting a proc-macro with a dependency. The // doc unit builder was not carrying the "for host" setting through the // dependencies, and the `pm-dep` dependency was causing a panic because // it was looking for target features instead of host features. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" resolver = "2" [dependencies] pm = { path = "pm" } "#, ) .file("src/lib.rs", "") .file( "pm/Cargo.toml", r#" [package] name = "pm" version = "0.1.0" edition = "2015" [lib] proc-macro = true [dependencies] pm-dep = { path = "../pm-dep" } "#, ) .file("pm/src/lib.rs", "") .file("pm-dep/Cargo.toml", &basic_manifest("pm-dep", "0.1.0")) .file("pm-dep/src/lib.rs", "") .build(); // Unfortunately this cannot check the output because what it prints is // nondeterministic. Sometimes it says "Compiling pm-dep" and sometimes // "Checking pm-dep". This is because it is both building it and checking // it in parallel (building so it can build the proc-macro, and checking // so rustdoc can load it). p.cargo("doc").run(); } #[cargo_test] fn edition_2021_default_2() { // edition = 2021 defaults to v2 resolver. Package::new("common", "1.0.0") .feature("f1", &[]) .file("src/lib.rs", "") .publish(); Package::new("bar", "1.0.0") .add_dep( Dependency::new("common", "1.0") .target("cfg(whatever)") .enable_features(&["f1"]), ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] common = "1.0" bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); // First without edition. p.cargo("tree -f") .arg("{p} feats:{f}") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) feats: β”œβ”€β”€ bar v1.0.0 feats: └── common v1.0.0 feats:f1 "#]]) .run(); p.change_file( "Cargo.toml", r#" cargo-features = ["edition2021"] [package] name = "foo" version = "0.1.0" edition = "2021" [dependencies] common = "1.0" bar = "1.0" "#, ); // Importantly, this does not include `f1` on `common`. p.cargo("tree -f") .arg("{p} feats:{f}") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) feats: β”œβ”€β”€ bar v1.0.0 feats: └── common v1.0.0 feats: "#]]) .run(); } #[cargo_test] fn all_features_merges_with_features() { Package::new("dep", "0.1.0") .feature("feat1", &[]) .file( "src/lib.rs", r#" #[cfg(feature="feat1")] pub fn work() { println!("it works"); } "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [features] a = [] [dependencies] dep = "0.1" [[example]] name = "ex" required-features = ["a", "dep/feat1"] "#, ) .file( "examples/ex.rs", r#" fn main() { dep::work(); } "#, ) .file("src/lib.rs", "") .build(); p.cargo("run --example ex --all-features --features dep/feat1") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] dep v0.1.0 (registry `dummy-registry`) [COMPILING] dep v0.1.0 [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/examples/ex[EXE]` "#]]) .with_stdout_data(str![[r#" it works "#]]) .run(); switch_to_resolver_2(&p); p.cargo("run --example ex --all-features --features dep/feat1") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/examples/ex[EXE]` "#]]) .with_stdout_data(str![[r#" it works "#]]) .run(); } #[cargo_test] fn dep_with_optional_host_deps_activated() { // To prevent regression like rust-lang/cargo#11330 let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2021" [dependencies] serde = { path = "serde", features = ["derive", "build"] } "#, ) .file("src/lib.rs", "") .file( "serde/Cargo.toml", r#" [package] name = "serde" version = "0.1.0" edition = "2021" [dependencies] serde_derive = { path = "../serde_derive", optional = true } [build-dependencies] serde_build = { path = "../serde_build", optional = true } [features] derive = ["dep:serde_derive"] build = ["dep:serde_build"] "#, ) .file("serde/src/lib.rs", "") .file("serde/build.rs", "fn main() {}") .file( "serde_derive/Cargo.toml", r#" [package] name = "serde_derive" version = "0.1.0" edition = "2021" [lib] proc-macro = true "#, ) .file("serde_derive/src/lib.rs", "") .file( "serde_build/Cargo.toml", &basic_manifest("serde_build", "0.1.0"), ) .file("serde_build/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 3 packages to latest compatible versions [COMPILING] serde_build v0.1.0 ([ROOT]/foo/serde_build) [COMPILING] serde_derive v0.1.0 ([ROOT]/foo/serde_derive) [COMPILING] serde v0.1.0 ([ROOT]/foo/serde) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn dont_unify_proc_macro_example_from_dependency() { // See https://github.com/rust-lang/cargo/issues/13726 let p = project() .file( "Cargo.toml", r#" [package] name = "foo" edition = "2021" [dependencies] pm_helper = { path = "pm_helper" } "#, ) .file("src/lib.rs", "") .file( "pm_helper/Cargo.toml", r#" [package] name = "pm_helper" [[example]] name = "pm" proc-macro = true crate-type = ["proc-macro"] "#, ) .file("pm_helper/src/lib.rs", "") .file("pm_helper/examples/pm.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] pm_helper v0.0.0 ([ROOT]/foo/pm_helper) [CHECKING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/features_namespaced.rs000064400000000000000000001042021046102023000205500ustar 00000000000000//! Tests for namespaced features. use cargo_test_support::prelude::*; use cargo_test_support::registry::{Dependency, Package, RegistryBuilder}; use cargo_test_support::str; use cargo_test_support::{project, publish}; use super::features2::switch_to_resolver_2; #[cargo_test] fn dependency_with_crate_syntax() { // Registry dependency uses dep: syntax. Package::new("baz", "1.0.0").publish(); Package::new("bar", "1.0.0") .add_dep(Dependency::new("baz", "1.0").optional(true)) .feature("feat", &["dep:baz"]) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = {version="1.0", features=["feat"]} "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] baz v1.0.0 (registry `dummy-registry`) [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [CHECKING] baz v1.0.0 [CHECKING] bar v1.0.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn namespaced_invalid_feature() { // Specifies a feature that doesn't exist. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] bar = ["baz"] "#, ) .file("src/main.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `bar` includes `baz` which is neither a dependency nor another feature "#]]) .run(); } #[cargo_test] fn namespaced_invalid_dependency() { // Specifies a dep:name that doesn't exist. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [features] bar = ["dep:baz"] "#, ) .file("src/main.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `bar` includes `dep:baz`, but `baz` is not listed as a dependency "#]]) .run(); } #[cargo_test] fn namespaced_non_optional_dependency() { // Specifies a dep:name for a dependency that is not optional. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [features] bar = ["dep:baz"] [dependencies] baz = "0.1" "#, ) .file("src/main.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `bar` includes `dep:baz`, but `baz` is not an optional dependency A non-optional dependency of the same name is defined; consider adding `optional = true` to its definition. "#]]) .run(); } #[cargo_test] fn namespaced_implicit_feature() { // Backwards-compatible with old syntax. Package::new("baz", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [features] bar = ["baz"] [dependencies] baz = { version = "0.1", optional = true } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check --features baz") .with_stderr_data(str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] baz v0.1.0 (registry `dummy-registry`) [CHECKING] baz v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn namespaced_shadowed_dep() { // An optional dependency is not listed in the features table, and its // implicit feature is overridden. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [features] baz = [] [dependencies] baz = { version = "0.1", optional = true } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: optional dependency `baz` is not included in any feature Make sure that `dep:baz` is included in one of features in the [features] table. "#]]) .run(); } #[cargo_test] fn namespaced_shadowed_non_optional() { // Able to specify a feature with the same name as a required dependency. Package::new("baz", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [features] baz = [] [dependencies] baz = "0.1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); } #[cargo_test] fn namespaced_implicit_non_optional() { // Includes a non-optional dependency in [features] table. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [features] bar = ["baz"] [dependencies] baz = "0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `bar` includes `baz`, but `baz` is not an optional dependency A non-optional dependency of the same name is defined; consider adding `optional = true` to its definition. "#]]) .run(); } #[cargo_test] fn namespaced_same_name() { // Explicitly listing an optional dependency in the [features] table. Package::new("baz", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [features] baz = ["dep:baz"] [dependencies] baz = { version = "0.1", optional = true } "#, ) .file( "src/main.rs", r#" fn main() { if cfg!(feature="baz") { println!("baz"); } } "#, ) .build(); p.cargo("run") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .with_stdout_data("") .run(); p.cargo("run --features baz") .with_stderr_data(str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] baz v0.1.0 (registry `dummy-registry`) [COMPILING] baz v0.1.0 [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .with_stdout_data(str![[r#" baz "#]]) .run(); } #[cargo_test] fn no_implicit_feature() { // Using `dep:` will not create an implicit feature. Package::new("regex", "1.0.0").publish(); Package::new("lazy_static", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] regex = { version = "1.0", optional = true } lazy_static = { version = "1.0", optional = true } [features] regex = ["dep:regex", "dep:lazy_static"] "#, ) .file( "src/main.rs", r#" fn main() { if cfg!(feature = "regex") { println!("regex"); } #[allow(unexpected_cfgs)] if cfg!(feature = "lazy_static") { println!("lazy_static"); } } "#, ) .build(); p.cargo("run") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .with_stdout_data("") .run(); p.cargo("run --features regex") .with_stderr_data( str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] regex v1.0.0 (registry `dummy-registry`) [DOWNLOADED] lazy_static v1.0.0 (registry `dummy-registry`) [COMPILING] regex v1.0.0 [COMPILING] lazy_static v1.0.0 [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]] .unordered(), ) .with_stdout_data(str![[r#" regex "#]]) .run(); p.cargo("run --features lazy_static") .with_stderr_data(str![[r#" [ERROR] Package `foo v0.1.0 ([ROOT]/foo)` does not have feature `lazy_static`. It has an optional dependency with that name, but that dependency uses the "dep:" syntax in the features table, so it does not have an implicit feature with that name. "#]]) .with_status(101) .run(); } #[cargo_test] fn crate_syntax_bad_name() { // "dep:bar" = [] Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { version="1.0", optional=true } [features] "dep:bar" = [] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check --features dep:bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] feature named `dep:bar` is not allowed to start with `dep:` --> Cargo.toml:11:17 | 11 | "dep:bar" = [] | ^^^^^^^^^ | "#]]) .run(); } #[cargo_test] fn crate_syntax_in_dep() { // features = ["dep:baz"] Package::new("baz", "1.0.0").publish(); Package::new("bar", "1.0.0") .add_dep(Dependency::new("baz", "1.0").optional(true)) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { version = "1.0", features = ["dep:baz"] } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `dep:baz` in dependency `bar` is not allowed to use explicit `dep:` syntax If you want to enable an optional dependency, specify the name of the optional dependency without the `dep:` prefix, or specify a feature from the dependency's `[features]` table that enables the optional dependency. "#]]) .run(); } #[cargo_test] fn crate_syntax_cli() { // --features dep:bar Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { version = "1.0", optional=true } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check --features dep:bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] feature `dep:bar` is not allowed to use explicit `dep:` syntax "#]]) .run(); switch_to_resolver_2(&p); p.cargo("check --features dep:bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] feature `dep:bar` is not allowed to use explicit `dep:` syntax "#]]) .run(); } #[cargo_test] fn crate_required_features() { // required-features = ["dep:bar"] Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { version = "1.0", optional=true } [[bin]] name = "foo" required-features = ["dep:bar"] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [ERROR] invalid feature `dep:bar` in required-features of target `foo`: `dep:` prefixed feature values are not allowed in required-features "#]]) .run(); } #[cargo_test] fn json_exposed() { // Checks that the implicit dep: values are exposed in JSON. Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { version = "1.0", optional=true } "#, ) .file("src/lib.rs", "") .build(); p.cargo("metadata --no-deps") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": "{...}", "description": null, "documentation": null, "edition": "2015", "features": { "bar": [ "dep:bar" ] }, "homepage": null, "id": "path+[ROOTURL]/foo#0.1.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": "{...}", "version": "0.1.0" } ], "resolve": null, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn crate_feature_with_explicit() { // crate_name/feat_name syntax where crate_name already has a feature defined. // NOTE: I don't know if this is actually ideal behavior. Package::new("bar", "1.0.0") .feature("bar_feat", &[]) .file( "src/lib.rs", r#" #[cfg(not(feature="bar_feat"))] compile_error!("bar_feat is not enabled"); "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { version="1.0", optional = true } [features] f1 = ["bar/bar_feat"] bar = ["dep:bar", "f2"] f2 = [] "#, ) .file( "src/lib.rs", r#" #[cfg(not(feature="bar"))] compile_error!("bar should be enabled"); #[cfg(not(feature="f2"))] compile_error!("f2 should be enabled"); "#, ) .build(); p.cargo("check --features f1") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [CHECKING] bar v1.0.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn optional_explicit_without_crate() { // "feat" syntax when there is no implicit "feat" feature because it is // explicitly listed elsewhere. Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { version = "1.0", optional = true } [features] feat1 = ["dep:bar"] feat2 = ["bar"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `feat2` includes `bar`, but `bar` is an optional dependency without an implicit feature Use `dep:bar` to enable the dependency. "#]]) .run(); } #[cargo_test] fn tree() { Package::new("baz", "1.0.0").publish(); Package::new("bar", "1.0.0") .add_dep(Dependency::new("baz", "1.0").optional(true)) .feature("feat1", &["dep:baz"]) .feature("feat2", &[]) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { version = "1.0", features = ["feat1"], optional=true } [features] a = ["bar/feat2"] bar = ["dep:bar"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree -e features") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) "#]]) .run(); p.cargo("tree -e features --features a") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ bar feature "default" β”‚ └── bar v1.0.0 β”‚ └── baz feature "default" β”‚ └── baz v1.0.0 └── bar feature "feat1" └── bar v1.0.0 (*) "#]]) .run(); p.cargo("tree -e features --features a -i bar") .with_stdout_data(str![[r#" bar v1.0.0 β”œβ”€β”€ bar feature "default" β”‚ └── foo v0.1.0 ([ROOT]/foo) β”‚ β”œβ”€β”€ foo feature "a" (command-line) β”‚ β”œβ”€β”€ foo feature "bar" β”‚ β”‚ └── foo feature "a" (command-line) β”‚ └── foo feature "default" (command-line) β”œβ”€β”€ bar feature "feat1" β”‚ └── foo v0.1.0 ([ROOT]/foo) (*) └── bar feature "feat2" └── foo feature "a" (command-line) "#]]) .run(); p.cargo("tree -e features --features bar") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ bar feature "default" β”‚ └── bar v1.0.0 β”‚ └── baz feature "default" β”‚ └── baz v1.0.0 └── bar feature "feat1" └── bar v1.0.0 (*) "#]]) .run(); p.cargo("tree -e features --features bar -i bar") .with_stdout_data(str![[r#" bar v1.0.0 β”œβ”€β”€ bar feature "default" β”‚ └── foo v0.1.0 ([ROOT]/foo) β”‚ β”œβ”€β”€ foo feature "bar" (command-line) β”‚ └── foo feature "default" (command-line) └── bar feature "feat1" └── foo v0.1.0 ([ROOT]/foo) (*) "#]]) .run(); } #[cargo_test] fn tree_no_implicit() { // tree without an implicit feature Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { version = "1.0", optional=true } [features] a = ["dep:bar"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree -e features") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) "#]]) .run(); p.cargo("tree -e features --all-features") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar feature "default" └── bar v1.0.0 "#]]) .run(); p.cargo("tree -e features -i bar --all-features") .with_stdout_data(str![[r#" bar v1.0.0 └── bar feature "default" └── foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ foo feature "a" (command-line) └── foo feature "default" (command-line) "#]]) .run(); } #[cargo_test] fn publish_no_implicit() { let registry = RegistryBuilder::new().http_api().http_index().build(); // Does not include implicit features or dep: syntax on publish. Package::new("opt-dep1", "1.0.0").publish(); Package::new("opt-dep2", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" description = "foo" license = "MIT" homepage = "https://example.com/" [dependencies] opt-dep1 = { version = "1.0", optional = true } opt-dep2 = { version = "1.0", optional = true } [features] feat = ["opt-dep1"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [PACKAGING] foo v0.1.0 ([ROOT]/foo) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.1.0 ([ROOT]/foo) [UPLOADED] foo v0.1.0 to registry `crates-io` [NOTE] waiting for `foo v0.1.0` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.1.0 at registry `crates-io` "#]]) .run(); publish::validate_upload_with_contents( r#" { "authors": [], "badges": {}, "categories": [], "deps": [ { "default_features": true, "features": [], "kind": "normal", "name": "opt-dep1", "optional": true, "target": null, "version_req": "^1.0" }, { "default_features": true, "features": [], "kind": "normal", "name": "opt-dep2", "optional": true, "target": null, "version_req": "^1.0" } ], "description": "foo", "documentation": null, "features": { "feat": ["opt-dep1"] }, "homepage": "https://example.com/", "keywords": [], "license": "MIT", "license_file": null, "links": null, "name": "foo", "readme": null, "readme_file": null, "repository": null, "rust_version": null, "vers": "0.1.0" } "#, "foo-0.1.0.crate", &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "Cargo.lock"], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.1.0" build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" homepage = "https://example.com/" readme = false license = "MIT" [features] feat = ["opt-dep1"] [lib] name = "foo" path = "src/lib.rs" [dependencies.opt-dep1] version = "1.0" optional = true [dependencies.opt-dep2] version = "1.0" optional = true "##]], )], ); } #[cargo_test] fn publish() { let registry = RegistryBuilder::new().http_api().http_index().build(); // Publish behavior with explicit dep: syntax. Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" description = "foo" license = "MIT" homepage = "https://example.com/" [dependencies] bar = { version = "1.0", optional = true } [features] feat1 = [] feat2 = ["dep:bar"] feat3 = ["feat2"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [PACKAGING] foo v0.1.0 ([ROOT]/foo) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.1.0 ([ROOT]/foo) [COMPILING] foo v0.1.0 ([ROOT]/foo/target/package/foo-0.1.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.1.0 ([ROOT]/foo) [UPLOADED] foo v0.1.0 to registry `crates-io` [NOTE] waiting for `foo v0.1.0` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.1.0 at registry `crates-io` "#]]) .run(); publish::validate_upload_with_contents( r#" { "authors": [], "badges": {}, "categories": [], "deps": [ { "default_features": true, "features": [], "kind": "normal", "name": "bar", "optional": true, "target": null, "version_req": "^1.0" } ], "description": "foo", "documentation": null, "features": { "feat1": [], "feat2": ["dep:bar"], "feat3": ["feat2"] }, "homepage": "https://example.com/", "keywords": [], "license": "MIT", "license_file": null, "links": null, "name": "foo", "readme": null, "readme_file": null, "repository": null, "rust_version": null, "vers": "0.1.0" } "#, "foo-0.1.0.crate", &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "Cargo.lock"], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.1.0" build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" homepage = "https://example.com/" readme = false license = "MIT" [features] feat1 = [] feat2 = ["dep:bar"] feat3 = ["feat2"] [lib] name = "foo" path = "src/lib.rs" [dependencies.bar] version = "1.0" optional = true "##]], )], ); } #[cargo_test] fn namespaced_feature_together() { // Check for an error when `dep:` is used with `/` Package::new("bar", "1.0.0") .feature("bar-feat", &[]) .publish(); // Non-optional shouldn't have extra err. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" [features] f1 = ["dep:bar/bar-feat"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `f1` includes `dep:bar/bar-feat` with both `dep:` and `/` To fix this, remove the `dep:` prefix. "#]]) .run(); // Weak dependency shouldn't have extra err. p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = {version = "1.0", optional = true } [features] f1 = ["dep:bar?/bar-feat"] "#, ); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `f1` includes `dep:bar?/bar-feat` with both `dep:` and `/` To fix this, remove the `dep:` prefix. "#]]) .run(); // If dep: is already specified, shouldn't have extra err. p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = {version = "1.0", optional = true } [features] f1 = ["dep:bar", "dep:bar/bar-feat"] "#, ); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `f1` includes `dep:bar/bar-feat` with both `dep:` and `/` To fix this, remove the `dep:` prefix. "#]]) .run(); // Only when the other 3 cases aren't true should it give some extra help. p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = {version = "1.0", optional = true } [features] f1 = ["dep:bar/bar-feat"] "#, ); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `f1` includes `dep:bar/bar-feat` with both `dep:` and `/` To fix this, remove the `dep:` prefix. If the intent is to avoid creating an implicit feature `bar` for an optional dependency, then consider replacing this with two values: "dep:bar", "bar/bar-feat" "#]]) .run(); } #[cargo_test] fn dep_feature_when_hidden() { // Checks for behavior with dep:bar and bar/feat syntax when there is no // `bar` feature. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar", optional = true } [features] f1 = ["dep:bar"] f2 = ["bar/bar_feat"] "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [features] bar_feat = [] "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("tree -f") .arg("{p} features={f}") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) features= "#]]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version "#]]) .run(); p.cargo("tree -F f1 -f") .arg("{p} features={f}") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) features=f1 └── bar v0.1.0 ([ROOT]/foo/bar) features= "#]]) .with_stderr_data("") .run(); p.cargo("tree -F f2 -f") .arg("{p} features={f}") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) features=f2 └── bar v0.1.0 ([ROOT]/foo/bar) features=bar_feat "#]]) .with_stderr_data("") .run(); p.cargo("tree --all-features -f") .arg("{p} features={f}") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) features=f1,f2 └── bar v0.1.0 ([ROOT]/foo/bar) features=bar_feat "#]]) .with_stderr_data("") .run(); } cargo-0.86.0/tests/testsuite/fetch.rs000064400000000000000000000071161046102023000156510ustar 00000000000000//! Tests for the `cargo fetch` command. use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::rustc_host; use cargo_test_support::{basic_manifest, cross_compile, project, str}; #[cargo_test] fn no_deps() { let p = project() .file("src/main.rs", "mod a; fn main() {}") .file("src/a.rs", "") .build(); p.cargo("fetch").with_stderr_data("").run(); } #[cargo_test] fn fetch_all_platform_dependencies_when_no_target_is_given() { if cross_compile::disabled() { return; } Package::new("d1", "1.2.3") .file("Cargo.toml", &basic_manifest("d1", "1.2.3")) .file("src/lib.rs", "") .publish(); Package::new("d2", "0.1.2") .file("Cargo.toml", &basic_manifest("d2", "0.1.2")) .file("src/lib.rs", "") .publish(); let target = cross_compile::alternate(); let host = rustc_host(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [target.{host}.dependencies] d1 = "1.2.3" [target.{target}.dependencies] d2 = "0.1.2" "#, host = host, target = target ), ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .with_stderr_data(str![[r#" ... [DOWNLOADED] d1 v1.2.3 (registry `dummy-registry`) [DOWNLOADED] d2 v0.1.2 (registry `dummy-registry`) ... "#]]) .run(); } #[cargo_test] fn fetch_platform_specific_dependencies() { if cross_compile::disabled() { return; } Package::new("d1", "1.2.3") .file("Cargo.toml", &basic_manifest("d1", "1.2.3")) .file("src/lib.rs", "") .publish(); Package::new("d2", "0.1.2") .file("Cargo.toml", &basic_manifest("d2", "0.1.2")) .file("src/lib.rs", "") .publish(); let target = cross_compile::alternate(); let host = rustc_host(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [target.{host}.dependencies] d1 = "1.2.3" [target.{target}.dependencies] d2 = "0.1.2" "#, host = host, target = target ), ) .file("src/lib.rs", "") .build(); p.cargo("fetch --target") .arg(&host) .with_stderr_contains("[DOWNLOADED] d1 v1.2.3 [..]") .with_stderr_does_not_contain("[DOWNLOADED] d2 v0.1.2 [..]") .run(); p.cargo("fetch --target") .arg(&target) .with_stderr_contains("[DOWNLOADED] d2 v0.1.2[..]") .with_stderr_does_not_contain("[DOWNLOADED] d1 v1.2.3 [..]") .run(); } #[cargo_test] fn fetch_warning() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" misspelled = "wut" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .with_stderr_data(str![[r#" [WARNING] unused manifest key: package.misspelled "#]]) .run(); } cargo-0.86.0/tests/testsuite/fix.rs000064400000000000000000002427471046102023000153610ustar 00000000000000//! Tests for the `cargo fix` command. use cargo::core::Edition; use cargo_test_support::compare::assert_e2e; use cargo_test_support::git::{self, init}; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::{Dependency, Package}; use cargo_test_support::str; use cargo_test_support::tools; use cargo_test_support::{basic_manifest, is_nightly, project}; #[cargo_test] fn do_not_fix_broken_builds() { let p = project() .file( "src/lib.rs", r#" pub fn foo() { let mut x = 3; let _ = x; } pub fn foo2() { let _x: u32 = "a"; } "#, ) .build(); p.cargo("fix --allow-no-vcs") .env("__CARGO_FIX_YOLO", "1") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] could not compile `foo` (lib) due to 1 previous error; 1 warning emitted ... "#]]) .run(); assert!(p.read_file("src/lib.rs").contains("let mut x = 3;")); } #[cargo_test] fn fix_broken_if_requested() { let p = project() .file( "src/lib.rs", r#" fn foo(a: &u32) -> u32 { a + 1 } pub fn bar() { foo(1); } "#, ) .build(); p.cargo("fix --allow-no-vcs --broken-code") .env("__CARGO_FIX_YOLO", "1") .run(); } #[cargo_test] fn fix_path_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = 'bar' } [workspace] "#, ) .file( "src/lib.rs", r#" extern crate bar; pub fn foo() -> u32 { let mut x = 3; x } "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file( "bar/src/lib.rs", r#" pub fn foo() -> u32 { let mut x = 3; x } "#, ) .build(); p.cargo("fix --allow-no-vcs -p foo -p bar") .env("__CARGO_FIX_YOLO", "1") .with_stdout_data("") .with_stderr_data( str![[r#" [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [FIXED] bar/src/lib.rs (1 fix) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FIXED] src/lib.rs (1 fix) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn do_not_fix_non_relevant_deps() { let p = project() .no_manifest() .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = '../bar' } [workspace] "#, ) .file("foo/src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file( "bar/src/lib.rs", r#" pub fn foo() -> u32 { let mut x = 3; x } "#, ) .build(); p.cargo("fix --allow-no-vcs") .env("__CARGO_FIX_YOLO", "1") .cwd("foo") .run(); assert!(p.read_file("bar/src/lib.rs").contains("mut")); } #[cargo_test] fn prepare_for_2018() { let p = project() .file( "src/lib.rs", r#" #![allow(unused)] mod foo { pub const FOO: &str = "fooo"; } mod bar { use ::foo::FOO; } fn main() { let x = ::foo::FOO; } "#, ) .build(); p.cargo("fix --edition --allow-no-vcs") .with_stderr_data(str![[r#" [MIGRATING] Cargo.toml from 2015 edition to 2018 [CHECKING] foo v0.0.1 ([ROOT]/foo) [MIGRATING] src/lib.rs from 2015 edition to 2018 [FIXED] src/lib.rs (2 fixes) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); println!("{}", p.read_file("src/lib.rs")); assert!(p.read_file("src/lib.rs").contains("use crate::foo::FOO;")); assert!(p .read_file("src/lib.rs") .contains("let x = crate::foo::FOO;")); } #[cargo_test] fn local_paths() { let p = project() .file( "src/lib.rs", r#" use test::foo; mod test { pub fn foo() {} } pub fn f() { foo(); } "#, ) .build(); p.cargo("fix --edition --allow-no-vcs") .with_stderr_data(str![[r#" [MIGRATING] Cargo.toml from 2015 edition to 2018 [CHECKING] foo v0.0.1 ([ROOT]/foo) [MIGRATING] src/lib.rs from 2015 edition to 2018 [FIXED] src/lib.rs (1 fix) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); println!("{}", p.read_file("src/lib.rs")); assert!(p.read_file("src/lib.rs").contains("use crate::test::foo;")); } #[cargo_test] fn upgrade_extern_crate() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = '2018' [workspace] [dependencies] bar = { path = 'bar' } "#, ) .file( "src/lib.rs", r#" #![warn(rust_2018_idioms)] extern crate bar; use bar::bar; pub fn foo() { ::bar::bar(); bar(); } "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("fix --allow-no-vcs") .env("__CARGO_FIX_YOLO", "1") .with_stderr_data(str![[r#" [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FIXED] src/lib.rs (1 fix) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); println!("{}", p.read_file("src/lib.rs")); assert!(!p.read_file("src/lib.rs").contains("extern crate")); } #[cargo_test] fn specify_rustflags() { let p = project() .file( "src/lib.rs", r#" #![allow(unused)] mod foo { pub const FOO: &str = "fooo"; } fn main() { let x = ::foo::FOO; } "#, ) .build(); p.cargo("fix --edition --allow-no-vcs") .env("RUSTFLAGS", "-C linker=cc") .with_stderr_data(str![[r#" [MIGRATING] Cargo.toml from 2015 edition to 2018 [CHECKING] foo v0.0.1 ([ROOT]/foo) [MIGRATING] src/lib.rs from 2015 edition to 2018 [FIXED] src/lib.rs (1 fix) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); } #[cargo_test] fn no_changes_necessary() { let p = project().file("src/lib.rs", "").build(); p.cargo("fix --allow-no-vcs") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); } #[cargo_test] fn fixes_extra_mut() { let p = project() .file( "src/lib.rs", r#" pub fn foo() -> u32 { let mut x = 3; x } "#, ) .build(); p.cargo("fix --allow-no-vcs") .env("__CARGO_FIX_YOLO", "1") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FIXED] src/lib.rs (1 fix) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); } #[cargo_test] fn fixes_two_missing_ampersands() { let p = project() .file( "src/lib.rs", r#" pub fn foo() -> u32 { let mut x = 3; let mut y = 3; x + y } "#, ) .build(); p.cargo("fix --allow-no-vcs") .env("__CARGO_FIX_YOLO", "1") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FIXED] src/lib.rs (2 fixes) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); } #[cargo_test] fn tricky() { let p = project() .file( "src/lib.rs", r#" pub fn foo() -> u32 { let mut x = 3; let mut y = 3; x + y } "#, ) .build(); p.cargo("fix --allow-no-vcs") .env("__CARGO_FIX_YOLO", "1") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FIXED] src/lib.rs (2 fixes) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); } #[cargo_test] fn preserve_line_endings() { let p = project() .file( "src/lib.rs", "fn add(a: &u32) -> u32 { a + 1 }\r\n\ pub fn foo() -> u32 { let mut x = 3; add(&x) }\r\n\ ", ) .build(); p.cargo("fix --allow-no-vcs") .env("__CARGO_FIX_YOLO", "1") .run(); assert!(p.read_file("src/lib.rs").contains("\r\n")); } #[cargo_test] fn fix_deny_warnings() { let p = project() .file( "src/lib.rs", "#![deny(warnings)] pub fn foo() { let mut x = 3; let _ = x; } ", ) .build(); p.cargo("fix --allow-no-vcs") .env("__CARGO_FIX_YOLO", "1") .run(); } #[cargo_test] fn fix_deny_warnings_but_not_others() { let p = project() .file( "src/lib.rs", " #![deny(unused_mut)] pub fn foo() -> u32 { let mut x = 3; x } pub fn bar() { #[allow(unused_mut)] let mut _y = 4; } ", ) .build(); p.cargo("fix --allow-no-vcs") .env("__CARGO_FIX_YOLO", "1") .run(); assert!(!p.read_file("src/lib.rs").contains("let mut x = 3;")); assert!(p.read_file("src/lib.rs").contains("let mut _y = 4;")); } #[cargo_test] fn fix_two_files() { let p = project() .file( "src/lib.rs", " pub mod bar; pub fn foo() -> u32 { let mut x = 3; x } ", ) .file( "src/bar.rs", " pub fn foo() -> u32 { let mut x = 3; x } ", ) .build(); p.cargo("fix --allow-no-vcs") .env("__CARGO_FIX_YOLO", "1") .with_stderr_data( str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FIXED] src/bar.rs (1 fix) [FIXED] src/lib.rs (1 fix) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); assert!(!p.read_file("src/lib.rs").contains("let mut x = 3;")); assert!(!p.read_file("src/bar.rs").contains("let mut x = 3;")); } #[cargo_test] fn fixes_missing_ampersand() { let p = project() .file("src/main.rs", "fn main() { let mut x = 3; let _ = x; }") .file( "src/lib.rs", r#" pub fn foo() { let mut x = 3; let _ = x; } #[test] pub fn foo2() { let mut x = 3; let _ = x; } "#, ) .file( "tests/a.rs", r#" #[test] pub fn foo() { let mut x = 3; let _ = x; } "#, ) .file("examples/foo.rs", "fn main() { let mut x = 3; let _ = x; }") .file("build.rs", "fn main() { let mut x = 3; let _ = x; }") .build(); p.cargo("fix --all-targets --allow-no-vcs") .env("__CARGO_FIX_YOLO", "1") .with_stdout_data("") // Don't assert number of fixes for `src/lib.rs`, as we don't know if we're // fixing it once or twice! We run this all concurrently, and if we // compile (and fix) in `--test` mode first, we get two fixes. Otherwise // we'll fix one non-test thing, and then fix another one later in // test mode. .with_stderr_data( str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FIXED] build.rs (1 fix) [FIXED] src/lib.rs ([..]fix[..]) [FIXED] src/main.rs (1 fix) [FIXED] examples/foo.rs (1 fix) [FIXED] tests/a.rs (1 fix) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s ... "#]] .unordered(), ) .run(); p.cargo("check").run(); p.cargo("test").run(); } #[cargo_test] fn fix_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [features] bar = [] [workspace] "#, ) .file( "src/lib.rs", r#" #[cfg(feature = "bar")] pub fn foo() -> u32 { let mut x = 3; x } "#, ) .build(); p.cargo("fix --allow-no-vcs").run(); p.cargo("check").run(); p.cargo("fix --features bar --allow-no-vcs").run(); p.cargo("check --features bar").run(); } #[cargo_test] fn shows_warnings() { let p = project() .file( "src/lib.rs", "#[deprecated] fn bar() {} pub fn foo() { let _ = bar(); }", ) .build(); p.cargo("fix --allow-no-vcs") .with_stderr_data(str![[r#" ... [WARNING] use of deprecated function `bar` ... "#]]) .run(); } #[cargo_test] fn warns_if_no_vcs_detected() { let p = project().file("src/lib.rs", "pub fn foo() {}").build(); p.cargo("fix") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no VCS found for this package and `cargo fix` can potentially perform destructive changes; if you'd like to suppress this error pass `--allow-no-vcs` "#]]) .run(); p.cargo("fix --allow-no-vcs").run(); } #[cargo_test] fn warns_about_dirty_working_directory() { let p = git::new("foo", |p| p.file("src/lib.rs", "pub fn foo() {}")); p.change_file("src/lib.rs", ""); p.cargo("fix") .with_status(101) .with_stderr_data(str![[r#" [ERROR] the working directory of this package has uncommitted changes, and `cargo fix` can potentially perform destructive changes; if you'd like to suppress this error pass `--allow-dirty`, `--allow-staged`, or commit the changes to these files: * src/lib.rs (dirty) "#]]) .run(); p.cargo("fix --allow-dirty").run(); } #[cargo_test] fn warns_about_staged_working_directory() { let (p, repo) = git::new_repo("foo", |p| p.file("src/lib.rs", "pub fn foo() {}")); p.change_file("src/lib.rs", "pub fn bar() {}"); git::add(&repo); p.cargo("fix") .with_status(101) .with_stderr_data(str![[r#" [ERROR] the working directory of this package has uncommitted changes, and `cargo fix` can potentially perform destructive changes; if you'd like to suppress this error pass `--allow-dirty`, `--allow-staged`, or commit the changes to these files: * src/lib.rs (staged) "#]]) .run(); p.cargo("fix --allow-staged").run(); } #[cargo_test] fn errors_about_untracked_files() { let mut git_project = project().at("foo"); git_project = git_project.file("src/lib.rs", "pub fn foo() {}"); let p = git_project.build(); let _ = init(&p.root()); p.cargo("fix") .with_status(101) .with_stderr_data(str![[r#" [ERROR] the working directory of this package has uncommitted changes, and `cargo fix` can potentially perform destructive changes; if you'd like to suppress this error pass `--allow-dirty`, `--allow-staged`, or commit the changes to these files: * Cargo.toml (dirty) * src/ (dirty) "#]]) .run(); p.cargo("fix --allow-dirty").run(); } #[cargo_test] fn does_not_warn_about_clean_working_directory() { let p = git::new("foo", |p| p.file("src/lib.rs", "pub fn foo() {}")); p.cargo("fix").run(); } #[cargo_test] fn does_not_warn_about_dirty_ignored_files() { let p = git::new("foo", |p| { p.file("src/lib.rs", "pub fn foo() {}") .file(".gitignore", "bar\n") }); p.change_file("bar", ""); p.cargo("fix").run(); } #[cargo_test] fn fix_all_targets_by_default() { let p = project() .file("src/lib.rs", "pub fn foo() { let mut x = 3; let _ = x; }") .file("tests/foo.rs", "pub fn foo() { let mut x = 3; let _ = x; }") .build(); p.cargo("fix --allow-no-vcs") .env("__CARGO_FIX_YOLO", "1") .run(); assert!(!p.read_file("src/lib.rs").contains("let mut x")); assert!(!p.read_file("tests/foo.rs").contains("let mut x")); } #[cargo_test] fn prepare_for_unstable() { // During the period where a new edition is coming up, but not yet stable, // this test will verify that it cannot be migrated to on stable. If there // is no next edition, it does nothing. let next = match Edition::LATEST_UNSTABLE { Some(next) => next, None => { eprintln!("Next edition is currently not available, skipping test."); return; } }; let latest_stable = Edition::LATEST_STABLE; let prev = latest_stable.previous().unwrap(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "{}" "#, latest_stable ), ) .file("src/lib.rs", "") .build(); // -j1 to make the error more deterministic (otherwise there can be // multiple errors since they run in parallel). p.cargo("fix --edition --allow-no-vcs -j1") .with_stderr_data(&format!("\ [CHECKING] foo v0.1.0 ([ROOT]/foo) [WARNING] `src/lib.rs` is on the latest edition, but trying to migrate to edition {next}. Edition {next} is unstable and not allowed in this release, consider trying the nightly release channel. If you are trying to migrate from the previous edition ({prev}), the process requires following these steps: 1. Start with `edition = \"{prev}\"` in `Cargo.toml` 2. Run `cargo fix --edition` 3. Modify `Cargo.toml` to set `edition = \"{latest_stable}\"` 4. Run `cargo build` or `cargo test` to verify the fixes worked More details may be found at https://doc.rust-lang.org/edition-guide/editions/transitioning-an-existing-project-to-a-new-edition.html [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s ", next=next, latest_stable=latest_stable, prev=prev)) .run(); if !is_nightly() { // The rest of this test is fundamentally always nightly. return; } p.cargo("fix --edition --allow-no-vcs") .masquerade_as_nightly_cargo(&["always_nightly"]) .with_stderr_data(&format!( "\ [MIGRATING] Cargo.toml from {latest_stable} edition to {next} [CHECKING] foo v0.1.0 ([ROOT]/foo) [MIGRATING] src/lib.rs from {latest_stable} edition to {next} [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s ", latest_stable = latest_stable, next = next, )) .run(); } #[cargo_test] fn prepare_for_latest_stable() { // This is the stable counterpart of prepare_for_unstable. let latest_stable = Edition::LATEST_STABLE; let previous = latest_stable.previous().unwrap(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = 'foo' version = '0.1.0' edition = '{}' "#, previous ), ) .file("src/lib.rs", "") .build(); p.cargo("fix --edition --allow-no-vcs") .with_stderr_data(&format!( "\ [MIGRATING] Cargo.toml from {previous} edition to {latest_stable} [CHECKING] foo v0.1.0 ([ROOT]/foo) [MIGRATING] src/lib.rs from {previous} edition to {latest_stable} [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s ", )) .run(); } #[cargo_test(nightly, reason = "fundamentally always nightly")] fn prepare_for_already_on_latest_unstable() { // During the period where a new edition is coming up, but not yet stable, // this test will check what happens if you are already on the latest. If // there is no next edition, it does nothing. let next_edition = match Edition::LATEST_UNSTABLE { Some(next) => next, None => { eprintln!("Next edition is currently not available, skipping test."); return; } }; let p = project() .file( "Cargo.toml", &format!( r#" cargo-features = ["edition{}"] [package] name = 'foo' version = '0.1.0' edition = '{}' "#, next_edition, next_edition ), ) .file("src/lib.rs", "") .build(); p.cargo("fix --edition --allow-no-vcs") .masquerade_as_nightly_cargo(&["always_nightly"]) .with_stderr_data(&format!( "\ [CHECKING] foo v0.1.0 ([ROOT]/foo) [WARNING] `src/lib.rs` is already on the latest edition ({next_edition}), unable to migrate further ... ", next_edition = next_edition )) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] fn prepare_for_already_on_latest_stable() { // Stable counterpart of prepare_for_already_on_latest_unstable. if Edition::LATEST_UNSTABLE.is_some() { eprintln!("This test cannot run while the latest edition is unstable, skipping."); return; } let latest_stable = Edition::LATEST_STABLE; let p = project() .file( "Cargo.toml", &format!( r#" [package] name = 'foo' version = '0.1.0' edition = '{}' "#, latest_stable ), ) .file("src/lib.rs", "") .build(); p.cargo("fix --edition --allow-no-vcs") .with_stderr_contains("[CHECKING] foo [..]") .with_stderr_contains(&format!( "\ [WARNING] `src/lib.rs` is already on the latest edition ({latest_stable}), unable to migrate further ", latest_stable = latest_stable )) .run(); } #[cargo_test] fn fix_overlapping() { let p = project() .file( "src/lib.rs", r#" pub fn foo() {} pub struct A; pub mod bar { pub fn baz() { ::foo::<::A>(); } } "#, ) .build(); p.cargo("fix --allow-no-vcs --edition --lib") .with_stderr_data(str![[r#" [MIGRATING] Cargo.toml from 2015 edition to 2018 [CHECKING] foo v0.0.1 ([ROOT]/foo) [MIGRATING] src/lib.rs from 2015 edition to 2018 [FIXED] src/lib.rs (2 fixes) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let contents = p.read_file("src/lib.rs"); println!("{}", contents); assert!(contents.contains("crate::foo::()")); } #[cargo_test] fn fix_idioms() { let p = project() .file( "Cargo.toml", r#" [package] name = 'foo' version = '0.1.0' edition = '2018' "#, ) .file( "src/lib.rs", r#" use std::any::Any; pub fn foo() { let _x: Box = Box::new(3); } "#, ) .build(); p.cargo("fix --edition-idioms --allow-no-vcs") .with_stderr_data(str![[r#" [CHECKING] foo v0.1.0 ([ROOT]/foo) [FIXED] src/lib.rs (1 fix) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.read_file("src/lib.rs").contains("Box")); } #[cargo_test] fn idioms_2015_ok() { let p = project().file("src/lib.rs", "").build(); p.cargo("fix --edition-idioms --allow-no-vcs").run(); } #[cargo_test] fn shows_warnings_on_second_run_without_changes() { let p = project() .file( "src/lib.rs", r#" #[deprecated] fn bar() {} pub fn foo() { let _ = bar(); } "#, ) .build(); p.cargo("fix --allow-no-vcs") .with_stderr_data(str![[r#" ... [WARNING] use of deprecated function `bar` ... "#]]) .run(); p.cargo("fix --allow-no-vcs") .with_stderr_data(str![[r#" ... [WARNING] use of deprecated function `bar` ... "#]]) .run(); } #[cargo_test] fn shows_warnings_on_second_run_without_changes_on_multiple_targets() { let p = project() .file( "src/lib.rs", r#" #[deprecated] fn bar() {} pub fn foo() { let _ = bar(); } "#, ) .file( "src/main.rs", r#" #[deprecated] fn bar() {} fn main() { let _ = bar(); } "#, ) .file( "tests/foo.rs", r#" #[deprecated] fn bar() {} #[test] fn foo_test() { let _ = bar(); } "#, ) .file( "tests/bar.rs", r#" #[deprecated] fn bar() {} #[test] fn foo_test() { let _ = bar(); } "#, ) .file( "examples/fooxample.rs", r#" #[deprecated] fn bar() {} fn main() { let _ = bar(); } "#, ) .build(); p.cargo("fix --allow-no-vcs --all-targets") .with_stderr_data( str![[r#" ... --> src/lib.rs:6:29 ... --> src/main.rs:6:29 ... --> examples/fooxample.rs:6:29 ... --> tests/foo.rs:7:29 ... --> tests/bar.rs:7:29 ... "#]] .unordered(), ) .run(); p.cargo("fix --allow-no-vcs --all-targets") .with_stderr_data( str![[r#" ... --> src/lib.rs:6:29 ... --> src/main.rs:6:29 ... --> examples/fooxample.rs:6:29 ... --> tests/bar.rs:7:29 ... --> tests/foo.rs:7:29 ... "#]] .unordered(), ) .run(); } #[cargo_test] fn doesnt_rebuild_dependencies() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = 'bar' } [workspace] "#, ) .file("src/lib.rs", "extern crate bar;") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "") .build(); p.cargo("fix --allow-no-vcs -p foo") .env("__CARGO_FIX_YOLO", "1") .with_stdout_data("") .with_stderr_data(str![[r#" [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("fix --allow-no-vcs -p foo") .env("__CARGO_FIX_YOLO", "1") .with_stdout_data("") .with_stderr_data(str![[r#" [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn does_not_crash_with_rustc_wrapper() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fix --allow-no-vcs") .env("RUSTC_WRAPPER", tools::echo_wrapper()) .run(); p.build_dir().rm_rf(); p.cargo("fix --allow-no-vcs --verbose") .env("RUSTC_WORKSPACE_WRAPPER", tools::echo_wrapper()) .run(); } #[cargo_test] fn uses_workspace_wrapper_and_primary_wrapper_override() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fix --allow-no-vcs --verbose") .env("RUSTC_WORKSPACE_WRAPPER", tools::echo_wrapper()) .with_stderr_data(str![[r#" ... WRAPPER CALLED: rustc src/lib.rs --crate-name foo [..] ... "#]]) .run(); } #[cargo_test] fn only_warn_for_relevant_crates() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] a = { path = 'a' } "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" "#, ) .file( "a/src/lib.rs", " pub fn foo() {} pub mod bar { use foo; pub fn baz() { foo() } } ", ) .build(); p.cargo("fix --allow-no-vcs --edition") .with_stderr_data(str![[r#" [MIGRATING] Cargo.toml from 2015 edition to 2018 [LOCKING] 1 package to latest compatible version [CHECKING] a v0.1.0 ([ROOT]/foo/a) [CHECKING] foo v0.1.0 ([ROOT]/foo) [MIGRATING] src/lib.rs from 2015 edition to 2018 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn fix_to_broken_code() { let p = project() .file( "foo/Cargo.toml", r#" [package] name = 'foo' version = '0.1.0' edition = "2015" [workspace] "#, ) .file( "foo/src/main.rs", r#" use std::env; use std::fs; use std::io::Write; use std::path::{Path, PathBuf}; use std::process::{self, Command}; fn main() { // Ignore calls to things like --print=file-names and compiling build.rs. // Also compatible for rustc invocations with `@path` argfile. let is_lib_rs = env::args_os() .map(PathBuf::from) .flat_map(|p| if let Some(p) = p.to_str().unwrap_or_default().strip_prefix("@") { fs::read_to_string(p).unwrap().lines().map(PathBuf::from).collect() } else { vec![p] }) .any(|l| l == Path::new("src/lib.rs")); if is_lib_rs { let path = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let path = path.join("foo"); if path.exists() { panic!() } else { fs::File::create(&path).unwrap(); } } let status = Command::new("rustc") .args(env::args().skip(1)) .status() .expect("failed to run rustc"); process::exit(status.code().unwrap_or(2)); } "#, ) .file( "bar/Cargo.toml", r#" [package] name = 'bar' version = '0.1.0' edition = "2015" [workspace] "#, ) .file("bar/build.rs", "fn main() {}") .file("bar/src/lib.rs", "pub fn foo() { let mut x = 3; let _ = x; }") .build(); // Build our rustc shim p.cargo("build").cwd("foo").run(); // Attempt to fix code, but our shim will always fail the second compile p.cargo("fix --allow-no-vcs --broken-code") .cwd("bar") .env("RUSTC", p.root().join("foo/target/debug/foo")) .with_status(101) .with_stderr_data(str![[r#" ... [WARNING] failed to automatically apply fixes suggested by rustc to crate `bar` ... "#]]) .run(); assert_e2e().eq( p.read_file("bar/src/lib.rs"), str!["pub fn foo() { let x = 3; let _ = x; }"], ); } #[cargo_test] fn fix_with_common() { let p = project() .file("src/lib.rs", "") .file( "tests/t1.rs", "mod common; #[test] fn t1() { common::try(); }", ) .file( "tests/t2.rs", "mod common; #[test] fn t2() { common::try(); }", ) .file("tests/common/mod.rs", "pub fn try() {}") .build(); p.cargo("fix --edition --allow-no-vcs").run(); assert_e2e().eq( p.read_file("tests/common/mod.rs"), str!["pub fn r#try() {}"], ); } #[cargo_test] fn fix_in_existing_repo_weird_ignore() { // Check that ignore doesn't ignore the repo itself. let p = git::new("foo", |project| { project .file("src/lib.rs", "") .file(".gitignore", "foo\ninner\nCargo.lock\ntarget\n") .file("inner/file", "") }); p.cargo("fix").run(); // This is questionable about whether it is the right behavior. It should // probably be checking if any source file for the current project is // ignored. p.cargo("fix") .cwd("inner") .with_stderr_data(str![[r#" [ERROR] no VCS found for this package and `cargo fix` can potentially perform destructive changes; if you'd like to suppress this error pass `--allow-no-vcs` "#]]) .with_status(101) .run(); p.cargo("fix").cwd("src").run(); } #[cargo_test] fn fix_color_message() { // Check that color appears in diagnostics. let p = project() .file("src/lib.rs", "std::compile_error!{\"color test\"}") .build(); p.cargo("fix --allow-no-vcs --color=always") .with_stderr_data( "\ ... [..]\x1b[[..] ... ", ) .with_status(101) .run(); p.cargo("fix --allow-no-vcs --color=never") .with_stderr_data(str![[r#" ... [ERROR] color test ... "#]]) .with_stderr_does_not_contain("[..]\x1b[[..]") .with_status(101) .run(); } #[cargo_test] fn edition_v2_resolver_report() { // Show a report if the V2 resolver shows differences. Package::new("common", "1.0.0") .feature("f1", &[]) .feature("dev-feat", &[]) .add_dep(Dependency::new("opt_dep", "1.0").optional(true)) .publish(); Package::new("opt_dep", "1.0.0").publish(); Package::new("bar", "1.0.0") .add_dep( Dependency::new("common", "1.0") .target("cfg(whatever)") .enable_features(&["f1"]), ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] common = "1.0" bar = "1.0" [build-dependencies] common = { version = "1.0", features = ["opt_dep"] } [dev-dependencies] common = { version="1.0", features=["dev-feat"] } "#, ) .file("src/lib.rs", "") .build(); p.cargo("fix --edition --allow-no-vcs") .with_stderr_data(str![[r#" [MIGRATING] Cargo.toml from 2018 edition to 2021 [UPDATING] `dummy-registry` index [LOCKING] 3 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] common v1.0.0 (registry `dummy-registry`) [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [DOWNLOADED] opt_dep v1.0.0 (registry `dummy-registry`) [NOTE] Switching to Edition 2021 will enable the use of the version 2 feature resolver in Cargo. This may cause some dependencies to be built with fewer features enabled than previously. More information about the resolver changes may be found at https://doc.rust-lang.org/nightly/edition-guide/rust-2021/default-cargo-resolver.html When building the following dependencies, the given features will no longer be used: common v1.0.0 removed features: dev-feat, f1, opt_dep common v1.0.0 (as host dependency) removed features: dev-feat, f1 The following differences only apply when building with dev-dependencies: common v1.0.0 removed features: f1, opt_dep [CHECKING] opt_dep v1.0.0 [CHECKING] common v1.0.0 [CHECKING] bar v1.0.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [MIGRATING] src/lib.rs from 2018 edition to 2021 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]].unordered()) .run(); } #[cargo_test] fn rustfix_handles_multi_spans() { // Checks that rustfix handles a single diagnostic with multiple // suggestion spans (non_fmt_panic in this case). let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file( "src/lib.rs", r#" pub fn foo() { panic!(format!("hey")); } "#, ) .build(); p.cargo("fix --allow-no-vcs").run(); assert!(p.read_file("src/lib.rs").contains(r#"panic!("hey");"#)); } #[cargo_test] fn fix_edition_2021() { // Can migrate 2021, even when lints are allowed. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" "#, ) .file( "src/lib.rs", r#" #![allow(ellipsis_inclusive_range_patterns)] pub fn f() -> bool { let x = 123; match x { 0...100 => true, _ => false, } } "#, ) .build(); p.cargo("fix --edition --allow-no-vcs") .with_stderr_data(str![[r#" [MIGRATING] Cargo.toml from 2018 edition to 2021 [CHECKING] foo v0.1.0 ([ROOT]/foo) [MIGRATING] src/lib.rs from 2018 edition to 2021 [FIXED] src/lib.rs (1 fix) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.read_file("src/lib.rs").contains(r#"0..=100 => true,"#)); } #[cargo_test] fn fix_shared_cross_workspace() { // Fixing a file that is shared between multiple packages in the same workspace. // Make sure two processes don't try to fix the same file at the same time. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo", "bar"] "#, ) .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/lib.rs", "pub mod shared;") // This will fix both unused and bare trait. .file("foo/src/shared.rs", "pub fn fixme(x: Box<&Fn() -> ()>) {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file( "bar/src/lib.rs", r#" #[path="../../foo/src/shared.rs"] pub mod shared; "#, ) .build(); // The output here can be either of these two, depending on who runs first: // [FIXED] bar/src/../../foo/src/shared.rs (2 fixes) // [FIXED] foo/src/shared.rs (2 fixes) p.cargo("fix --allow-no-vcs") .env("__CARGO_FIX_YOLO", "1") .with_stderr_data( str![[r#" [CHECKING] foo v0.1.0 ([ROOT]/foo/foo) [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [FIXED] [..]foo/src/shared.rs (2 fixes) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); assert_e2e().eq( &p.read_file("foo/src/shared.rs"), str!["pub fn fixme(_x: Box<&dyn Fn() -> ()>) {}"], ); } #[cargo_test] fn abnormal_exit() { // rustc fails unexpectedly after applying fixes, should show some error information. // // This works with a proc-macro that runs twice: // - First run (collect diagnostics pass): writes a file, exits normally. // - Second run (verify diagnostics work): it detects the presence of the // file, removes the file, and aborts the process. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] pm = {path="pm"} "#, ) .file( "src/lib.rs", r#" pub fn f() { let mut x = 1; pm::crashme!(); } "#, ) .file( "pm/Cargo.toml", r#" [package] name = "pm" version = "0.1.0" edition = "2018" [lib] proc-macro = true "#, ) .file( "pm/src/lib.rs", r#" use proc_macro::TokenStream; #[proc_macro] pub fn crashme(_input: TokenStream) -> TokenStream { // Use a file to succeed on the first pass, and fail on the second. let p = std::env::var_os("ONCE_PATH").unwrap(); let check_path = std::path::Path::new(&p); if check_path.exists() { eprintln!("I'm not a diagnostic."); std::fs::remove_file(check_path).unwrap(); std::process::abort(); } else { std::fs::write(check_path, "").unwrap(); "".parse().unwrap() } } "#, ) .build(); p.cargo("fix --lib --allow-no-vcs") .env( "ONCE_PATH", paths::root().join("proc-macro-run-once").to_str().unwrap(), ) // "signal: 6, SIGABRT: process abort signal" on some platforms .with_stderr_data(str![[r#" ... [WARNING] failed to automatically apply fixes suggested by rustc to crate `foo` ... I'm not a diagnostic. rustc exited abnormally: [..] Original diagnostics will follow. ... "#]]) .run(); } #[cargo_test] fn fix_with_run_cargo_in_proc_macros() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [lib] proc-macro = true "#, ) .file( "src/lib.rs", r#" use proc_macro::*; #[proc_macro] pub fn foo(_input: TokenStream) -> TokenStream { let output = std::process::Command::new(env!("CARGO")) .args(&["metadata", "--format-version=1"]) .output() .unwrap(); eprintln!("{}", std::str::from_utf8(&output.stderr).unwrap()); println!("{}", std::str::from_utf8(&output.stdout).unwrap()); "".parse().unwrap() } "#, ) .file( "src/bin/main.rs", r#" use foo::foo; fn main() { foo!("bar") } "#, ) .build(); p.cargo("fix --allow-no-vcs") .with_stderr_does_not_contain("error: could not find .rs file in rustc args") .run(); } #[cargo_test] fn non_edition_lint_migration() { // Migrating to a new edition where a non-edition lint causes problems. let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file( "src/lib.rs", r#" // This is only used in a test. // To be correct, this should be gated on #[cfg(test)], but // sometimes people don't do that. If the unused_imports // lint removes this, then the unittest will fail to compile. use std::str::from_utf8; pub mod foo { pub const FOO: &[u8] = &[102, 111, 111]; } #[test] fn example() { assert_eq!( from_utf8(::foo::FOO), Ok("foo") ); } "#, ) .build(); // Check that it complains about an unused import. p.cargo("check --lib") .with_stderr_data(str![[r#" ... [..]use std::str::from_utf8; ... = [NOTE] `#[warn(unused_imports)]` on by default ... "#]]) .run(); p.cargo("fix --edition --allow-no-vcs").run(); let contents = p.read_file("src/lib.rs"); // Check it does not remove the "unused" import. assert!(contents.contains("use std::str::from_utf8;")); // Check that it made the edition migration. assert!(contents.contains("from_utf8(crate::foo::FOO)")); } #[cargo_test] fn fix_in_dependency() { // Tests what happens if rustc emits a suggestion to modify a file from a // dependency in cargo's home directory. This should never happen, and // indicates a bug in rustc. However, there are several known bugs in // rustc where it does this (often involving macros), so `cargo fix` has a // guard that says if the suggestion points to some location in CARGO_HOME // to not apply it. // // See https://github.com/rust-lang/cargo/issues/9857 for some other // examples. // // This test uses a simulated rustc which replays a suggestion via a JSON // message that points into CARGO_HOME. This does not use the real rustc // because as the bugs are fixed in the real rustc, that would cause this // test to stop working. Package::new("bar", "1.0.0") .file( "src/lib.rs", r#" #[macro_export] macro_rules! m { ($i:tt) => { let $i = 1; }; } "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file( "src/lib.rs", r#" pub fn foo() { bar::m!(abc); } "#, ) .build(); p.cargo("fetch").run(); // The path in CARGO_HOME. let bar_path = std::fs::read_dir(paths::home().join(".cargo/registry/src")) .unwrap() .next() .unwrap() .unwrap() .path(); // Since this is a substitution into a Rust string (representing a JSON // string), deal with backslashes like on Windows. let bar_path_str = bar_path.to_str().unwrap().replace("\\", "/"); // This is a fake rustc that will emit a JSON message when the `foo` crate // builds that tells cargo to modify a file it shouldn't. let rustc = project() .at("rustc-replay") .file("Cargo.toml", &basic_manifest("rustc-replay", "1.0.0")) .file("src/main.rs", &r##" fn main() { let pkg_name = match std::env::var("CARGO_PKG_NAME") { Ok(pkg_name) => pkg_name, Err(_) => { let r = std::process::Command::new("rustc") .args(std::env::args_os().skip(1)) .status(); std::process::exit(r.unwrap().code().unwrap_or(2)); } }; if pkg_name == "foo" { eprintln!("{}", r#"{ "$message_type": "diagnostic", "message": "unused variable: `abc`", "code": { "code": "unused_variables", "explanation": null }, "level": "warning", "spans": [ { "file_name": "__BAR_PATH__/bar-1.0.0/src/lib.rs", "byte_start": 127, "byte_end": 129, "line_start": 5, "line_end": 5, "column_start": 29, "column_end": 31, "is_primary": true, "text": [ { "text": " let $i = 1;", "highlight_start": 29, "highlight_end": 31 } ], "label": null, "suggested_replacement": null, "suggestion_applicability": null, "expansion": null } ], "children": [ { "message": "`#[warn(unused_variables)]` on by default", "code": null, "level": "note", "spans": [], "children": [], "rendered": null }, { "message": "if this is intentional, prefix it with an underscore", "code": null, "level": "help", "spans": [ { "file_name": "__BAR_PATH__/bar-1.0.0/src/lib.rs", "byte_start": 127, "byte_end": 129, "line_start": 5, "line_end": 5, "column_start": 29, "column_end": 31, "is_primary": true, "text": [ { "text": " let $i = 1;", "highlight_start": 29, "highlight_end": 31 } ], "label": null, "suggested_replacement": "_abc", "suggestion_applicability": "MachineApplicable", "expansion": null } ], "children": [], "rendered": null } ], "rendered": "warning: unused variable: `abc`\n --> __BAR_PATH__/bar-1.0.0/src/lib.rs:5:29\n |\n5 | let $i = 1;\n | ^^ help: if this is intentional, prefix it with an underscore: `_abc`\n |\n = note: `#[warn(unused_variables)]` on by default\n\n" }"#.replace("\n", "")); } } "##.replace("__BAR_PATH__", &bar_path_str)) .build(); rustc.cargo("build").run(); let rustc_bin = rustc.bin("rustc-replay"); // The output here should not say `Fixed`. // // It is OK to compare the full diagnostic output here because the text is // hard-coded in rustc-replay. Normally tests should not be checking the // compiler output. p.cargo("fix --lib --allow-no-vcs") .env("RUSTC", &rustc_bin) .with_stderr_data(str![[r#" [CHECKING] bar v1.0.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [WARNING] unused variable: `abc` --> [ROOT]/home/.cargo/registry/src/-[HASH]/bar-1.0.0/src/lib.rs:5:29 | 5 | let $i = 1; | ^^ [HELP] if this is intentional, prefix it with an underscore: `_abc` | = [NOTE] `#[warn(unused_variables)]` on by default [WARNING] `foo` (lib) generated 1 warning (run `cargo fix --lib -p foo` to apply 1 suggestion) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn fix_in_rust_src() { // Tests what happens if rustc emits a suggestion to modify the standard // library in rust source. This should never happen, and indicates a bug in // rustc. However, there are several known bugs in rustc where it does this // (often involving macros), so `cargo fix` has a guard that says if the // suggestion points to rust source under sysroot to not apply it. // // See https://github.com/rust-lang/cargo/issues/9857 for some other // examples. // // This test uses a simulated rustc which replays a suggestion via a JSON // message that points into rust-src. This does not use the real rustc // because as the bugs are fixed in the real rustc, that would cause this // test to stop working. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" edition = "2021" "#, ) .file( "src/lib.rs", r#" pub fn bug_report(w: &mut W) -> std::fmt::Result { if true { writeln!(w, "`;?` here ->")?; } else { writeln!(w, "but not here") } Ok(()) } "#, ) .build(); p.cargo("fetch").run(); // Since this is a substitution into a Rust string (representing a JSON // string), deal with backslashes like on Windows. let sysroot = paths::sysroot().replace("\\", "/"); // This is a fake rustc that will emit a JSON message when the `foo` crate // builds that tells cargo to modify a file it shouldn't. let rustc = project() .at("rustc-replay") .file("Cargo.toml", &basic_manifest("rustc-replay", "1.0.0")) .file("src/main.rs", &r##" fn main() { let pkg_name = match std::env::var("CARGO_PKG_NAME") { Ok(pkg_name) => pkg_name, Err(_) => { let r = std::process::Command::new("rustc") .args(std::env::args_os().skip(1)) .status(); std::process::exit(r.unwrap().code().unwrap_or(2)); } }; if pkg_name == "foo" { eprintln!("{}", r#"{ "$message_type": "diagnostic", "message": "mismatched types", "code": { "code": "E0308", "explanation": "Expected type did not match the received type.\n\nErroneous code examples:\n\n```compile_fail,E0308\nfn plus_one(x: i32) -> i32 {\n x + 1\n}\n\nplus_one(\"Not a number\");\n// ^^^^^^^^^^^^^^ expected `i32`, found `&str`\n\nif \"Not a bool\" {\n// ^^^^^^^^^^^^ expected `bool`, found `&str`\n}\n\nlet x: f32 = \"Not a float\";\n// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`\n// |\n// expected due to this\n```\n\nThis error occurs when an expression was used in a place where the compiler\nexpected an expression of a different type. It can occur in several cases, the\nmost common being when calling a function and passing an argument which has a\ndifferent type than the matching type in the function declaration.\n" }, "level": "error", "spans": [ { "file_name": "__SYSROOT__/lib/rustlib/src/rust/library/core/src/macros/mod.rs", "byte_start": 23568, "byte_end": 23617, "line_start": 670, "line_end": 670, "column_start": 9, "column_end": 58, "is_primary": true, "text": [ { "text": " $dst.write_fmt($crate::format_args_nl!($($arg)*))", "highlight_start": 9, "highlight_end": 58 } ], "label": "expected `()`, found `Result<(), Error>`", "suggested_replacement": null, "suggestion_applicability": null, "expansion": { "span": { "file_name": "lib.rs", "byte_start": 144, "byte_end": 171, "line_start": 5, "line_end": 5, "column_start": 9, "column_end": 36, "is_primary": false, "text": [ { "text": " writeln!(w, \"but not here\")", "highlight_start": 9, "highlight_end": 36 } ], "label": null, "suggested_replacement": null, "suggestion_applicability": null, "expansion": null }, "macro_decl_name": "writeln!", "def_site_span": { "file_name": "__SYSROOT__/lib/rustlib/src/rust/library/core/src/macros/mod.rs", "byte_start": 23434, "byte_end": 23454, "line_start": 665, "line_end": 665, "column_start": 1, "column_end": 21, "is_primary": false, "text": [ { "text": "macro_rules! writeln {", "highlight_start": 1, "highlight_end": 21 } ], "label": null, "suggested_replacement": null, "suggestion_applicability": null, "expansion": null } } }, { "file_name": "lib.rs", "byte_start": 75, "byte_end": 177, "line_start": 2, "line_end": 6, "column_start": 5, "column_end": 6, "is_primary": false, "text": [ { "text": " if true {", "highlight_start": 5, "highlight_end": 14 }, { "text": " writeln!(w, \"`;?` here ->\")?;", "highlight_start": 1, "highlight_end": 38 }, { "text": " } else {", "highlight_start": 1, "highlight_end": 13 }, { "text": " writeln!(w, \"but not here\")", "highlight_start": 1, "highlight_end": 36 }, { "text": " }", "highlight_start": 1, "highlight_end": 6 } ], "label": "expected this to be `()`", "suggested_replacement": null, "suggestion_applicability": null, "expansion": null } ], "children": [ { "message": "use the `?` operator to extract the `Result<(), std::fmt::Error>` value, propagating a `Result::Err` value to the caller", "code": null, "level": "help", "spans": [ { "file_name": "__SYSROOT__/lib/rustlib/src/rust/library/core/src/macros/mod.rs", "byte_start": 23617, "byte_end": 23617, "line_start": 670, "line_end": 670, "column_start": 58, "column_end": 58, "is_primary": true, "text": [ { "text": " $dst.write_fmt($crate::format_args_nl!($($arg)*))", "highlight_start": 58, "highlight_end": 58 } ], "label": null, "suggested_replacement": "?", "suggestion_applicability": "HasPlaceholders", "expansion": { "span": { "file_name": "lib.rs", "byte_start": 144, "byte_end": 171, "line_start": 5, "line_end": 5, "column_start": 9, "column_end": 36, "is_primary": false, "text": [ { "text": " writeln!(w, \"but not here\")", "highlight_start": 9, "highlight_end": 36 } ], "label": null, "suggested_replacement": null, "suggestion_applicability": null, "expansion": null }, "macro_decl_name": "writeln!", "def_site_span": { "file_name": "__SYSROOT__/lib/rustlib/src/rust/library/core/src/macros/mod.rs", "byte_start": 23434, "byte_end": 23454, "line_start": 665, "line_end": 665, "column_start": 1, "column_end": 21, "is_primary": false, "text": [ { "text": "macro_rules! writeln {", "highlight_start": 1, "highlight_end": 21 } ], "label": null, "suggested_replacement": null, "suggestion_applicability": null, "expansion": null } } } ], "children": [], "rendered": null } ], "rendered": "error[E0308]: mismatched types\n --> lib.rs:5:9\n |\n2 | / if true {\n3 | | writeln!(w, \"`;?` here ->\")?;\n4 | | } else {\n5 | | writeln!(w, \"but not here\")\n | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Result<(), Error>`\n6 | | }\n | |_____- expected this to be `()`\n |\n = note: expected unit type `()`\n found enum `Result<(), std::fmt::Error>`\n = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info)\nhelp: consider using a semicolon here\n |\n6 | };\n | +\nhelp: you might have meant to return this value\n |\n5 | return writeln!(w, \"but not here\");\n | ++++++ +\nhelp: use the `?` operator to extract the `Result<(), std::fmt::Error>` value, propagating a `Result::Err` value to the caller\n --> __SYSROOT__/lib/rustlib/src/rust/library/core/src/macros/mod.rs:670:58\n |\n67| $dst.write_fmt($crate::format_args_nl!($($arg)*))?\n | +\n\n" }"#.replace("\n", "")); std::process::exit(2); } } "##.replace("__SYSROOT__", &sysroot)) .build(); rustc.cargo("build").run(); let rustc_bin = rustc.bin("rustc-replay"); // The output here should not say `Fixed`. // // It is OK to compare the full diagnostic output here because the text is // hard-coded in rustc-replay. Normally tests should not be checking the // compiler output. p.cargo("fix --lib --allow-no-vcs --broken-code") .env("__CARGO_FIX_YOLO", "1") .env("RUSTC", &rustc_bin) .with_status(101) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.0 ([ROOT]/foo) error[E0308]: mismatched types --> lib.rs:5:9 | 2 | / if true { 3 | | writeln!(w, "`;?` here ->")?; 4 | | } else { 5 | | writeln!(w, "but not here") | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Result<(), Error>` 6 | | } | |_____- expected this to be `()` | = [NOTE] expected unit type `()` found enum `Result<(), std::fmt::Error>` = [NOTE] this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info) [HELP] consider using a semicolon here | 6 | }; | + [HELP] you might have meant to return this value | 5 | return writeln!(w, "but not here"); | ++++++ + [HELP] use the `?` operator to extract the `Result<(), std::fmt::Error>` value, propagating a `Result::Err` value to the caller --> [..]/lib/rustlib/src/rust/library/core/src/macros/mod.rs:670:58 | 67| $dst.write_fmt($crate::format_args_nl!($($arg)*))? | + [ERROR] could not compile `foo` (lib) due to 1 previous error "#]]) .run(); } // See #[cargo_test] fn fix_only_once_for_duplicates() { let p = project() .file( "src/main.rs", r#" macro_rules! foo { () => { &1; }; } fn main() { foo!(); foo!(); } "#, ) .build(); p.cargo("fix --allow-no-vcs") .env("__CARGO_FIX_YOLO", "1") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FIXED] src/main.rs (1 fix) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert_e2e().eq( p.read_file("src/main.rs"), str![[r#" macro_rules! foo { () => { let _ = &1; }; } fn main() { foo!(); foo!(); } "#]], ); } #[cargo_test] fn migrate_project_to_package() { let p = project() .file( "Cargo.toml", r#" # Before project [ project ] # After project header # After project header line name = "foo" edition = "2021" # After project table "#, ) .file("src/lib.rs", "") .build(); p.cargo("fix --edition --allow-no-vcs") .with_stderr_data(str![[r#" [MIGRATING] Cargo.toml from 2021 edition to 2024 [FIXED] Cargo.toml (1 fix) [CHECKING] foo v0.0.0 ([ROOT]/foo) [MIGRATING] src/lib.rs from 2021 edition to 2024 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert_e2e().eq( p.read_file("Cargo.toml"), str![[r#" # Before project [ package ] # After project header # After project header line name = "foo" edition = "2021" # After project table "#]], ); } #[cargo_test] fn migrate_removes_project() { let p = project() .file( "Cargo.toml", r#" # Before package [ package ] # After package header # After package header line name = "foo" edition = "2021" # After package table # Before project [ project ] # After project header # After project header line name = "foo" edition = "2021" # After project table "#, ) .file("src/lib.rs", "") .build(); p.cargo("fix --edition --allow-no-vcs") .with_stderr_data(str![[r#" [MIGRATING] Cargo.toml from 2021 edition to 2024 [FIXED] Cargo.toml (1 fix) [CHECKING] foo v0.0.0 ([ROOT]/foo) [MIGRATING] src/lib.rs from 2021 edition to 2024 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert_e2e().eq( p.read_file("Cargo.toml"), str![[r#" # Before package [ package ] # After package header # After package header line name = "foo" edition = "2021" # After project table "#]], ); } #[cargo_test] fn migrate_removes_project_for_script() { let p = project() .file( "foo.rs", r#" --- # Before package [ package ] # After package header # After package header line name = "foo" edition = "2021" # After package table # Before project [ project ] # After project header # After project header line name = "foo" edition = "2021" # After project table --- fn main() { } "#, ) .build(); p.cargo("-Zscript fix --edition --allow-no-vcs --manifest-path foo.rs") .masquerade_as_nightly_cargo(&["script"]) .with_stderr_data(str![[r#" [MIGRATING] foo.rs from 2021 edition to 2024 [FIXED] foo.rs (1 fix) [CHECKING] foo v0.0.0 ([ROOT]/foo) [MIGRATING] [ROOT]/home/.cargo/target/[HASH]/foo.rs from 2021 edition to 2024 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert_e2e().eq( p.read_file("foo.rs"), str![[r#" --- # Before package [ package ] # After package header # After package header line name = "foo" edition = "2021" # After project table --- fn main() { } "#]], ); } #[cargo_test] fn migrate_rename_underscore_fields() { let p = project() .file( "Cargo.toml", r#" [workspace.dependencies] # Before default_features a = {path = "a", default_features = false} # After default_features value # After default_features line [package] name = "foo" edition = "2021" [lib] name = "foo" # Before crate_type crate_type = ["staticlib", "dylib"] # After crate_type value # After crate_type line [[example]] name = "ex" path = "examples/ex.rs" # Before crate_type crate_type = ["proc-macro"] # After crate_type value # After crate_type line # Before dev_dependencies [ dev_dependencies ] # After dev_dependencies header # After dev_dependencies line a = {path = "a", default_features = false} # After dev_dependencies table # Before build_dependencies [ build_dependencies ] # After build_dependencies header # After build_dependencies line a = {path = "a", default_features = false} # After build_dependencies table # Before dev_dependencies [ target.'cfg(any())'.dev_dependencies ] # After dev_dependencies header # After dev_dependencies line a = {path = "a", default_features = false} # After dev_dependencies table # Before build_dependencies [ target.'cfg(any())'.build_dependencies ] # After build_dependencies header # After build_dependencies line a = {path = "a", default_features = false} # After build_dependencies table "#, ) .file("src/lib.rs", "") .file( "examples/ex.rs", r#" fn main() { println!("ex"); } "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("fix --edition --allow-no-vcs") .with_stderr_data(str![[r#" [MIGRATING] Cargo.toml from 2021 edition to 2024 [FIXED] Cargo.toml (11 fixes) [CHECKING] a v0.0.1 ([ROOT]/foo/a) [CHECKING] foo v0.0.0 ([ROOT]/foo) [MIGRATING] src/lib.rs from 2021 edition to 2024 [MIGRATING] examples/ex.rs from 2021 edition to 2024 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert_e2e().eq( p.read_file("Cargo.toml"), str![[r#" [workspace.dependencies] # Before default_features a = {path = "a", default-features = false} # After default_features value # After default_features line [package] name = "foo" edition = "2021" [lib] name = "foo" # Before crate_type crate-type = ["staticlib", "dylib"] # After crate_type value # After crate_type line [[example]] name = "ex" path = "examples/ex.rs" # Before crate_type crate-type = ["proc-macro"] # After crate_type value # After crate_type line # Before dev_dependencies [ dev-dependencies ] # After dev_dependencies header # After dev_dependencies line a = {path = "a", default-features = false} # After dev_dependencies table # Before build_dependencies [ build-dependencies ] # After build_dependencies header # After build_dependencies line a = {path = "a", default-features = false} # After build_dependencies table # Before dev_dependencies [ target.'cfg(any())'.dev-dependencies ] # After dev_dependencies header # After dev_dependencies line a = {path = "a", default-features = false} # After dev_dependencies table # Before build_dependencies [ target.'cfg(any())'.build-dependencies ] # After build_dependencies header # After build_dependencies line a = {path = "a", default-features = false} # After build_dependencies table "#]], ); } #[cargo_test] fn migrate_rename_underscore_fields_in_virtual_manifest() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo"] resolver = "2" [workspace.dependencies] # Before default_features a = {path = "a", default_features = false} # After default_features value # After default_features line "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" edition = "2021" "#, ) .file("foo/src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("fix --edition --allow-no-vcs") .with_stderr_data(str![[r#" [MIGRATING] Cargo.toml from 2021 edition to 2024 [FIXED] Cargo.toml (1 fix) [MIGRATING] foo/Cargo.toml from 2021 edition to 2024 [CHECKING] foo v0.0.0 ([ROOT]/foo/foo) [MIGRATING] foo/src/lib.rs from 2021 edition to 2024 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert_e2e().eq( p.read_file("Cargo.toml"), str![[r#" [workspace] members = ["foo"] resolver = "2" [workspace.dependencies] # Before default_features a = {path = "a", default-features = false} # After default_features value # After default_features line "#]], ); assert_e2e().eq( p.read_file("foo/Cargo.toml"), str![[r#" [package] name = "foo" edition = "2021" "#]], ); } #[cargo_test] fn remove_ignored_default_features() { Package::new("dep_simple", "0.1.0").publish(); Package::new("dep_df_true", "0.1.0").publish(); Package::new("dep_df_false", "0.1.0").publish(); let pkg_default = r#" [package] name = "pkg_default" version = "0.1.0" edition = "2021" [dependencies] dep_simple = { workspace = true } dep_df_true = { workspace = true } dep_df_false = { workspace = true } [build-dependencies] dep_simple = { workspace = true } dep_df_true = { workspace = true } dep_df_false = { workspace = true } [target.'cfg(target_os = "linux")'.dependencies] dep_simple = { workspace = true } dep_df_true = { workspace = true } dep_df_false = { workspace = true } "#; let pkg_df_true = r#" [package] name = "pkg_df_true" version = "0.1.0" edition = "2021" [dependencies] dep_simple = { workspace = true, default-features = true } dep_df_true = { workspace = true, default-features = true } dep_df_false = { workspace = true, default-features = true } [build-dependencies] dep_simple = { workspace = true, default-features = true } dep_df_true = { workspace = true, default-features = true } dep_df_false = { workspace = true, default-features = true } [target.'cfg(target_os = "linux")'.dependencies] dep_simple = { workspace = true, default-features = true } dep_df_true = { workspace = true, default-features = true } dep_df_false = { workspace = true, default-features = true } "#; let pkg_df_false = r#" [package] name = "pkg_df_false" version = "0.1.0" edition = "2021" [dependencies] dep_simple = { workspace = true, default-features = false } dep_df_true = { workspace = true, default-features = false } dep_df_false = { workspace = true, default-features = false } [build-dependencies] dep_simple = { workspace = true, default-features = false } dep_df_true = { workspace = true, default-features = false } dep_df_false = { workspace = true, default-features = false } [target.'cfg(target_os = "linux")'.dependencies] dep_simple = { workspace = true, default-features = false } dep_df_true = { workspace = true, default-features = false } dep_df_false = { workspace = true, default-features = false } "#; let p = project() .file( "Cargo.toml", r#" [workspace] members = ["pkg_default", "pkg_df_true", "pkg_df_false"] resolver = "2" [workspace.dependencies] dep_simple = "0.1.0" dep_df_true = { version = "0.1.0", default-features = true } dep_df_false = { version = "0.1.0", default-features = false } "#, ) .file("pkg_default/Cargo.toml", pkg_default) .file("pkg_default/src/lib.rs", "") .file("pkg_df_true/Cargo.toml", pkg_df_true) .file("pkg_df_true/src/lib.rs", "") .file("pkg_df_false/Cargo.toml", pkg_df_false) .file("pkg_df_false/src/lib.rs", "") .build(); p.cargo("fix --all --edition --allow-no-vcs") .with_stderr_data( str![[r#" [MIGRATING] pkg_default/Cargo.toml from 2021 edition to 2024 [MIGRATING] pkg_df_true/Cargo.toml from 2021 edition to 2024 [MIGRATING] pkg_df_false/Cargo.toml from 2021 edition to 2024 [FIXED] pkg_df_false/Cargo.toml (6 fixes) [UPDATING] `dummy-registry` index [LOCKING] 3 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] dep_simple v0.1.0 (registry `dummy-registry`) [DOWNLOADED] dep_df_true v0.1.0 (registry `dummy-registry`) [DOWNLOADED] dep_df_false v0.1.0 (registry `dummy-registry`) [CHECKING] dep_df_true v0.1.0 [CHECKING] dep_df_false v0.1.0 [CHECKING] dep_simple v0.1.0 [CHECKING] pkg_df_true v0.1.0 ([ROOT]/foo/pkg_df_true) [CHECKING] pkg_df_false v0.1.0 ([ROOT]/foo/pkg_df_false) [CHECKING] pkg_default v0.1.0 ([ROOT]/foo/pkg_default) [MIGRATING] pkg_df_false/src/lib.rs from 2021 edition to 2024 [MIGRATING] pkg_df_true/src/lib.rs from 2021 edition to 2024 [MIGRATING] pkg_default/src/lib.rs from 2021 edition to 2024 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); assert_e2e().eq(p.read_file("pkg_default/Cargo.toml"), pkg_default); assert_e2e().eq(p.read_file("pkg_df_true/Cargo.toml"), pkg_df_true); assert_e2e().eq( p.read_file("pkg_df_false/Cargo.toml"), str![[r#" [package] name = "pkg_df_false" version = "0.1.0" edition = "2021" [dependencies] dep_simple = { workspace = true} dep_df_true = { workspace = true} dep_df_false = { workspace = true, default-features = false } [build-dependencies] dep_simple = { workspace = true} dep_df_true = { workspace = true} dep_df_false = { workspace = true, default-features = false } [target.'cfg(target_os = "linux")'.dependencies] dep_simple = { workspace = true} dep_df_true = { workspace = true} dep_df_false = { workspace = true, default-features = false } "#]], ); } cargo-0.86.0/tests/testsuite/fix_n_times.rs000064400000000000000000000413211046102023000170600ustar 00000000000000//! Tests for the `cargo fix` command, specifically targeting the logic around //! running rustc multiple times to apply and verify fixes. //! //! These tests use a replacement of rustc ("rustc-fix-shim") which emits JSON //! messages based on what the test is exercising. It uses an environment //! variable `RUSTC_FIX_SHIM_SEQUENCE` which determines how it should behave //! based on how many times `rustc` has run. It keeps track of how many times //! rustc has run in a local file. //! //! For example, a sequence of `[Step::OneFix, Step::Error]` will emit one //! suggested fix the first time `rustc` is run, and then the next time it is //! run it will generate an error. //! //! The [`expect_fix_runs_rustc_n_times`] function handles setting everything //! up, and verifying the results. use std::path::PathBuf; use std::sync::{Mutex, OnceLock}; use cargo_test_support::prelude::*; use cargo_test_support::{basic_manifest, paths, project, str, tools, Execs}; /// The action that the `rustc` shim should take in the current sequence of /// events. #[derive(Clone, Copy, PartialEq)] #[repr(u8)] enum Step { /// Exits with success with no messages. SuccessNoOutput = b'0', /// Emits one suggested fix. /// /// The suggested fix involves updating the number of the first line /// comment which starts as `// fix-count 0`. OneFix = b'1', /// Emits two suggested fixes which overlap, which rustfix can only apply /// one of them, and fails for the other. /// /// The suggested fix is the same as `Step::OneFix`, it just shows up /// twice. TwoFixOverlapping = b'2', /// Generates a warning without a suggestion. Warning = b'w', /// Generates an error message with no suggestion. Error = b'e', /// Emits one suggested fix and an error. OneFixError = b'f', } /// Verifies `cargo fix` behavior based on the given sequence of behaviors for /// `rustc`. /// /// - `sequence` is the sequence of behaviors for each call to `rustc`. /// If rustc is called more often than the number of steps, then it will panic. /// - `extra_execs` a callback that allows extra customization of the [`Execs`]. /// - `expected_stderr` is the expected output from cargo. /// - `expected_lib_rs` is the expected contents of `src/lib.rs` after the /// fixes have been applied. The file starts out with the content `// /// fix-count 0`, and the number increases based on which suggestions are /// applied. fn expect_fix_runs_rustc_n_times( sequence: &[Step], extra_execs: impl FnOnce(&mut Execs), expected_stderr: impl IntoData, expected_lib_rs: &str, ) { let rustc = rustc_for_cargo_fix(); let p = project().file("src/lib.rs", "// fix-count 0").build(); let sequence_vec: Vec<_> = sequence.iter().map(|x| *x as u8).collect(); let sequence_str = std::str::from_utf8(&sequence_vec).unwrap(); let mut execs = p.cargo("fix --allow-no-vcs --lib"); execs .env("RUSTC", &rustc) .env("RUSTC_FIX_SHIM_SEQUENCE", sequence_str) .with_stderr_data(expected_stderr); extra_execs(&mut execs); execs.run(); let lib_rs = p.read_file("src/lib.rs"); assert_eq!(expected_lib_rs, lib_rs); let count: usize = p.read_file("rustc-fix-shim-count").parse().unwrap(); assert_eq!(sequence.len(), count); } /// Returns the path to the rustc replacement executable. fn rustc_for_cargo_fix() -> PathBuf { static FIX_SHIM: OnceLock>> = OnceLock::new(); let mut lock = FIX_SHIM.get_or_init(|| Default::default()).lock().unwrap(); if let Some(path) = &*lock { return path.clone(); } let p = project() .at(paths::global_root().join("rustc-fix-shim")) .file("Cargo.toml", &basic_manifest("rustc-fix-shim", "1.0.0")) .file( "src/main.rs", r##" fn main() { if std::env::var_os("CARGO_PKG_NAME").is_none() { // Handle things like rustc -Vv let r = std::process::Command::new("rustc") .args(std::env::args_os().skip(1)) .status(); std::process::exit(r.unwrap().code().unwrap_or(2)); } // Keep track of which step in the sequence that needs to run. let successful_count = std::fs::read_to_string("rustc-fix-shim-count") .map(|c| c.parse().unwrap()) .unwrap_or(0); std::fs::write("rustc-fix-shim-count", format!("{}", successful_count + 1)).unwrap(); // The sequence tells us which behavior we should have. let seq = std::env::var("RUSTC_FIX_SHIM_SEQUENCE").unwrap(); if successful_count >= seq.len() { panic!("rustc called too many times count={}, \ make sure to update the Step sequence", successful_count); } match seq.as_bytes()[successful_count] { b'0' => return, b'1' => { output_suggestion(successful_count + 1); } b'2' => { output_suggestion(successful_count + 1); output_suggestion(successful_count + 2); } b'w' => { output_message("warning", successful_count + 1); } b'e' => { output_message("error", successful_count + 1); std::process::exit(1); } b'f' => { output_suggestion(successful_count + 1); output_message("error", successful_count + 2); std::process::exit(1); } _ => panic!("unexpected sequence"), } } fn output_suggestion(count: usize) { let json = format!( r#"{{ "$message_type": "diagnostic", "message": "rustc fix shim comment {count}", "code": null, "level": "warning", "spans": [ {{ "file_name": "src/lib.rs", "byte_start": 13, "byte_end": 14, "line_start": 1, "line_end": 1, "column_start": 14, "column_end": 15, "is_primary": true, "text": [ {{ "text": "// fix-count 0", "highlight_start": 14, "highlight_end": 15 }} ], "label": "increase this number", "suggested_replacement": null, "suggestion_applicability": null, "expansion": null }} ], "children": [ {{ "message": "update the number here", "code": null, "level": "help", "spans": [ {{ "file_name": "src/lib.rs", "byte_start": 13, "byte_end": 14, "line_start": 1, "line_end": 1, "column_start": 14, "column_end": 15, "is_primary": true, "text": [ {{ "text": "// fix-count 0", "highlight_start": 14, "highlight_end": 15 }} ], "label": null, "suggested_replacement": "{count}", "suggestion_applicability": "MachineApplicable", "expansion": null }} ], "children": [], "rendered": null }} ], "rendered": "rustc fix shim comment {count}" }}"#, ) .replace("\n", ""); eprintln!("{json}"); } fn output_message(level: &str, count: usize) { let json = format!( r#"{{ "$message_type": "diagnostic", "message": "rustc fix shim {level} count={count}", "code": null, "level": "{level}", "spans": [ {{ "file_name": "src/lib.rs", "byte_start": 0, "byte_end": 0, "line_start": 1, "line_end": 1, "column_start": 1, "column_end": 1, "is_primary": true, "text": [ {{ "text": "// fix-count 0", "highlight_start": 1, "highlight_end": 4 }} ], "label": "forced error", "suggested_replacement": null, "suggestion_applicability": null, "expansion": null }} ], "children": [], "rendered": "rustc fix shim {level} count={count}" }}"#, ) .replace("\n", ""); eprintln!("{json}"); } "##, ) .build(); p.cargo("build").run(); let path = p.bin("rustc-fix-shim"); *lock = Some(path.clone()); path } #[cargo_test] fn fix_no_suggestions() { // No suggested fixes. expect_fix_runs_rustc_n_times( &[Step::SuccessNoOutput], |_execs| {}, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], "// fix-count 0", ); } #[cargo_test] fn fix_one_suggestion() { // One suggested fix, with a successful verification, no output. expect_fix_runs_rustc_n_times( &[Step::OneFix, Step::SuccessNoOutput], |_execs| {}, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FIXED] src/lib.rs (1 fix) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], "// fix-count 1", ); } #[cargo_test] fn fix_one_overlapping() { // Two suggested fixes, where one fails, then the next step returns no suggestions. expect_fix_runs_rustc_n_times( &[Step::TwoFixOverlapping, Step::SuccessNoOutput], |_execs| {}, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FIXED] src/lib.rs (1 fix) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], "// fix-count 2", ); } #[cargo_test] fn fix_overlapping_max() { // Rustc repeatedly spits out suggestions that overlap, which should hit // the limit of 4 attempts. It should show the output from the 5th attempt. expect_fix_runs_rustc_n_times( &[ Step::TwoFixOverlapping, Step::TwoFixOverlapping, Step::TwoFixOverlapping, Step::TwoFixOverlapping, Step::TwoFixOverlapping, ], |_execs| {}, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [WARNING] error applying suggestions to `src/lib.rs` The full error message was: > cannot replace slice of data that was already replaced This likely indicates a bug in either rustc or cargo itself, and we would appreciate a bug report! You're likely to see a number of compiler warnings after this message which cargo attempted to fix but failed. If you could open an issue at https://github.com/rust-lang/rust/issues quoting the full output of this command we'd be very appreciative! Note that you may be able to make some more progress in the near-term fixing code with the `--broken-code` flag [FIXED] src/lib.rs (4 fixes) rustc fix shim comment 5 rustc fix shim comment 6 [WARNING] `foo` (lib) generated 2 warnings (run `cargo fix --lib -p foo` to apply 2 suggestions) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], "// fix-count 5", ); } #[cargo_test] fn fix_verification_failed() { // One suggested fix, with an error in the verification step. // This should cause `cargo fix` to back out the changes. expect_fix_runs_rustc_n_times( &[Step::OneFix, Step::Error], |_execs| {}, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [WARNING] failed to automatically apply fixes suggested by rustc to crate `foo` after fixes were automatically applied the compiler reported errors within these files: * src/lib.rs This likely indicates a bug in either rustc or cargo itself, and we would appreciate a bug report! You're likely to see a number of compiler warnings after this message which cargo attempted to fix but failed. If you could open an issue at https://github.com/rust-lang/rust/issues quoting the full output of this command we'd be very appreciative! Note that you may be able to make some more progress in the near-term fixing code with the `--broken-code` flag The following errors were reported: rustc fix shim error count=2 Original diagnostics will follow. rustc fix shim comment 1 [WARNING] `foo` (lib) generated 1 warning (run `cargo fix --lib -p foo` to apply 1 suggestion) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], "// fix-count 0", ); } #[cargo_test] fn fix_verification_failed_clippy() { // This is the same as `fix_verification_failed_clippy`, except it checks // the error message has the customization for the clippy URL and // subcommand. expect_fix_runs_rustc_n_times( &[Step::OneFix, Step::Error], |execs| { execs.env("RUSTC_WORKSPACE_WRAPPER", tools::wrapped_clippy_driver()); }, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [WARNING] failed to automatically apply fixes suggested by rustc to crate `foo` after fixes were automatically applied the compiler reported errors within these files: * src/lib.rs This likely indicates a bug in either rustc or cargo itself, and we would appreciate a bug report! You're likely to see a number of compiler warnings after this message which cargo attempted to fix but failed. If you could open an issue at https://github.com/rust-lang/rust-clippy/issues quoting the full output of this command we'd be very appreciative! Note that you may be able to make some more progress in the near-term fixing code with the `--broken-code` flag The following errors were reported: rustc fix shim error count=2 Original diagnostics will follow. rustc fix shim comment 1 [WARNING] `foo` (lib) generated 1 warning (run `cargo clippy --fix --lib -p foo` to apply 1 suggestion) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], "// fix-count 0", ); } #[cargo_test] fn warnings() { // Only emits warnings. expect_fix_runs_rustc_n_times( &[Step::Warning], |_execs| {}, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) rustc fix shim warning count=1 [WARNING] `foo` (lib) generated 1 warning [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], "// fix-count 0", ); } #[cargo_test] fn starts_with_error() { // The source code doesn't compile to start with. expect_fix_runs_rustc_n_times( &[Step::Error], |execs| { execs.with_status(101); }, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) rustc fix shim error count=1 [ERROR] could not compile `foo` (lib) due to 1 previous error "#]], "// fix-count 0", ); } #[cargo_test] fn broken_code_no_suggestions() { // --broken-code with no suggestions expect_fix_runs_rustc_n_times( &[Step::Error], |execs| { execs.arg("--broken-code").with_status(101); }, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) rustc fix shim error count=1 [ERROR] could not compile `foo` (lib) due to 1 previous error "#]], "// fix-count 0", ); } #[cargo_test] fn broken_code_one_suggestion() { // --broken-code where there is an error and a suggestion. expect_fix_runs_rustc_n_times( &[Step::OneFixError, Step::Error], |execs| { execs.arg("--broken-code").with_status(101); }, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [WARNING] failed to automatically apply fixes suggested by rustc to crate `foo` after fixes were automatically applied the compiler reported errors within these files: * src/lib.rs This likely indicates a bug in either rustc or cargo itself, and we would appreciate a bug report! You're likely to see a number of compiler warnings after this message which cargo attempted to fix but failed. If you could open an issue at https://github.com/rust-lang/rust/issues quoting the full output of this command we'd be very appreciative! Note that you may be able to make some more progress in the near-term fixing code with the `--broken-code` flag The following errors were reported: rustc fix shim error count=2 Original diagnostics will follow. rustc fix shim comment 1 rustc fix shim error count=2 [WARNING] `foo` (lib) generated 1 warning [ERROR] could not compile `foo` (lib) due to 1 previous error; 1 warning emitted "#]], "// fix-count 1", ); } cargo-0.86.0/tests/testsuite/freshness.rs000064400000000000000000002565531046102023000165730ustar 00000000000000//! Tests for fingerprinting (rebuild detection). use std::fs::{self, OpenOptions}; use std::io; use std::io::prelude::*; use std::net::TcpListener; use std::path::{Path, PathBuf}; use std::process::Stdio; use std::thread; use std::time::SystemTime; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{ basic_lib_manifest, basic_manifest, is_coarse_mtime, project, rustc_host, rustc_host_env, sleep_ms, str, }; use filetime::FileTime; use super::death; #[cargo_test] fn modifying_and_moving() { let p = project() .file("src/main.rs", "mod a; fn main() {}") .file("src/a.rs", "") .build(); p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.root().move_into_the_past(); p.root().join("target").move_into_the_past(); p.change_file("src/a.rs", "#[allow(unused)]fn main() {}"); p.cargo("build -v") .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the file `src/a.rs` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); fs::rename(&p.root().join("src/a.rs"), &p.root().join("src/b.rs")).unwrap(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) error[E0583]: file not found for module `a` ... [ERROR] could not compile `foo` (bin "foo") due to 1 previous error "#]]) .run(); } #[cargo_test] fn modify_only_some_files() { let p = project() .file("src/lib.rs", "mod a;") .file("src/a.rs", "") .file("src/main.rs", "mod b; fn main() {}") .file("src/b.rs", "") .file("tests/test.rs", "") .build(); p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("test").run(); sleep_ms(1000); assert!(p.bin("foo").is_file()); let lib = p.root().join("src/lib.rs"); p.change_file("src/lib.rs", "invalid rust code"); p.change_file("src/b.rs", "#[allow(unused)]fn foo() {}"); lib.move_into_the_past(); // Make sure the binary is rebuilt, not the lib p.cargo("build -v") .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the file `src/b.rs` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.bin("foo").is_file()); } #[cargo_test] fn rebuild_sub_package_then_while_package() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" edition = "2015" [dependencies.a] path = "a" [dependencies.b] path = "b" "#, ) .file("src/lib.rs", "extern crate a; extern crate b;") .file( "a/Cargo.toml", r#" [package] name = "a" authors = [] version = "0.0.1" edition = "2015" [dependencies.b] path = "../b" "#, ) .file("a/src/lib.rs", "extern crate b;") .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/lib.rs", "") .build(); p.cargo("build") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] b v0.0.1 ([ROOT]/foo/b) [COMPILING] a v0.0.1 ([ROOT]/foo/a) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); if is_coarse_mtime() { sleep_ms(1000); } p.change_file("b/src/lib.rs", "pub fn b() {}"); p.cargo("build -pb -v") .with_stderr_data(str![[r#" [DIRTY] b v0.0.1 ([ROOT]/foo/b): the file `b/src/lib.rs` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] b v0.0.1 ([ROOT]/foo/b) [RUNNING] `rustc --crate-name b [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file( "src/lib.rs", "extern crate a; extern crate b; pub fn toplevel() {}", ); p.cargo("build -v") .with_stderr_data(str![[r#" [FRESH] b v0.0.1 ([ROOT]/foo/b) [DIRTY] a v0.0.1 ([ROOT]/foo/a): the dependency b was rebuilt ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] a v0.0.1 ([ROOT]/foo/a) [RUNNING] `rustc --crate-name a [..] [DIRTY] foo v0.0.1 ([ROOT]/foo): the dependency b was rebuilt ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] src/lib.rs [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn changing_lib_features_caches_targets() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" edition = "2015" [features] foo = [] "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build --features foo") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); /* Targets should be cached from the first build */ p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build --features foo") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn changing_profiles_caches_targets() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" edition = "2015" [profile.dev] panic = "abort" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "#]]) .run(); /* Targets should be cached from the first build */ p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("test foo") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .run(); } #[cargo_test] fn changing_bin_paths_common_target_features_caches_targets() { // Make sure dep_cache crate is built once per feature let p = project() .no_manifest() .file( ".cargo/config.toml", r#" [build] target-dir = "./target" "#, ) .file( "dep_crate/Cargo.toml", r#" [package] name = "dep_crate" version = "0.0.1" edition = "2015" authors = [] [features] ftest = [] "#, ) .file( "dep_crate/src/lib.rs", r#" #[cfg(feature = "ftest")] pub fn yo() { println!("ftest on") } #[cfg(not(feature = "ftest"))] pub fn yo() { println!("ftest off") } "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [dependencies] dep_crate = {path = "../dep_crate", features = []} "#, ) .file("a/src/lib.rs", "") .file( "a/src/main.rs", r#" extern crate dep_crate; use dep_crate::yo; fn main() { yo(); } "#, ) .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.0.1" edition = "2015" authors = [] [dependencies] dep_crate = {path = "../dep_crate", features = ["ftest"]} "#, ) .file("b/src/lib.rs", "") .file( "b/src/main.rs", r#" extern crate dep_crate; use dep_crate::yo; fn main() { yo(); } "#, ) .build(); /* Build and rebuild a/. Ensure dep_crate only builds once */ p.cargo("run") .cwd("a") .with_stdout_data(str![[r#" ftest off "#]]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] dep_crate v0.0.1 ([ROOT]/foo/dep_crate) [COMPILING] a v0.0.1 ([ROOT]/foo/a) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/./target/debug/a[EXE]` "#]]) .run(); p.cargo("clean -p a").cwd("a").run(); p.cargo("run") .cwd("a") .with_stdout_data(str![[r#" ftest off "#]]) .with_stderr_data(str![[r#" [COMPILING] a v0.0.1 ([ROOT]/foo/a) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/./target/debug/a[EXE]` "#]]) .run(); /* Build and rebuild b/. Ensure dep_crate only builds once */ p.cargo("run") .cwd("b") .with_stdout_data(str![[r#" ftest on "#]]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] dep_crate v0.0.1 ([ROOT]/foo/dep_crate) [COMPILING] b v0.0.1 ([ROOT]/foo/b) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/./target/debug/b[EXE]` "#]]) .run(); p.cargo("clean -p b").cwd("b").run(); p.cargo("run") .cwd("b") .with_stdout_data(str![[r#" ftest on "#]]) .with_stderr_data(str![[r#" [COMPILING] b v0.0.1 ([ROOT]/foo/b) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/./target/debug/b[EXE]` "#]]) .run(); /* Build a/ package again. If we cache different feature dep builds correctly, * this should not cause a rebuild of dep_crate */ p.cargo("clean -p a").cwd("a").run(); p.cargo("run") .cwd("a") .with_stdout_data(str![[r#" ftest off "#]]) .with_stderr_data(str![[r#" [COMPILING] a v0.0.1 ([ROOT]/foo/a) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/./target/debug/a[EXE]` "#]]) .run(); /* Build b/ package again. If we cache different feature dep builds correctly, * this should not cause a rebuild */ p.cargo("clean -p b").cwd("b").run(); p.cargo("run") .cwd("b") .with_stdout_data(str![[r#" ftest on "#]]) .with_stderr_data(str![[r#" [COMPILING] b v0.0.1 ([ROOT]/foo/b) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/./target/debug/b[EXE]` "#]]) .run(); } #[cargo_test] fn changing_bin_features_caches_targets() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" edition = "2015" [features] foo = [] "#, ) .file( "src/main.rs", r#" fn main() { let msg = if cfg!(feature = "foo") { "feature on" } else { "feature off" }; println!("{}", msg); } "#, ) .build(); p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.rename_run("foo", "off1") .with_stdout_data(str![[r#" feature off "#]]) .run(); p.cargo("build --features foo") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.rename_run("foo", "on1") .with_stdout_data(str![[r#" feature on "#]]) .run(); /* Targets should be cached from the first build */ let mut e = p.cargo("build -v"); // MSVC does not include hash in binary filename, so it gets recompiled. if cfg!(target_env = "msvc") { e.with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the list of features changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } else { e.with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } e.run(); p.rename_run("foo", "off2") .with_stdout_data(str![[r#" feature off "#]]) .run(); let mut e = p.cargo("build --features foo -v"); if cfg!(target_env = "msvc") { e.with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the list of features changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } else { e.with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } e.run(); p.rename_run("foo", "on2") .with_stdout_data(str![[r#" feature on "#]]) .run(); } #[cargo_test] fn rebuild_tests_if_lib_changes() { let p = project() .file("src/lib.rs", "pub fn foo() {}") .file("tests/foo-test.rs", "extern crate foo;") .build(); p.cargo("build").run(); p.cargo("test").run(); sleep_ms(1000); p.change_file("src/lib.rs", ""); p.cargo("build").run(); p.cargo("test -v --test foo-test") .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the dependency foo was rebuilt ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo_test [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/foo_test-[HASH][EXE]` "#]]) .run(); } #[cargo_test] fn no_rebuild_transitive_target_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a" } [dev-dependencies] b = { path = "b" } "#, ) .file("src/lib.rs", "") .file("tests/foo.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [target.foo.dependencies] c = { path = "../c" } "#, ) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.0.1" edition = "2015" authors = [] [dependencies] c = { path = "../c" } "#, ) .file("b/src/lib.rs", "") .file("c/Cargo.toml", &basic_manifest("c", "0.0.1")) .file("c/src/lib.rs", "") .build(); p.cargo("build").run(); p.cargo("test --no-run") .with_stderr_data(str![[r#" [COMPILING] c v0.0.1 ([ROOT]/foo/c) [COMPILING] b v0.0.1 ([ROOT]/foo/b) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [EXECUTABLE] tests/foo.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .run(); } #[cargo_test] fn rerun_if_changed_in_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a" } "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "a/build.rs", r#" fn main() { println!("cargo::rerun-if-changed=build.rs"); } "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("build").run(); p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn same_build_dir_cached_packages() { let p = project() .no_manifest() .file( "a1/Cargo.toml", r#" [package] name = "a1" version = "0.0.1" edition = "2015" authors = [] [dependencies] b = { path = "../b" } "#, ) .file("a1/src/lib.rs", "") .file( "a2/Cargo.toml", r#" [package] name = "a2" version = "0.0.1" edition = "2015" authors = [] [dependencies] b = { path = "../b" } "#, ) .file("a2/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.0.1" edition = "2015" authors = [] [dependencies] c = { path = "../c" } "#, ) .file("b/src/lib.rs", "") .file( "c/Cargo.toml", r#" [package] name = "c" version = "0.0.1" edition = "2015" authors = [] [dependencies] d = { path = "../d" } "#, ) .file("c/src/lib.rs", "") .file("d/Cargo.toml", &basic_manifest("d", "0.0.1")) .file("d/src/lib.rs", "") .file( ".cargo/config.toml", r#" [build] target-dir = "./target" "#, ) .build(); p.cargo("build") .cwd("a1") .with_stderr_data(str![[r#" [LOCKING] 3 packages to latest compatible versions [COMPILING] d v0.0.1 ([ROOT]/foo/d) [COMPILING] c v0.0.1 ([ROOT]/foo/c) [COMPILING] b v0.0.1 ([ROOT]/foo/b) [COMPILING] a1 v0.0.1 ([ROOT]/foo/a1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build") .cwd("a2") .with_stderr_data(str![[r#" [LOCKING] 3 packages to latest compatible versions [COMPILING] a2 v0.0.1 ([ROOT]/foo/a2) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn no_rebuild_if_build_artifacts_move_backwards_in_time() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a" } "#, ) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/src/lib.rs", "") .build(); p.cargo("build").run(); p.root().move_into_the_past(); p.cargo("build") .with_stdout_data(str![]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rebuild_if_build_artifacts_move_forward_in_time() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a" } "#, ) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/src/lib.rs", "") .build(); p.cargo("build").run(); p.root().move_into_the_future(); p.cargo("build") .env("CARGO_LOG", "") .with_stdout_data(str![]) .with_stderr_data(str![[r#" [COMPILING] a v0.0.1 ([ROOT]/foo/a) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rebuild_if_environment_changes() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" description = "old desc" version = "0.0.1" edition = "2015" authors = [] "#, ) .file( "src/main.rs", r#" fn main() { println!("{}", env!("CARGO_PKG_DESCRIPTION")); } "#, ) .build(); p.cargo("run") .with_stdout_data(str![[r#" old desc "#]]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); p.change_file( "Cargo.toml", r#" [package] name = "foo" description = "new desc" version = "0.0.1" edition = "2015" authors = [] "#, ); p.cargo("run -v") .with_stdout_data(str![[r#" new desc "#]]) .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the environment variable CARGO_PKG_DESCRIPTION changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); } #[cargo_test] fn no_rebuild_when_rename_dir() { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [workspace] [dependencies] foo = { path = "foo" } "#, ) .file("src/_unused.rs", "") .file("build.rs", "fn main() {}") .file("foo/Cargo.toml", &basic_manifest("foo", "0.0.1")) .file("foo/src/lib.rs", "") .file("foo/build.rs", "fn main() {}") .build(); // make sure the most recently modified file is `src/lib.rs`, not // `Cargo.toml`, to expose a historical bug where we forgot to strip the // `Cargo.toml` path from looking for the package root. cargo_test_support::sleep_ms(100); fs::write(p.root().join("src/lib.rs"), "").unwrap(); p.cargo("build").run(); let mut new = p.root(); new.pop(); new.push("bar"); fs::rename(p.root(), &new).unwrap(); p.cargo("build") .cwd(&new) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn unused_optional_dep() { Package::new("registry1", "0.1.0").publish(); Package::new("registry2", "0.1.0").publish(); Package::new("registry3", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "p" authors = [] version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } baz = { path = "baz" } registry1 = "*" "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.1" edition = "2015" authors = [] [dev-dependencies] registry2 = "*" "#, ) .file("bar/src/lib.rs", "") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.1" edition = "2015" authors = [] [dependencies] registry3 = { version = "*", optional = true } "#, ) .file("baz/src/lib.rs", "") .build(); p.cargo("build").run(); p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn path_dev_dep_registry_updates() { Package::new("registry1", "0.1.0").publish(); Package::new("registry2", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "p" authors = [] version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.1" edition = "2015" authors = [] [dependencies] registry1 = "*" [dev-dependencies] baz = { path = "../baz"} "#, ) .file("bar/src/lib.rs", "") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.1" edition = "2015" authors = [] [dependencies] registry2 = "*" "#, ) .file("baz/src/lib.rs", "") .build(); p.cargo("build").run(); p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn change_panic_mode() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ['bar', 'baz'] [profile.dev] panic = 'abort' "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1")) .file("bar/src/lib.rs", "") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.1" edition = "2015" authors = [] [lib] proc-macro = true [dependencies] bar = { path = '../bar' } "#, ) .file("baz/src/lib.rs", "extern crate bar;") .build(); p.cargo("build -p bar").run(); p.cargo("build -p baz").run(); } #[cargo_test] fn dont_rebuild_based_on_plugins() { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.1" edition = "2015" [workspace] members = ['baz'] [dependencies] proc-macro-thing = { path = 'proc-macro-thing' } "#, ) .file("src/lib.rs", "") .file( "proc-macro-thing/Cargo.toml", r#" [package] name = "proc-macro-thing" version = "0.1.1" edition = "2015" [lib] proc-macro = true [dependencies] qux = { path = '../qux' } "#, ) .file("proc-macro-thing/src/lib.rs", "") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.1" edition = "2015" [dependencies] qux = { path = '../qux' } "#, ) .file("baz/src/main.rs", "fn main() {}") .file("qux/Cargo.toml", &basic_manifest("qux", "0.1.1")) .file("qux/src/lib.rs", "") .build(); p.cargo("build").run(); p.cargo("build -p baz").run(); p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -p bar") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn reuse_workspace_lib() { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.1" edition = "2015" [workspace] [dependencies] baz = { path = 'baz' } "#, ) .file("src/lib.rs", "") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.1")) .file("baz/src/lib.rs", "") .build(); p.cargo("build").run(); p.cargo("test -p baz -v --no-run") .with_stderr_data(str![[r#" [COMPILING] baz v0.1.1 ([ROOT]/foo/baz) [RUNNING] `rustc --crate-name baz [..] [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] `[ROOT]/foo/target/debug/deps/baz-[HASH][EXE]` "#]]) .run(); } #[cargo_test] fn reuse_shared_build_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] shared = {path = "shared"} [workspace] members = ["shared", "bar"] "#, ) .file("src/main.rs", "fn main() {}") .file("shared/Cargo.toml", &basic_manifest("shared", "0.0.1")) .file("shared/src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" [build-dependencies] shared = { path = "../shared" } "#, ) .file("bar/src/lib.rs", "") .file("bar/build.rs", "fn main() {}") .build(); p.cargo("build --workspace").run(); // This should not recompile! p.cargo("build -p foo -v") .with_stderr_data(str![[r#" [FRESH] shared v0.0.1 ([ROOT]/foo/shared) [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn changing_rustflags_is_cached() { let p = project().file("src/lib.rs", "").build(); // This isn't ever cached, we always have to recompile p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -v") .env("RUSTFLAGS", "-C linker=cc") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -v") .with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -v") .env("RUSTFLAGS", "-C linker=cc") .with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn changing_rustc_extra_flags_is_cached() { let p = project().file("src/lib.rs", "").build(); // This isn't ever cached, we always have to recompile p.cargo("rustc") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("rustc -v -- -C linker=cc") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("rustc -v") .with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("rustc -v -- -C linker=cc") .with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn update_dependency_mtime_does_not_rebuild() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = { path = "bar" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("build -Z mtime-on-use") .masquerade_as_nightly_cargo(&["mtime-on-use"]) .env("RUSTFLAGS", "-C linker=cc") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // This does not make new files, but it does update the mtime of the dependency. p.cargo("build -p bar -Z mtime-on-use") .masquerade_as_nightly_cargo(&["mtime-on-use"]) .env("RUSTFLAGS", "-C linker=cc") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // This should not recompile! p.cargo("build -Z mtime-on-use") .masquerade_as_nightly_cargo(&["mtime-on-use"]) .env("RUSTFLAGS", "-C linker=cc") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } fn fingerprint_cleaner(mut dir: PathBuf, timestamp: filetime::FileTime) { // Cargo is experimenting with letting outside projects develop some // limited forms of GC for target_dir. This is one of the forms. // Specifically, Cargo is updating the mtime of a file in // target/profile/.fingerprint each time it uses the fingerprint. // So a cleaner can remove files associated with a fingerprint // if all the files in the fingerprint's folder are older then a time stamp without // effecting any builds that happened since that time stamp. let mut cleaned = false; dir.push(".fingerprint"); for fing in fs::read_dir(&dir).unwrap() { let fing = fing.unwrap(); let outdated = |f: io::Result| { filetime::FileTime::from_last_modification_time(&f.unwrap().metadata().unwrap()) <= timestamp }; if fs::read_dir(fing.path()).unwrap().all(outdated) { fs::remove_dir_all(fing.path()).unwrap(); println!("remove: {:?}", fing.path()); // a real cleaner would remove the big files in deps and build as well // but fingerprint is sufficient for our tests cleaned = true; } else { } } assert!( cleaned, "called fingerprint_cleaner, but there was nothing to remove" ); } #[cargo_test] fn fingerprint_cleaner_does_not_rebuild() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = { path = "bar" } [features] a = [] "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("build -Z mtime-on-use") .masquerade_as_nightly_cargo(&["mtime-on-use"]) .run(); p.cargo("build -Z mtime-on-use --features a") .masquerade_as_nightly_cargo(&["mtime-on-use"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); if is_coarse_mtime() { sleep_ms(1000); } let timestamp = filetime::FileTime::from_system_time(SystemTime::now()); if is_coarse_mtime() { sleep_ms(1000); } // This does not make new files, but it does update the mtime. p.cargo("build -Z mtime-on-use --features a") .masquerade_as_nightly_cargo(&["mtime-on-use"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); fingerprint_cleaner(p.target_debug_dir(), timestamp); // This should not recompile! p.cargo("build -Z mtime-on-use --features a") .masquerade_as_nightly_cargo(&["mtime-on-use"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // But this should be cleaned and so need a rebuild p.cargo("build -Z mtime-on-use") .masquerade_as_nightly_cargo(&["mtime-on-use"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn reuse_panic_build_dep_test() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [build-dependencies] bar = { path = "bar" } [dev-dependencies] bar = { path = "bar" } [profile.dev] panic = "abort" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); // Check that `bar` is not built twice. It is only needed once (without `panic`). p.cargo("test --lib --no-run -v") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar [..] [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build [..] [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..] src/lib.rs [..]--test[..] [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` "#]]) .run(); } #[cargo_test] fn reuse_panic_pm() { // foo(panic) -> bar(panic) // somepm(nopanic) -> bar(nopanic) let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = { path = "bar" } somepm = { path = "somepm" } [profile.dev] panic = "abort" "#, ) .file("src/lib.rs", "extern crate bar;") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .file( "somepm/Cargo.toml", r#" [package] name = "somepm" version = "0.0.1" edition = "2015" [lib] proc-macro = true [dependencies] bar = { path = "../bar" } "#, ) .file("somepm/src/lib.rs", "extern crate bar;") .build(); // bar is built once without panic (for proc-macro) and once with (for the // normal dependency). p.cargo("build -v") .with_stderr_data( str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar [..] -C panic=abort [..] [RUNNING] `rustc --crate-name bar [..] [COMPILING] somepm v0.0.1 ([ROOT]/foo/somepm) [RUNNING] `rustc --crate-name somepm [..] [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -C panic=abort [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn bust_patched_dep() { Package::new("registry1", "0.1.0").publish(); Package::new("registry2", "0.1.0") .dep("registry1", "0.1.0") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] registry2 = "0.1.0" [patch.crates-io] registry1 = { path = "reg1new" } "#, ) .file("src/lib.rs", "") .file("reg1new/Cargo.toml", &basic_manifest("registry1", "0.1.0")) .file("reg1new/src/lib.rs", "") .build(); p.cargo("build").run(); if is_coarse_mtime() { sleep_ms(1000); } p.change_file("reg1new/src/lib.rs", "// modified"); if is_coarse_mtime() { sleep_ms(1000); } p.cargo("build -v").with_stderr_data(str![[r#" [DIRTY] registry1 v0.1.0 ([ROOT]/foo/reg1new): the file `reg1new/src/lib.rs` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] registry1 v0.1.0 ([ROOT]/foo/reg1new) [RUNNING] `rustc --crate-name registry1 [..] [DIRTY] registry2 v0.1.0: the dependency registry1 was rebuilt [COMPILING] registry2 v0.1.0 [RUNNING] `rustc --crate-name registry2 [..] [DIRTY] foo v0.0.1 ([ROOT]/foo): the dependency registry2 was rebuilt [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); p.cargo("build -v") .with_stderr_data(str![[r#" [FRESH] registry1 v0.1.0 ([ROOT]/foo/reg1new) [FRESH] registry2 v0.1.0 [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rebuild_on_mid_build_file_modification() { let server = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = server.local_addr().unwrap(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["root", "proc_macro_dep"] "#, ) .file( "root/Cargo.toml", r#" [package] name = "root" version = "0.1.0" edition = "2015" authors = [] [dependencies] proc_macro_dep = { path = "../proc_macro_dep" } "#, ) .file( "root/src/lib.rs", r#" #[macro_use] extern crate proc_macro_dep; #[derive(Noop)] pub struct X; "#, ) .file( "proc_macro_dep/Cargo.toml", r#" [package] name = "proc_macro_dep" version = "0.1.0" edition = "2015" authors = [] [lib] proc-macro = true "#, ) .file( "proc_macro_dep/src/lib.rs", &format!( r#" extern crate proc_macro; use std::io::Read; use std::net::TcpStream; use proc_macro::TokenStream; #[proc_macro_derive(Noop)] pub fn noop(_input: TokenStream) -> TokenStream {{ let mut stream = TcpStream::connect("{}").unwrap(); let mut v = Vec::new(); stream.read_to_end(&mut v).unwrap(); "".parse().unwrap() }} "#, addr ), ) .build(); let root = p.root(); let t = thread::spawn(move || { let socket = server.accept().unwrap().0; sleep_ms(1000); let mut file = OpenOptions::new() .write(true) .append(true) .open(root.join("root/src/lib.rs")) .unwrap(); writeln!(file, "// modified").expect("Failed to append to root sources"); drop(file); drop(socket); drop(server.accept().unwrap()); }); p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] proc_macro_dep v0.1.0 ([ROOT]/foo/proc_macro_dep) [COMPILING] root v0.1.0 ([ROOT]/foo/root) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -v").with_stderr_data(str![[r#" [FRESH] proc_macro_dep v0.1.0 ([ROOT]/foo/proc_macro_dep) [DIRTY] root v0.1.0 ([ROOT]/foo/root): the file `root/src/lib.rs` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] root v0.1.0 ([ROOT]/foo/root) [RUNNING] `rustc --crate-name root [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); t.join().ok().unwrap(); } #[cargo_test] fn dirty_both_lib_and_test() { // This tests that all artifacts that depend on the results of a build // script will get rebuilt when the build script reruns, even for separate // commands. It does the following: // // 1. Project "foo" has a build script which will compile a small // staticlib to link against. Normally this would use the `cc` crate, // but here we just use rustc to avoid the `cc` dependency. // 2. Build the library. // 3. Build the unit test. The staticlib intentionally has a bad value. // 4. Rewrite the staticlib with the correct value. // 5. Build the library again. // 6. Build the unit test. This should recompile. let slib = |n| { format!( r#" #[no_mangle] pub extern "C" fn doit() -> i32 {{ return {}; }} "#, n ) }; let p = project() .file( "src/lib.rs", r#" extern "C" { fn doit() -> i32; } #[test] fn t1() { assert_eq!(unsafe { doit() }, 1, "doit assert failure"); } "#, ) .file( "build.rs", r#" use std::env; use std::path::PathBuf; use std::process::Command; fn main() { let rustc = env::var_os("RUSTC").unwrap(); let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); assert!( Command::new(rustc) .args(&[ "--crate-type=staticlib", "--out-dir", out_dir.to_str().unwrap(), "slib.rs" ]) .status() .unwrap() .success(), "slib build failed" ); println!("cargo::rustc-link-lib=slib"); println!("cargo::rustc-link-search={}", out_dir.display()); } "#, ) .file("slib.rs", &slib(2)) .build(); p.cargo("build").run(); // 2 != 1 p.cargo("test --lib") .with_status(101) .with_stdout_data("...\n[..]doit assert failure[..]\n...") .run(); if is_coarse_mtime() { // #5918 sleep_ms(1000); } // Fix the mistake. p.change_file("slib.rs", &slib(1)); p.cargo("build").run(); // This should recompile with the new static lib, and the test should pass. p.cargo("test --lib").run(); } #[cargo_test] fn script_fails_stay_dirty() { // Check if a script is aborted (such as hitting Ctrl-C) that it will re-run. // Steps: // 1. Build to establish fingerprints. // 2. Make a change that triggers the build script to re-run. Abort the // script while it is running. // 3. Run the build again and make sure it re-runs the script. let p = project() .file( "build.rs", r#" mod helper; fn main() { println!("cargo::rerun-if-changed=build.rs"); helper::doit(); } "#, ) .file("helper.rs", "pub fn doit() {}") .file("src/lib.rs", "") .build(); p.cargo("build").run(); if is_coarse_mtime() { sleep_ms(1000); } p.change_file("helper.rs", r#"pub fn doit() {panic!("Crash!");}"#); p.cargo("build") .with_stderr_data("...\n[..]Crash![..]\n...") .with_status(101) .run(); // There was a bug where this second call would be "fresh". p.cargo("build") .with_stderr_data("...\n[..]Crash![..]\n...") .with_status(101) .run(); } #[cargo_test] fn simulated_docker_deps_stay_cached() { // Test what happens in docker where the nanoseconds are zeroed out. Package::new("regdep", "1.0.0").publish(); Package::new("regdep_old_style", "1.0.0") .file("build.rs", "fn main() {}") .file("src/lib.rs", "") .publish(); Package::new("regdep_env", "1.0.0") .file( "build.rs", r#" fn main() { println!("cargo::rerun-if-env-changed=SOMEVAR"); } "#, ) .file("src/lib.rs", "") .publish(); Package::new("regdep_rerun", "1.0.0") .file( "build.rs", r#" fn main() { println!("cargo::rerun-if-changed=build.rs"); } "#, ) .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] pathdep = { path = "pathdep" } regdep = "1.0" regdep_old_style = "1.0" regdep_env = "1.0" regdep_rerun = "1.0" "#, ) .file( "src/lib.rs", " extern crate pathdep; extern crate regdep; extern crate regdep_old_style; extern crate regdep_env; extern crate regdep_rerun; ", ) .file("build.rs", "fn main() {}") .file("pathdep/Cargo.toml", &basic_manifest("pathdep", "1.0.0")) .file("pathdep/src/lib.rs", "") .build(); p.cargo("build").run(); let already_zero = { // This happens on HFS with 1-second timestamp resolution, // or other filesystems where it just so happens to write exactly on a // 1-second boundary. let metadata = fs::metadata(p.root().join("src/lib.rs")).unwrap(); let mtime = FileTime::from_last_modification_time(&metadata); mtime.nanoseconds() == 0 }; // Recursively remove `nanoseconds` from every path. fn zeropath(path: &Path) { for entry in walkdir::WalkDir::new(path) .into_iter() .filter_map(|e| e.ok()) { let metadata = fs::metadata(entry.path()).unwrap(); let mtime = metadata.modified().unwrap(); let mtime_duration = mtime.duration_since(SystemTime::UNIX_EPOCH).unwrap(); let trunc_mtime = FileTime::from_unix_time(mtime_duration.as_secs() as i64, 0); let atime = metadata.accessed().unwrap(); let atime_duration = atime.duration_since(SystemTime::UNIX_EPOCH).unwrap(); let trunc_atime = FileTime::from_unix_time(atime_duration.as_secs() as i64, 0); if let Err(e) = filetime::set_file_times(entry.path(), trunc_atime, trunc_mtime) { // Windows doesn't allow changing filetimes on some things // (directories, other random things I'm not sure why). Just // ignore them. if e.kind() == std::io::ErrorKind::PermissionDenied { println!("PermissionDenied filetime on {:?}", entry.path()); } else { panic!("FileTime error on {:?}: {:?}", entry.path(), e); } } } } zeropath(&p.root()); zeropath(&paths::home()); if already_zero { println!("already zero"); // If it was already truncated, then everything stays fresh. p.cargo("build -v") .with_stderr_data( str![[r#" [FRESH] pathdep [..] [FRESH] regdep [..] [FRESH] regdep_env [..] [FRESH] regdep_old_style [..] [FRESH] regdep_rerun [..] [FRESH] foo [..] [FINISHED] [..] "#]] .unordered(), ) .run(); } else { println!("not already zero"); // It is not ideal that `foo` gets recompiled, but that is the current // behavior. Currently mtimes are ignored for registry deps. // // Note that this behavior is due to the fact that `foo` has a build // script in "old" mode where it doesn't print `rerun-if-*`. In this // mode we use `Precalculated` to fingerprint a path dependency, where // `Precalculated` is an opaque string which has the most recent mtime // in it. It differs between builds because one has nsec=0 and the other // likely has a nonzero nsec. Hence, the rebuild. p.cargo("build -v") .with_stderr_data( str![[r#" [FRESH] regdep [..] [FRESH] pathdep [..] [FRESH] regdep_env [..] [DIRTY] foo v0.1.0 ([ROOT]/foo): the precalculated components changed [COMPILING] foo v0.1.0 ([ROOT]/foo) [FRESH] regdep_rerun [..] [FRESH] regdep_old_style [..] [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } } #[cargo_test] fn metadata_change_invalidates() { // (key, value, value-updated, env-var-name) let scenarios = [ ( "description", r#""foo""#, r#""foo_updated""#, "CARGO_PKG_DESCRIPTION", ), ( "homepage", r#""foo""#, r#""foo_updated""#, "CARGO_PKG_HOMEPAGE", ), ( "repository", r#""foo""#, r#""foo_updated""#, "CARGO_PKG_REPOSITORY", ), ( "license", r#""foo""#, r#""foo_updated""#, "CARGO_PKG_LICENSE", ), ( "license-file", r#""foo""#, r#""foo_updated""#, "CARGO_PKG_LICENSE_FILE", ), ( "authors", r#"["foo"]"#, r#"["foo_updated"]"#, "CARGO_PKG_AUTHORS", ), ( "rust-version", r#""1.0.0""#, r#""1.0.1""#, "CARGO_PKG_RUST_VERSION", ), ("readme", r#""foo""#, r#""foo_updated""#, "CARGO_PKG_README"), ]; let base_cargo_toml = r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#; let p = project().build(); for (key, value, value_updated, env_var) in scenarios { p.change_file("Cargo.toml", base_cargo_toml); p.change_file( "src/main.rs", &format!( r#" fn main() {{ let output = env!("{env_var}"); println!("{{output}}"); }} "# ), ); // Compile the first time p.cargo("build").run(); // Update the manifest, rebuild, and verify the build was invalided p.change_file("Cargo.toml", &format!("{base_cargo_toml}\n{key} = {value}")); p.cargo("build -v") .with_stderr_data(format!( r#"[DIRTY] foo v0.1.0 ([ROOT]/foo): the environment variable {env_var} changed [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "# )) .run(); // Remove references to the metadata and rebuild p.change_file( "src/main.rs", r#" fn main() { println!("foo"); } "#, ); p.cargo("build").run(); // Update the manifest value and verify the build is NOT invalidated. p.change_file( "Cargo.toml", &format!("{base_cargo_toml}\n{key} = {value_updated}"), ); p.cargo("build -v") .with_stderr_data(str![[r#" [FRESH] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } } #[cargo_test] fn edition_change_invalidates() { const MANIFEST: &str = r#" [package] name = "foo" version = "0.1.0" "#; let p = project() .file("Cargo.toml", MANIFEST) .file("src/lib.rs", "") .build(); p.cargo("build").run(); p.change_file("Cargo.toml", &format!("{}edition = \"2018\"", MANIFEST)); p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file( "Cargo.toml", &format!( r#"{}edition = "2018" [lib] edition = "2015" "#, MANIFEST ), ); p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -v") .with_stderr_data(str![[r#" [FRESH] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert_eq!(p.glob("target/debug/deps/libfoo-*.rlib").count(), 1); } #[cargo_test] fn rename_with_path_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = { path = 'a' } "#, ) .file("src/lib.rs", "extern crate a; pub fn foo() { a::foo(); }") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] [dependencies] b = { path = 'b' } "#, ) .file("a/src/lib.rs", "extern crate b; pub fn foo() { b::foo() }") .file( "a/b/Cargo.toml", r#" [package] name = "b" version = "0.5.0" edition = "2015" authors = [] "#, ) .file("a/b/src/lib.rs", "pub fn foo() { }"); let p = p.build(); p.cargo("build").run(); // Now rename the root directory and rerun `cargo run`. Not only should we // not build anything but we also shouldn't crash. let mut new = p.root(); new.pop(); new.push("foo2"); fs::rename(p.root(), &new).unwrap(); p.cargo("build") .cwd(&new) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn move_target_directory_with_path_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = { path = "a" } "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] "#, ) .file("src/lib.rs", "extern crate a; pub use a::print_msg;") .file( "a/build.rs", r###" use std::env; use std::fs; use std::path::Path; fn main() { println!("cargo::rerun-if-changed=build.rs"); let out_dir = env::var("OUT_DIR").unwrap(); let dest_path = Path::new(&out_dir).join("hello.rs"); fs::write(&dest_path, r#" pub fn message() -> &'static str { "Hello, World!" } "#).unwrap(); } "###, ) .file( "a/src/lib.rs", r#" include!(concat!(env!("OUT_DIR"), "/hello.rs")); pub fn print_msg() { message(); } "#, ); let p = p.build(); let mut parent = p.root(); parent.pop(); p.cargo("build").run(); let new_target = p.root().join("target2"); fs::rename(p.root().join("target"), &new_target).unwrap(); p.cargo("build") .env("CARGO_TARGET_DIR", &new_target) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rerun_if_changes() { let p = project() .file( "build.rs", r#" fn main() { println!("cargo::rerun-if-env-changed=FOO"); if std::env::var("FOO").is_ok() { println!("cargo::rerun-if-env-changed=BAR"); } } "#, ) .file("src/lib.rs", "") .build(); p.cargo("build").run(); p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -v") .env("FOO", "1") .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the env variable FOO changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build") .env("FOO", "1") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -v") .env("FOO", "1") .env("BAR", "1") .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the env variable BAR changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build") .env("FOO", "1") .env("BAR", "1") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -v") .env("BAR", "2") .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the env variable FOO changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build") .env("BAR", "2") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn channel_shares_filenames() { // Test that different "nightly" releases use the same output filename. // Create separate rustc binaries to emulate running different toolchains. let nightly1 = format!( "\ rustc 1.44.0-nightly (38114ff16 2020-03-21) binary: rustc commit-hash: 38114ff16e7856f98b2b4be7ab4cd29b38bed59a commit-date: 2020-03-21 host: {} release: 1.44.0-nightly LLVM version: 9.0 ", rustc_host() ); let nightly2 = format!( "\ rustc 1.44.0-nightly (a5b09d354 2020-03-31) binary: rustc commit-hash: a5b09d35473615e7142f5570f5c5fad0caf68bd2 commit-date: 2020-03-31 host: {} release: 1.44.0-nightly LLVM version: 9.0 ", rustc_host() ); let beta1 = format!( "\ rustc 1.43.0-beta.3 (4c587bbda 2020-03-25) binary: rustc commit-hash: 4c587bbda04ab55aaf56feab11dfdfe387a85d7a commit-date: 2020-03-25 host: {} release: 1.43.0-beta.3 LLVM version: 9.0 ", rustc_host() ); let beta2 = format!( "\ rustc 1.42.0-beta.5 (4e1c5f0e9 2020-02-28) binary: rustc commit-hash: 4e1c5f0e9769a588b91c977e3d81e140209ef3a2 commit-date: 2020-02-28 host: {} release: 1.42.0-beta.5 LLVM version: 9.0 ", rustc_host() ); let stable1 = format!( "\ rustc 1.42.0 (b8cedc004 2020-03-09) binary: rustc commit-hash: b8cedc00407a4c56a3bda1ed605c6fc166655447 commit-date: 2020-03-09 host: {} release: 1.42.0 LLVM version: 9.0 ", rustc_host() ); let stable2 = format!( "\ rustc 1.41.1 (f3e1a954d 2020-02-24) binary: rustc commit-hash: f3e1a954d2ead4e2fc197c7da7d71e6c61bad196 commit-date: 2020-02-24 host: {} release: 1.41.1 LLVM version: 9.0 ", rustc_host() ); let compiler = project() .at("compiler") .file("Cargo.toml", &basic_manifest("compiler", "0.1.0")) .file( "src/main.rs", r#" fn main() { if std::env::args_os().any(|a| a == "-vV") { print!("{}", env!("FUNKY_VERSION_TEST")); return; } let mut cmd = std::process::Command::new("rustc"); cmd.args(std::env::args_os().skip(1)); assert!(cmd.status().unwrap().success()); } "#, ) .build(); let makeit = |version, vv| { // Force a rebuild. compiler.target_debug_dir().join("deps").rm_rf(); compiler.cargo("build").env("FUNKY_VERSION_TEST", vv).run(); fs::rename(compiler.bin("compiler"), compiler.bin(version)).unwrap(); }; makeit("nightly1", nightly1); makeit("nightly2", nightly2); makeit("beta1", beta1); makeit("beta2", beta2); makeit("stable1", stable1); makeit("stable2", stable2); // Run `cargo check` with different rustc versions to observe its behavior. let p = project().file("src/lib.rs", "").build(); // Runs `cargo check` and returns the rmeta filename created. // Checks that the freshness matches the given value. let check = |version, fresh| -> String { let output = p .cargo("check --message-format=json") .env("RUSTC", compiler.bin(version)) .run(); // Collect the filenames generated. let mut artifacts: Vec<_> = std::str::from_utf8(&output.stdout) .unwrap() .lines() .filter_map(|line| { let value: serde_json::Value = serde_json::from_str(line).unwrap(); if value["reason"].as_str().unwrap() == "compiler-artifact" { assert_eq!(value["fresh"].as_bool().unwrap(), fresh); let filenames = value["filenames"].as_array().unwrap(); assert_eq!(filenames.len(), 1); Some(filenames[0].to_string()) } else { None } }) .collect(); // Should only generate one rmeta file. assert_eq!(artifacts.len(), 1); artifacts.pop().unwrap() }; let nightly1_name = check("nightly1", false); assert_eq!(check("nightly1", true), nightly1_name); assert_eq!(check("nightly2", false), nightly1_name); // same as before assert_eq!(check("nightly2", true), nightly1_name); // Should rebuild going back to nightly1. assert_eq!(check("nightly1", false), nightly1_name); let beta1_name = check("beta1", false); assert_ne!(beta1_name, nightly1_name); assert_eq!(check("beta1", true), beta1_name); assert_eq!(check("beta2", false), beta1_name); // same as before assert_eq!(check("beta2", true), beta1_name); // Should rebuild going back to beta1. assert_eq!(check("beta1", false), beta1_name); let stable1_name = check("stable1", false); assert_ne!(stable1_name, nightly1_name); assert_ne!(stable1_name, beta1_name); let stable2_name = check("stable2", false); assert_ne!(stable1_name, stable2_name); // Check everything is fresh. assert_eq!(check("stable1", true), stable1_name); assert_eq!(check("stable2", true), stable2_name); assert_eq!(check("beta1", true), beta1_name); assert_eq!(check("nightly1", true), nightly1_name); } #[cargo_test] fn linking_interrupted() { // Interrupt during the linking phase shouldn't leave test executable as "fresh". // This is used to detect when linking starts, then to pause the linker so // that the test can kill cargo. let link_listener = TcpListener::bind("127.0.0.1:0").unwrap(); let link_addr = link_listener.local_addr().unwrap(); // This is used to detect when rustc exits. let rustc_listener = TcpListener::bind("127.0.0.1:0").unwrap(); let rustc_addr = rustc_listener.local_addr().unwrap(); // Create a linker that we can interrupt. let linker = project() .at("linker") .file("Cargo.toml", &basic_manifest("linker", "1.0.0")) .file( "src/main.rs", &r#" fn main() { // Figure out the output filename. let output = match std::env::args().find(|a| a.starts_with("/OUT:")) { Some(s) => s[5..].to_string(), None => { let mut args = std::env::args(); loop { if args.next().unwrap() == "-o" { break; } } args.next().unwrap() } }; std::fs::remove_file(&output).unwrap(); std::fs::write(&output, "").unwrap(); // Tell the test that we are ready to be interrupted. let mut socket = std::net::TcpStream::connect("__ADDR__").unwrap(); // Wait for the test to kill us. std::thread::sleep(std::time::Duration::new(60, 0)); } "# .replace("__ADDR__", &link_addr.to_string()), ) .build(); linker.cargo("build").run(); // Create a wrapper around rustc that will tell us when rustc is finished. let rustc = project() .at("rustc-waiter") .file("Cargo.toml", &basic_manifest("rustc-waiter", "1.0.0")) .file( "src/main.rs", &r#" fn main() { let mut conn = None; // Check for a normal build (not -vV or --print). if std::env::args().any(|arg| arg == "t1") { // Tell the test that rustc has started. conn = Some(std::net::TcpStream::connect("__ADDR__").unwrap()); } let status = std::process::Command::new("rustc") .args(std::env::args().skip(1)) .status() .expect("rustc to run"); std::process::exit(status.code().unwrap_or(1)); } "# .replace("__ADDR__", &rustc_addr.to_string()), ) .build(); rustc.cargo("build").run(); // Build it once so that the fingerprint gets saved to disk. let p = project() .file("src/lib.rs", "") .file("tests/t1.rs", "") .build(); p.cargo("test --test t1 --no-run").run(); // Make a change, start a build, then interrupt it. p.change_file("src/lib.rs", "// modified"); let linker_env = format!("CARGO_TARGET_{}_LINKER", rustc_host_env()); // NOTE: This assumes that the paths to the linker or rustc are not in the // fingerprint. But maybe they should be? let mut cmd = p .cargo("test --test t1 --no-run") .env(&linker_env, linker.bin("linker")) .env("RUSTC", rustc.bin("rustc-waiter")) .build_command(); let mut child = cmd .stdout(Stdio::null()) .stderr(Stdio::null()) .env("__CARGO_TEST_SETSID_PLEASE_DONT_USE_ELSEWHERE", "1") .spawn() .unwrap(); // Wait for rustc to start. let mut rustc_conn = rustc_listener.accept().unwrap().0; // Wait for linking to start. drop(link_listener.accept().unwrap()); // Interrupt the child. death::ctrl_c(&mut child); assert!(!child.wait().unwrap().success()); // Wait for rustc to exit. If we don't wait, then the command below could // start while rustc is still being torn down. let mut buf = [0]; drop(rustc_conn.read_exact(&mut buf)); // Build again, shouldn't be fresh. p.cargo("test --test t1 -v") .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the config settings changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] [RUNNING] `rustc --crate-name t1 [..] [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/t1-[HASH][EXE]` "#]]) .run(); } #[cargo_test] #[cfg_attr( not(all(target_arch = "x86_64", target_os = "windows", target_env = "msvc")), ignore )] fn lld_is_fresh() { // Check for bug when using lld linker that it remains fresh with dylib. let p = project() .file( ".cargo/config.toml", r#" [target.x86_64-pc-windows-msvc] linker = "rust-lld" rustflags = ["-C", "link-arg=-fuse-ld=lld"] "#, ) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] crate-type = ["dylib"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("build").run(); p.cargo("build -v") .with_stderr_data(str![[r#" [FRESH] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn env_in_code_causes_rebuild() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file( "src/main.rs", r#" fn main() { println!("{:?}", option_env!("FOO")); println!("{:?}", option_env!("FOO\nBAR")); } "#, ) .build(); p.cargo("build").env_remove("FOO").run(); p.cargo("build") .env_remove("FOO") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -v") .env("FOO", "bar") .with_stderr_data(str![[r#" [DIRTY] foo v0.1.0 ([ROOT]/foo): the environment variable FOO changed [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build") .env("FOO", "bar") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -v") .env("FOO", "baz") .with_stderr_data(str![[r#" [DIRTY] foo v0.1.0 ([ROOT]/foo): the environment variable FOO changed [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build") .env("FOO", "baz") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -v") .env_remove("FOO") .with_stderr_data(str![[r#" [DIRTY] foo v0.1.0 ([ROOT]/foo): the environment variable FOO changed [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build") .env_remove("FOO") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let interesting = " #!$\nabc\r\\\t\u{8}\r\n"; p.cargo("build").env("FOO", interesting).run(); p.cargo("build") .env("FOO", interesting) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build").env("FOO\nBAR", interesting).run(); p.cargo("build") .env("FOO\nBAR", interesting) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn env_build_script_no_rebuild() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file( "build.rs", r#" fn main() { println!("cargo::rustc-env=FOO=bar"); } "#, ) .file( "src/main.rs", r#" fn main() { println!("{:?}", env!("FOO")); } "#, ) .build(); p.cargo("build").run(); p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cargo_env_changes() { // Checks that changes to the env var CARGO in the dep-info file triggers // a rebuild. let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file( "src/main.rs", r#" fn main() { println!("{:?}", env!("CARGO")); } "#, ) .build(); let cargo_exe = cargo_test_support::cargo_exe(); let other_cargo_path = p.root().join(cargo_exe.file_name().unwrap()); std::fs::hard_link(&cargo_exe, &other_cargo_path).unwrap(); let other_cargo = || { let mut pb = cargo_test_support::process(&other_cargo_path); pb.cwd(p.root()); cargo_test_support::execs().with_process_builder(pb) }; p.cargo("check").run(); other_cargo() .arg("check") .arg("-v") .with_stderr_data(str![[r#" [DIRTY] foo v1.0.0 ([ROOT]/foo): the environment variable CARGO changed [CHECKING] foo v1.0.0 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // And just to confirm that without using env! it doesn't rebuild. p.change_file("src/main.rs", "fn main() {}"); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] foo v1.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); other_cargo() .arg("check") .arg("-v") .with_stderr_data(str![[r#" [FRESH] foo v1.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn changing_linker() { // Changing linker should rebuild. let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("build").run(); let linker_env = format!("CARGO_TARGET_{}_LINKER", rustc_host_env()); p.cargo("build --verbose") .env(&linker_env, "nonexistent-linker") .with_status(101) .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the config settings changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -C linker=nonexistent-linker [..]` [ERROR] linker `nonexistent-linker` not found ... "#]]) .run(); } #[cargo_test] fn verify_source_before_recompile() { Package::new("bar", "0.1.0") .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("vendor --respect-source-config").run(); p.change_file( ".cargo/config.toml", r#" [source.crates-io] replace-with = 'vendor' [source.vendor] directory = 'vendor' "#, ); // Sanity check: vendoring works correctly. p.cargo("check --verbose") .with_stderr_data(str![[r#" [CHECKING] bar v0.1.0 [RUNNING] `rustc --crate-name bar [..] [ROOT]/foo/vendor/bar/src/lib.rs [..] [CHECKING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] src/lib.rs [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Now modify vendored crate. p.change_file( "vendor/bar/src/lib.rs", r#"compile_error!("You shall not pass!");"#, ); // Should ignore modified sources without any recompile. p.cargo("check --verbose") .with_stderr_data(str![[r#" [FRESH] bar v0.1.0 [FRESH] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Add a `RUSTFLAGS` to trigger a recompile. // // Cargo should refuse to build because of checksum verification failure. // Cargo shouldn't recompile dependency `bar`. p.cargo("check --verbose") .env("RUSTFLAGS", "-W warnings") .with_status(101) .with_stderr_data(str![[r#" [ERROR] the listed checksum of `[ROOT]/foo/vendor/bar/src/lib.rs` has changed: expected: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 actual: 66e843918c1d4ea8231af814f9f958958808249d4407de01114acb730ecd9bdf directory sources are not intended to be edited, if modifications are required then it is recommended that `[patch]` is used with a forked copy of the source "#]]) .run(); } #[cargo_test] fn skip_mtime_check_in_selected_cargo_home_subdirs() { let p = project() .at("cargo_home/registry/foo") .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .build(); let project_root = p.root(); let cargo_home = project_root.parent().unwrap().parent().unwrap(); p.cargo("check -v") .env("CARGO_HOME", &cargo_home) .with_stderr_data(str![[r#" [CHECKING] foo v0.5.0 ([ROOT]/cargo_home/registry/foo) [RUNNING] `rustc --crate-name foo [..] src/lib.rs [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file("src/lib.rs", "illegal syntax"); p.cargo("check -v") .env("CARGO_HOME", &cargo_home) .with_stderr_data(str![[r#" [FRESH] foo v0.5.0 ([ROOT]/cargo_home/registry/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn use_mtime_cache_in_cargo_home() { let p = project() .at("cargo_home/foo") .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .build(); let project_root = p.root(); let cargo_home = project_root.parent().unwrap(); p.cargo("check -v") .env("CARGO_HOME", &cargo_home) .with_stderr_data(str![[r#" [CHECKING] foo v0.5.0 ([ROOT]/cargo_home/foo) [RUNNING] `rustc --crate-name foo [..] src/lib.rs [..] src/lib.rs [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file("src/lib.rs", "illegal syntax"); p.cargo("check -v") .env("CARGO_HOME", &cargo_home) .with_status(101) .with_stderr_data(str![[r#" [DIRTY] foo v0.5.0 ([ROOT]/cargo_home/foo): the file `src/lib.rs` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) [CHECKING] foo v0.5.0 ([ROOT]/cargo_home/foo) [RUNNING] `rustc --crate-name foo [..] src/lib.rs [..] ... [ERROR] could not compile `foo` (lib) due to 1 previous error ... "#]]) .run(); } cargo-0.86.0/tests/testsuite/freshness_checksum.rs000064400000000000000000002611531046102023000204450ustar 00000000000000//! Tests for checksum-based fingerprinting (rebuild detection). use std::fs::{self, OpenOptions}; use std::io::prelude::*; use std::net::TcpListener; use std::process::Stdio; use std::thread; use cargo_test_support::assert_deps_contains; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{ basic_lib_manifest, basic_manifest, project, rustc_host, rustc_host_env, str, }; use super::death; #[cargo_test] fn non_nightly_fails() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("build -Zchecksum-freshness") .with_stderr_data(str![[r#" [ERROR] the `-Z` flag is only accepted on the nightly channel of Cargo, but this is the `stable` channel See https://doc.rust-lang.org/book/appendix-07-nightly-rust.html for more information about Rust release channels. "#]]) .with_status(101) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn checksum_actually_uses_checksum() { let p = project() .file("src/main.rs", "mod a; fn main() {}") .file("src/a.rs", "") .build(); p.cargo("check -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.root().move_into_the_future(); p.cargo("check -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn checksum_build_compatible_with_mtime_build() { let p = project() .file("src/main.rs", "mod a; fn main() {}") .file("src/a.rs", "") .build(); p.cargo("check -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn same_size_different_content() { let p = project() .file("src/main.rs", "mod a; fn main() {}") .file("src/a.rs", "") .build(); p.cargo("check -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file("src/main.rs", "mod a;fn main() { }"); p.cargo("check -v -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the file `src/main.rs` has changed (checksum didn't match, blake3=26aa07e1adab787246f9d333be65d2eb78dd5fd0fee834ba7a769098b4b651bc != blake3=fc1a42e376d9c148227c13de41b77143f6b5b8132d2b204b63cdbc9326848894) [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test( nightly, reason = "-Zbinary-dep-depinfo is unstable, also requires -Zchecksum-hash-algorithm" )] fn binary_depinfo_correctly_encoded() { Package::new("regdep", "0.1.0") .file("src/lib.rs", "pub fn f() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] regdep = "0.1" bar = {path = "./bar"} "#, ) .file( "src/main.rs", r#" fn main() { regdep::f(); bar::f(); } "#, ) /*********** Path Dependency `bar` ***********/ .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn f() {}") .build(); let host = rustc_host(); p.cargo("build -Zbinary-dep-depinfo -Zchecksum-freshness --target") .arg(&host) .masquerade_as_nightly_cargo(&["binary-dep-depinfo", "checksum-freshness"]) .with_stderr_data(str![[r#" ... [COMPILING] foo v0.1.0 ([ROOT]/foo) ... "#]]) .run(); assert_deps_contains( &p, &format!("target/{}/debug/.fingerprint/foo-*/dep-bin-foo", host), &[ (0, "src/main.rs"), (1, &format!("{}/debug/deps/libbar-*.rlib", host)), (1, &format!("{}/debug/deps/libregdep-*.rlib", host)), ], ); // Make sure it stays fresh. p.cargo("build -Zbinary-dep-depinfo -Zchecksum-freshness --target") .arg(&host) .masquerade_as_nightly_cargo(&["binary-dep-depinfo", "checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn modifying_and_moving() { let p = project() .file("src/main.rs", "mod a; fn main() {}") .file("src/a.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.root().move_into_the_past(); p.root().join("target").move_into_the_past(); p.change_file("src/a.rs", "#[allow(unused)]fn main() {}"); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): file size changed (0 != 28) for `src/a.rs` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); fs::rename(&p.root().join("src/a.rs"), &p.root().join("src/b.rs")).unwrap(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) error[E0583]: file not found for module `a` ... [ERROR] could not compile `foo` (bin "foo") due to 1 previous error "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn rebuild_sub_package_then_while_package() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" edition = "2015" [dependencies.a] path = "a" [dependencies.b] path = "b" "#, ) .file("src/lib.rs", "extern crate a; extern crate b;") .file( "a/Cargo.toml", r#" [package] name = "a" authors = [] version = "0.0.1" edition = "2015" [dependencies.b] path = "../b" "#, ) .file("a/src/lib.rs", "extern crate b;") .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/lib.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] b v0.0.1 ([ROOT]/foo/b) [COMPILING] a v0.0.1 ([ROOT]/foo/a) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file("b/src/lib.rs", "pub fn b() {}"); p.cargo("build -Zchecksum-freshness -pb -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [DIRTY] b v0.0.1 ([ROOT]/foo/b): file size changed (0 != 13) for `b/src/lib.rs` [COMPILING] b v0.0.1 ([ROOT]/foo/b) [RUNNING] `rustc --crate-name b [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file( "src/lib.rs", "extern crate a; extern crate b; pub fn toplevel() {}", ); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FRESH] b v0.0.1 ([ROOT]/foo/b) [DIRTY] a v0.0.1 ([ROOT]/foo/a): the dependency b was rebuilt ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] a v0.0.1 ([ROOT]/foo/a) [RUNNING] `rustc --crate-name a [..] [DIRTY] foo v0.0.1 ([ROOT]/foo): the dependency b was rebuilt ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] src/lib.rs [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn changing_lib_features_caches_targets() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" edition = "2015" [features] foo = [] "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness --features foo") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); /* Targets should be cached from the first build */ p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness --features foo") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn changing_profiles_caches_targets() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" edition = "2015" [profile.dev] panic = "abort" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("test -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "#]]) .run(); /* Targets should be cached from the first build */ p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("test -Zchecksum-freshness foo") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn changing_bin_paths_common_target_features_caches_targets() { // Make sure dep_cache crate is built once per feature let p = project() .no_manifest() .file( ".cargo/config.toml", r#" [build] target-dir = "./target" "#, ) .file( "dep_crate/Cargo.toml", r#" [package] name = "dep_crate" version = "0.0.1" edition = "2015" authors = [] [features] ftest = [] "#, ) .file( "dep_crate/src/lib.rs", r#" #[cfg(feature = "ftest")] pub fn yo() { println!("ftest on") } #[cfg(not(feature = "ftest"))] pub fn yo() { println!("ftest off") } "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [dependencies] dep_crate = {path = "../dep_crate", features = []} "#, ) .file("a/src/lib.rs", "") .file( "a/src/main.rs", r#" extern crate dep_crate; use dep_crate::yo; fn main() { yo(); } "#, ) .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.0.1" edition = "2015" authors = [] [dependencies] dep_crate = {path = "../dep_crate", features = ["ftest"]} "#, ) .file("b/src/lib.rs", "") .file( "b/src/main.rs", r#" extern crate dep_crate; use dep_crate::yo; fn main() { yo(); } "#, ) .build(); /* Build and rebuild a/. Ensure dep_crate only builds once */ p.cargo("run -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .cwd("a") .with_stdout_data(str![[r#" ftest off "#]]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] dep_crate v0.0.1 ([ROOT]/foo/dep_crate) [COMPILING] a v0.0.1 ([ROOT]/foo/a) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/./target/debug/a[EXE]` "#]]) .run(); p.cargo("clean -p a").cwd("a").run(); p.cargo("run -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .cwd("a") .with_stdout_data(str![[r#" ftest off "#]]) .with_stderr_data(str![[r#" [COMPILING] a v0.0.1 ([ROOT]/foo/a) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/./target/debug/a[EXE]` "#]]) .run(); /* Build and rebuild b/. Ensure dep_crate only builds once */ p.cargo("run -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .cwd("b") .with_stdout_data(str![[r#" ftest on "#]]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] dep_crate v0.0.1 ([ROOT]/foo/dep_crate) [COMPILING] b v0.0.1 ([ROOT]/foo/b) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/./target/debug/b[EXE]` "#]]) .run(); p.cargo("clean -p b").cwd("b").run(); p.cargo("run -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .cwd("b") .with_stdout_data(str![[r#" ftest on "#]]) .with_stderr_data(str![[r#" [COMPILING] b v0.0.1 ([ROOT]/foo/b) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/./target/debug/b[EXE]` "#]]) .run(); /* Build a/ package again. If we cache different feature dep builds correctly, * this should not cause a rebuild of dep_crate */ p.cargo("clean -p a").cwd("a").run(); p.cargo("run -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .cwd("a") .with_stdout_data(str![[r#" ftest off "#]]) .with_stderr_data(str![[r#" [COMPILING] a v0.0.1 ([ROOT]/foo/a) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/./target/debug/a[EXE]` "#]]) .run(); /* Build b/ package again. If we cache different feature dep builds correctly, * this should not cause a rebuild */ p.cargo("clean -p b").cwd("b").run(); p.cargo("run -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .cwd("b") .with_stdout_data(str![[r#" ftest on "#]]) .with_stderr_data(str![[r#" [COMPILING] b v0.0.1 ([ROOT]/foo/b) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/./target/debug/b[EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn changing_bin_features_caches_targets() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" edition = "2015" [features] foo = [] "#, ) .file( "src/main.rs", r#" fn main() { let msg = if cfg!(feature = "foo") { "feature on" } else { "feature off" }; println!("{}", msg); } "#, ) .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.rename_run("foo", "off1") .with_stdout_data(str![[r#" feature off "#]]) .run(); p.cargo("build -Zchecksum-freshness --features foo") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.rename_run("foo", "on1") .with_stdout_data(str![[r#" feature on "#]]) .run(); /* Targets should be cached from the first build */ let mut e = p.cargo("build -Zchecksum-freshness -v"); e.masquerade_as_nightly_cargo(&["checksum-freshness"]); // MSVC does not include hash in binary filename, so it gets recompiled. if cfg!(target_env = "msvc") { e.with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the list of features changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } else { e.with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } e.run(); p.rename_run("foo", "off2") .with_stdout_data(str![[r#" feature off "#]]) .run(); let mut e = p.cargo("build -Zchecksum-freshness --features foo -v"); e.masquerade_as_nightly_cargo(&["checksum-freshness"]); if cfg!(target_env = "msvc") { e.with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the list of features changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } else { e.with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } e.run(); p.rename_run("foo", "on2") .with_stdout_data(str![[r#" feature on "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn rebuild_tests_if_lib_changes() { let p = project() .file("src/lib.rs", "pub fn foo() {}") .file("tests/foo-test.rs", "extern crate foo;") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.cargo("test -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.change_file("src/lib.rs", ""); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.cargo("test -Zchecksum-freshness -v --test foo-test") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the dependency foo was rebuilt ([TIME_DIFF_AFTER_LAST_BUILD]) [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo_test [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/foo_test-[HASH][EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn no_rebuild_transitive_target_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a" } [dev-dependencies] b = { path = "b" } "#, ) .file("src/lib.rs", "") .file("tests/foo.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [target.foo.dependencies] c = { path = "../c" } "#, ) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.0.1" edition = "2015" authors = [] [dependencies] c = { path = "../c" } "#, ) .file("b/src/lib.rs", "") .file("c/Cargo.toml", &basic_manifest("c", "0.0.1")) .file("c/src/lib.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.cargo("test -Zchecksum-freshness --no-run") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [COMPILING] c v0.0.1 ([ROOT]/foo/c) [COMPILING] b v0.0.1 ([ROOT]/foo/b) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [EXECUTABLE] tests/foo.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn rerun_if_changed_in_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a" } "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "a/build.rs", r#" fn main() { println!("cargo::rerun-if-changed=build.rs"); } "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn same_build_dir_cached_packages() { let p = project() .no_manifest() .file( "a1/Cargo.toml", r#" [package] name = "a1" version = "0.0.1" edition = "2015" authors = [] [dependencies] b = { path = "../b" } "#, ) .file("a1/src/lib.rs", "") .file( "a2/Cargo.toml", r#" [package] name = "a2" version = "0.0.1" edition = "2015" authors = [] [dependencies] b = { path = "../b" } "#, ) .file("a2/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.0.1" edition = "2015" authors = [] [dependencies] c = { path = "../c" } "#, ) .file("b/src/lib.rs", "") .file( "c/Cargo.toml", r#" [package] name = "c" version = "0.0.1" edition = "2015" authors = [] [dependencies] d = { path = "../d" } "#, ) .file("c/src/lib.rs", "") .file("d/Cargo.toml", &basic_manifest("d", "0.0.1")) .file("d/src/lib.rs", "") .file( ".cargo/config.toml", r#" [build] target-dir = "./target" "#, ) .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .cwd("a1") .with_stderr_data(str![[r#" [LOCKING] 3 packages to latest compatible versions [COMPILING] d v0.0.1 ([ROOT]/foo/d) [COMPILING] c v0.0.1 ([ROOT]/foo/c) [COMPILING] b v0.0.1 ([ROOT]/foo/b) [COMPILING] a1 v0.0.1 ([ROOT]/foo/a1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .cwd("a2") .with_stderr_data(str![[r#" [LOCKING] 3 packages to latest compatible versions [COMPILING] a2 v0.0.1 ([ROOT]/foo/a2) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn no_rebuild_if_build_artifacts_move_backwards_in_time() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a" } "#, ) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/src/lib.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.root().move_into_the_past(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stdout_data(str![]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn rebuild_if_environment_changes() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" description = "old desc" version = "0.0.1" edition = "2015" authors = [] "#, ) .file( "src/main.rs", r#" fn main() { println!("{}", env!("CARGO_PKG_DESCRIPTION")); } "#, ) .build(); p.cargo("run -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stdout_data(str![[r#" old desc "#]]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); p.change_file( "Cargo.toml", r#" [package] name = "foo" description = "new desc" version = "0.0.1" edition = "2015" authors = [] "#, ); p.cargo("run -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stdout_data(str![[r#" new desc "#]]) .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the environment variable CARGO_PKG_DESCRIPTION changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn no_rebuild_when_rename_dir() { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [workspace] [dependencies] foo = { path = "foo" } "#, ) .file("src/_unused.rs", "") .file("build.rs", "fn main() {}") .file("foo/Cargo.toml", &basic_manifest("foo", "0.0.1")) .file("foo/src/lib.rs", "") .file("foo/build.rs", "fn main() {}") .build(); // make sure the most recently modified file is `src/lib.rs`, not // `Cargo.toml`, to expose a historical bug where we forgot to strip the // `Cargo.toml` path from looking for the package root. fs::write(p.root().join("src/lib.rs"), "").unwrap(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); let mut new = p.root(); new.pop(); new.push("bar"); fs::rename(p.root(), &new).unwrap(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .cwd(&new) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn unused_optional_dep() { Package::new("registry1", "0.1.0").publish(); Package::new("registry2", "0.1.0").publish(); Package::new("registry3", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "p" authors = [] version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } baz = { path = "baz" } registry1 = "*" "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.1" edition = "2015" authors = [] [dev-dependencies] registry2 = "*" "#, ) .file("bar/src/lib.rs", "") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.1" edition = "2015" authors = [] [dependencies] registry3 = { version = "*", optional = true } "#, ) .file("baz/src/lib.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn path_dev_dep_registry_updates() { Package::new("registry1", "0.1.0").publish(); Package::new("registry2", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "p" authors = [] version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.1" edition = "2015" authors = [] [dependencies] registry1 = "*" [dev-dependencies] baz = { path = "../baz"} "#, ) .file("bar/src/lib.rs", "") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.1" edition = "2015" authors = [] [dependencies] registry2 = "*" "#, ) .file("baz/src/lib.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn change_panic_mode() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ['bar', 'baz'] [profile.dev] panic = 'abort' "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1")) .file("bar/src/lib.rs", "") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.1" edition = "2015" authors = [] [lib] proc-macro = true [dependencies] bar = { path = '../bar' } "#, ) .file("baz/src/lib.rs", "extern crate bar;") .build(); p.cargo("build -Zchecksum-freshness -p bar") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.cargo("build -Zchecksum-freshness -p baz") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn dont_rebuild_based_on_plugins() { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.1" edition = "2015" [workspace] members = ['baz'] [dependencies] proc-macro-thing = { path = 'proc-macro-thing' } "#, ) .file("src/lib.rs", "") .file( "proc-macro-thing/Cargo.toml", r#" [package] name = "proc-macro-thing" version = "0.1.1" edition = "2015" [lib] proc-macro = true [dependencies] qux = { path = '../qux' } "#, ) .file("proc-macro-thing/src/lib.rs", "") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.1" edition = "2015" [dependencies] qux = { path = '../qux' } "#, ) .file("baz/src/main.rs", "fn main() {}") .file("qux/Cargo.toml", &basic_manifest("qux", "0.1.1")) .file("qux/src/lib.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.cargo("build -Zchecksum-freshness -p baz") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness -p bar") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn reuse_workspace_lib() { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.1" edition = "2015" [workspace] [dependencies] baz = { path = 'baz' } "#, ) .file("src/lib.rs", "") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.1")) .file("baz/src/lib.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.cargo("test -Zchecksum-freshness -p baz -v --no-run") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [COMPILING] baz v0.1.1 ([ROOT]/foo/baz) [RUNNING] `rustc --crate-name baz [..] [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] `[ROOT]/foo/target/debug/deps/baz-[HASH][EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn reuse_shared_build_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] shared = {path = "shared"} [workspace] members = ["shared", "bar"] "#, ) .file("src/main.rs", "fn main() {}") .file("shared/Cargo.toml", &basic_manifest("shared", "0.0.1")) .file("shared/src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" [build-dependencies] shared = { path = "../shared" } "#, ) .file("bar/src/lib.rs", "") .file("bar/build.rs", "fn main() {}") .build(); p.cargo("build -Zchecksum-freshness --workspace") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); // This should not recompile! p.cargo("build -Zchecksum-freshness -p foo -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FRESH] shared v0.0.1 ([ROOT]/foo/shared) [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn changing_rustflags_is_cached() { let p = project().file("src/lib.rs", "").build(); // This isn't ever cached, we always have to recompile p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("RUSTFLAGS", "-C linker=cc") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("RUSTFLAGS", "-C linker=cc") .with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn changing_rustc_extra_flags_is_cached() { let p = project().file("src/lib.rs", "").build(); // This isn't ever cached, we always have to recompile p.cargo("rustc -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("rustc -Zchecksum-freshness -v -- -C linker=cc") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("rustc -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("rustc -Zchecksum-freshness -v -- -C linker=cc") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn reuse_panic_build_dep_test() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [build-dependencies] bar = { path = "bar" } [dev-dependencies] bar = { path = "bar" } [profile.dev] panic = "abort" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); // Check that `bar` is not built twice. It is only needed once (without `panic`). p.cargo("test -Zchecksum-freshness --lib --no-run -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar [..] [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build [..] [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo [..] src/lib.rs [..]--test[..] [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn reuse_panic_pm() { // foo(panic) -> bar(panic) // somepm(nopanic) -> bar(nopanic) let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = { path = "bar" } somepm = { path = "somepm" } [profile.dev] panic = "abort" "#, ) .file("src/lib.rs", "extern crate bar;") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .file( "somepm/Cargo.toml", r#" [package] name = "somepm" version = "0.0.1" edition = "2015" [lib] proc-macro = true [dependencies] bar = { path = "../bar" } "#, ) .file("somepm/src/lib.rs", "extern crate bar;") .build(); // bar is built once without panic (for proc-macro) and once with (for the // normal dependency). p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data( str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar [..] -C panic=abort [..] [RUNNING] `rustc --crate-name bar [..] [COMPILING] somepm v0.0.1 ([ROOT]/foo/somepm) [RUNNING] `rustc --crate-name somepm [..] [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -C panic=abort [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn bust_patched_dep() { Package::new("registry1", "0.1.0").publish(); Package::new("registry2", "0.1.0") .dep("registry1", "0.1.0") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] registry2 = "0.1.0" [patch.crates-io] registry1 = { path = "reg1new" } "#, ) .file("src/lib.rs", "") .file("reg1new/Cargo.toml", &basic_manifest("registry1", "0.1.0")) .file("reg1new/src/lib.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.change_file("reg1new/src/lib.rs", "// modified"); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [DIRTY] registry1 v0.1.0 ([ROOT]/foo/reg1new): file size changed (0 != 11) for `reg1new/src/lib.rs` [COMPILING] registry1 v0.1.0 ([ROOT]/foo/reg1new) [RUNNING] `rustc --crate-name registry1 [..] [DIRTY] registry2 v0.1.0: the dependency registry1 was rebuilt [COMPILING] registry2 v0.1.0 [RUNNING] `rustc --crate-name registry2 [..] [DIRTY] foo v0.0.1 ([ROOT]/foo): the dependency registry2 was rebuilt [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FRESH] registry1 v0.1.0 ([ROOT]/foo/reg1new) [FRESH] registry2 v0.1.0 [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn rebuild_on_mid_build_file_modification() { let server = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = server.local_addr().unwrap(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["root", "proc_macro_dep"] "#, ) .file( "root/Cargo.toml", r#" [package] name = "root" version = "0.1.0" edition = "2015" authors = [] [dependencies] proc_macro_dep = { path = "../proc_macro_dep" } "#, ) .file( "root/src/lib.rs", r#" #[macro_use] extern crate proc_macro_dep; #[derive(Noop)] pub struct X; "#, ) .file( "proc_macro_dep/Cargo.toml", r#" [package] name = "proc_macro_dep" version = "0.1.0" edition = "2015" authors = [] [lib] proc-macro = true "#, ) .file( "proc_macro_dep/src/lib.rs", &format!( r#" extern crate proc_macro; use std::io::Read; use std::net::TcpStream; use proc_macro::TokenStream; #[proc_macro_derive(Noop)] pub fn noop(_input: TokenStream) -> TokenStream {{ let mut stream = TcpStream::connect("{}").unwrap(); let mut v = Vec::new(); stream.read_to_end(&mut v).unwrap(); "".parse().unwrap() }} "#, addr ), ) .build(); let root = p.root(); let t = thread::spawn(move || { let socket = server.accept().unwrap().0; let mut file = OpenOptions::new() .write(true) .append(true) .open(root.join("root/src/lib.rs")) .unwrap(); writeln!(file, "// modified").expect("Failed to append to root sources"); drop(file); drop(socket); drop(server.accept().unwrap()); }); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [COMPILING] proc_macro_dep v0.1.0 ([ROOT]/foo/proc_macro_dep) [COMPILING] root v0.1.0 ([ROOT]/foo/root) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FRESH] proc_macro_dep v0.1.0 ([ROOT]/foo/proc_macro_dep) [DIRTY] root v0.1.0 ([ROOT]/foo/root): file size changed (150 != 162) for `root/src/lib.rs` [COMPILING] root v0.1.0 ([ROOT]/foo/root) [RUNNING] `rustc --crate-name root [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); t.join().ok().unwrap(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn dirty_both_lib_and_test() { // This tests that all artifacts that depend on the results of a build // script will get rebuilt when the build script reruns, even for separate // commands. It does the following: // // 1. Project "foo" has a build script which will compile a small // staticlib to link against. Normally this would use the `cc` crate, // but here we just use rustc to avoid the `cc` dependency. // 2. Build the library. // 3. Build the unit test. The staticlib intentionally has a bad value. // 4. Rewrite the staticlib with the correct value. // 5. Build the library again. // 6. Build the unit test. This should recompile. let slib = |n| { format!( r#" #[no_mangle] pub extern "C" fn doit() -> i32 {{ return {}; }} "#, n ) }; let p = project() .file( "src/lib.rs", r#" extern "C" { fn doit() -> i32; } #[test] fn t1() { assert_eq!(unsafe { doit() }, 1, "doit assert failure"); } "#, ) .file( "build.rs", r#" use std::env; use std::path::PathBuf; use std::process::Command; fn main() { let rustc = env::var_os("RUSTC").unwrap(); let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); assert!( Command::new(rustc) .args(&[ "--crate-type=staticlib", "--out-dir", out_dir.to_str().unwrap(), "slib.rs" ]) .status() .unwrap() .success(), "slib build failed" ); println!("cargo::rustc-link-lib=slib"); println!("cargo::rustc-link-search={}", out_dir.display()); } "#, ) .file("slib.rs", &slib(2)) .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); // 2 != 1 p.cargo("test -Zchecksum-freshness --lib") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_status(101) .with_stdout_data("...\n[..]doit assert failure[..]\n...") .run(); // Fix the mistake. p.change_file("slib.rs", &slib(1)); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); // This should recompile with the new static lib, and the test should pass. p.cargo("test -Zchecksum-freshness --lib") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn script_fails_stay_dirty() { // Check if a script is aborted (such as hitting Ctrl-C) that it will re-run. // Steps: // 1. Build to establish fingerprints. // 2. Make a change that triggers the build script to re-run. Abort the // script while it is running. // 3. Run the build again and make sure it re-runs the script. let p = project() .file( "build.rs", r#" mod helper; fn main() { println!("cargo::rerun-if-changed=build.rs"); helper::doit(); } "#, ) .file("helper.rs", "pub fn doit() {}") .file("src/lib.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.change_file("helper.rs", r#"pub fn doit() {panic!("Crash!");}"#); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data("...\n[..]Crash![..]\n...") .with_status(101) .run(); // There was a bug where this second call would be "fresh". p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data("...\n[..]Crash![..]\n...") .with_status(101) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn edition_change_invalidates() { const MANIFEST: &str = r#" [package] name = "foo" version = "0.1.0" "#; let p = project() .file("Cargo.toml", MANIFEST) .file("src/lib.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.change_file("Cargo.toml", &format!("{}edition = \"2018\"", MANIFEST)); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file( "Cargo.toml", &format!( r#"{}edition = "2018" [lib] edition = "2015" "#, MANIFEST ), ); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FRESH] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert_eq!(p.glob("target/debug/deps/libfoo-*.rlib").count(), 1); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn rename_with_path_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = { path = 'a' } "#, ) .file("src/lib.rs", "extern crate a; pub fn foo() { a::foo(); }") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] [dependencies] b = { path = 'b' } "#, ) .file("a/src/lib.rs", "extern crate b; pub fn foo() { b::foo() }") .file( "a/b/Cargo.toml", r#" [package] name = "b" version = "0.5.0" edition = "2015" authors = [] "#, ) .file("a/b/src/lib.rs", "pub fn foo() { }"); let p = p.build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); // Now rename the root directory and rerun `cargo run`. Not only should we // not build anything but we also shouldn't crash. let mut new = p.root(); new.pop(); new.push("foo2"); fs::rename(p.root(), &new).unwrap(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .cwd(&new) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn move_target_directory_with_path_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = { path = "a" } "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] "#, ) .file("src/lib.rs", "extern crate a; pub use a::print_msg;") .file( "a/build.rs", r###" use std::env; use std::fs; use std::path::Path; fn main() { println!("cargo::rerun-if-changed=build.rs"); let out_dir = env::var("OUT_DIR").unwrap(); let dest_path = Path::new(&out_dir).join("hello.rs"); fs::write(&dest_path, r#" pub fn message() -> &'static str { "Hello, World!" } "#).unwrap(); } "###, ) .file( "a/src/lib.rs", r#" include!(concat!(env!("OUT_DIR"), "/hello.rs")); pub fn print_msg() { message(); } "#, ); let p = p.build(); let mut parent = p.root(); parent.pop(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); let new_target = p.root().join("target2"); fs::rename(p.root().join("target"), &new_target).unwrap(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("CARGO_TARGET_DIR", &new_target) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn rerun_if_changes() { let p = project() .file( "build.rs", r#" fn main() { println!("cargo::rerun-if-env-changed=FOO"); if std::env::var("FOO").is_ok() { println!("cargo::rerun-if-env-changed=BAR"); } } "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("FOO", "1") .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the env variable FOO changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("FOO", "1") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("FOO", "1") .env("BAR", "1") .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the env variable BAR changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("FOO", "1") .env("BAR", "1") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("BAR", "2") .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the env variable FOO changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("BAR", "2") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn channel_shares_filenames() { // Test that different "nightly" releases use the same output filename. // Create separate rustc binaries to emulate running different toolchains. let nightly1 = format!( "\ rustc 1.44.0-nightly (38114ff16 2020-03-21) binary: rustc commit-hash: 38114ff16e7856f98b2b4be7ab4cd29b38bed59a commit-date: 2020-03-21 host: {} release: 1.44.0-nightly LLVM version: 9.0 ", rustc_host() ); let nightly2 = format!( "\ rustc 1.44.0-nightly (a5b09d354 2020-03-31) binary: rustc commit-hash: a5b09d35473615e7142f5570f5c5fad0caf68bd2 commit-date: 2020-03-31 host: {} release: 1.44.0-nightly LLVM version: 9.0 ", rustc_host() ); let beta1 = format!( "\ rustc 1.43.0-beta.3 (4c587bbda 2020-03-25) binary: rustc commit-hash: 4c587bbda04ab55aaf56feab11dfdfe387a85d7a commit-date: 2020-03-25 host: {} release: 1.43.0-beta.3 LLVM version: 9.0 ", rustc_host() ); let beta2 = format!( "\ rustc 1.42.0-beta.5 (4e1c5f0e9 2020-02-28) binary: rustc commit-hash: 4e1c5f0e9769a588b91c977e3d81e140209ef3a2 commit-date: 2020-02-28 host: {} release: 1.42.0-beta.5 LLVM version: 9.0 ", rustc_host() ); let stable1 = format!( "\ rustc 1.42.0 (b8cedc004 2020-03-09) binary: rustc commit-hash: b8cedc00407a4c56a3bda1ed605c6fc166655447 commit-date: 2020-03-09 host: {} release: 1.42.0 LLVM version: 9.0 ", rustc_host() ); let stable2 = format!( "\ rustc 1.41.1 (f3e1a954d 2020-02-24) binary: rustc commit-hash: f3e1a954d2ead4e2fc197c7da7d71e6c61bad196 commit-date: 2020-02-24 host: {} release: 1.41.1 LLVM version: 9.0 ", rustc_host() ); let compiler = project() .at("compiler") .file("Cargo.toml", &basic_manifest("compiler", "0.1.0")) .file( "src/main.rs", r#" fn main() { if std::env::args_os().any(|a| a == "-vV") { print!("{}", env!("FUNKY_VERSION_TEST")); return; } let mut cmd = std::process::Command::new("rustc"); cmd.args(std::env::args_os().skip(1)); assert!(cmd.status().unwrap().success()); } "#, ) .build(); let makeit = |version, vv| { // Force a rebuild. compiler.target_debug_dir().join("deps").rm_rf(); compiler .cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("FUNKY_VERSION_TEST", vv) .run(); fs::rename(compiler.bin("compiler"), compiler.bin(version)).unwrap(); }; makeit("nightly1", nightly1); makeit("nightly2", nightly2); makeit("beta1", beta1); makeit("beta2", beta2); makeit("stable1", stable1); makeit("stable2", stable2); // Run `cargo check` with different rustc versions to observe its behavior. let p = project().file("src/lib.rs", "").build(); // Runs `cargo check` and returns the rmeta filename created. // Checks that the freshness matches the given value. let check = |version, fresh| -> String { let output = p .cargo("check -Zchecksum-freshness --message-format=json") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("RUSTC", compiler.bin(version)) .run(); // Collect the filenames generated. let mut artifacts: Vec<_> = std::str::from_utf8(&output.stdout) .unwrap() .lines() .filter_map(|line| { let value: serde_json::Value = serde_json::from_str(line).unwrap(); if value["reason"].as_str().unwrap() == "compiler-artifact" { assert_eq!(value["fresh"].as_bool().unwrap(), fresh); let filenames = value["filenames"].as_array().unwrap(); assert_eq!(filenames.len(), 1); Some(filenames[0].to_string()) } else { None } }) .collect(); // Should only generate one rmeta file. assert_eq!(artifacts.len(), 1); artifacts.pop().unwrap() }; let nightly1_name = check("nightly1", false); assert_eq!(check("nightly1", true), nightly1_name); assert_eq!(check("nightly2", false), nightly1_name); // same as before assert_eq!(check("nightly2", true), nightly1_name); // Should rebuild going back to nightly1. assert_eq!(check("nightly1", false), nightly1_name); let beta1_name = check("beta1", false); assert_ne!(beta1_name, nightly1_name); assert_eq!(check("beta1", true), beta1_name); assert_eq!(check("beta2", false), beta1_name); // same as before assert_eq!(check("beta2", true), beta1_name); // Should rebuild going back to beta1. assert_eq!(check("beta1", false), beta1_name); let stable1_name = check("stable1", false); assert_ne!(stable1_name, nightly1_name); assert_ne!(stable1_name, beta1_name); let stable2_name = check("stable2", false); assert_ne!(stable1_name, stable2_name); // Check everything is fresh. assert_eq!(check("stable1", true), stable1_name); assert_eq!(check("stable2", true), stable2_name); assert_eq!(check("beta1", true), beta1_name); assert_eq!(check("nightly1", true), nightly1_name); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn linking_interrupted() { // Interrupt during the linking phase shouldn't leave test executable as "fresh". // This is used to detect when linking starts, then to pause the linker so // that the test can kill cargo. let link_listener = TcpListener::bind("127.0.0.1:0").unwrap(); let link_addr = link_listener.local_addr().unwrap(); // This is used to detect when rustc exits. let rustc_listener = TcpListener::bind("127.0.0.1:0").unwrap(); let rustc_addr = rustc_listener.local_addr().unwrap(); // Create a linker that we can interrupt. let linker = project() .at("linker") .file("Cargo.toml", &basic_manifest("linker", "1.0.0")) .file( "src/main.rs", &r#" fn main() { // Figure out the output filename. let output = match std::env::args().find(|a| a.starts_with("/OUT:")) { Some(s) => s[5..].to_string(), None => { let mut args = std::env::args(); loop { if args.next().unwrap() == "-o" { break; } } args.next().unwrap() } }; std::fs::remove_file(&output).unwrap(); std::fs::write(&output, "").unwrap(); // Tell the test that we are ready to be interrupted. let mut socket = std::net::TcpStream::connect("__ADDR__").unwrap(); // Wait for the test to kill us. std::thread::sleep(std::time::Duration::new(60, 0)); } "# .replace("__ADDR__", &link_addr.to_string()), ) .build(); linker .cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); // Create a wrapper around rustc that will tell us when rustc is finished. let rustc = project() .at("rustc-waiter") .file("Cargo.toml", &basic_manifest("rustc-waiter", "1.0.0")) .file( "src/main.rs", &r#" fn main() { let mut conn = None; // Check for a normal build (not -vV or --print). if std::env::args().any(|arg| arg == "t1") { // Tell the test that rustc has started. conn = Some(std::net::TcpStream::connect("__ADDR__").unwrap()); } let status = std::process::Command::new("rustc") .args(std::env::args().skip(1)) .status() .expect("rustc to run"); std::process::exit(status.code().unwrap_or(1)); } "# .replace("__ADDR__", &rustc_addr.to_string()), ) .build(); rustc .cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); // Build it once so that the fingerprint gets saved to disk. let p = project() .file("src/lib.rs", "") .file("tests/t1.rs", "") .build(); p.cargo("test -Zchecksum-freshness --test t1 --no-run") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); // Make a change, start a build, then interrupt it. p.change_file("src/lib.rs", "// modified"); let linker_env = format!("CARGO_TARGET_{}_LINKER", rustc_host_env()); // NOTE: This assumes that the paths to the linker or rustc are not in the // fingerprint. But maybe they should be? let mut cmd = p .cargo("test -Zchecksum-freshness --test t1 --no-run") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env(&linker_env, linker.bin("linker")) .env("RUSTC", rustc.bin("rustc-waiter")) .build_command(); let mut child = cmd .stdout(Stdio::null()) .stderr(Stdio::null()) .env("__CARGO_TEST_SETSID_PLEASE_DONT_USE_ELSEWHERE", "1") .spawn() .unwrap(); // Wait for rustc to start. let mut rustc_conn = rustc_listener.accept().unwrap().0; // Wait for linking to start. drop(link_listener.accept().unwrap()); // Interrupt the child. death::ctrl_c(&mut child); assert!(!child.wait().unwrap().success()); // Wait for rustc to exit. If we don't wait, then the command below could // start while rustc is still being torn down. let mut buf = [0]; drop(rustc_conn.read_exact(&mut buf)); // Build again, shouldn't be fresh. p.cargo("test -Zchecksum-freshness --test t1 -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the config settings changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] [RUNNING] `rustc --crate-name t1 [..] [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/t1-[HASH][EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] #[cfg(all(target_arch = "x86_64", target_os = "windows", target_env = "msvc"))] fn lld_is_fresh() { // Check for bug when using lld linker that it remains fresh with dylib. let p = project() .file( ".cargo/config.toml", r#" [target.x86_64-pc-windows-msvc] linker = "rust-lld" rustflags = ["-C", "link-arg=-fuse-ld=lld"] "#, ) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] crate-type = ["dylib"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FRESH] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn env_in_code_causes_rebuild() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file( "src/main.rs", r#" fn main() { println!("{:?}", option_env!("FOO")); println!("{:?}", option_env!("FOO\nBAR")); } "#, ) .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env_remove("FOO") .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env_remove("FOO") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("FOO", "bar") .with_stderr_data(str![[r#" [DIRTY] foo v0.1.0 ([ROOT]/foo): the environment variable FOO changed [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("FOO", "bar") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("FOO", "baz") .with_stderr_data(str![[r#" [DIRTY] foo v0.1.0 ([ROOT]/foo): the environment variable FOO changed [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("FOO", "baz") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env_remove("FOO") .with_stderr_data(str![[r#" [DIRTY] foo v0.1.0 ([ROOT]/foo): the environment variable FOO changed [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env_remove("FOO") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let interesting = " #!$\nabc\r\\\t\u{8}\r\n"; p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("FOO", interesting) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("FOO", interesting) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("FOO\nBAR", interesting) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("FOO\nBAR", interesting) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn env_build_script_no_rebuild() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file( "build.rs", r#" fn main() { println!("cargo::rustc-env=FOO=bar"); } "#, ) .file( "src/main.rs", r#" fn main() { println!("{:?}", env!("FOO")); } "#, ) .build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn changing_linker() { // Changing linker should rebuild. let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("build -Zchecksum-freshness") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .run(); let linker_env = format!("CARGO_TARGET_{}_LINKER", rustc_host_env()); p.cargo("build -Zchecksum-freshness --verbose") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env(&linker_env, "nonexistent-linker") .with_status(101) .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the config settings changed [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -C linker=nonexistent-linker [..]` [ERROR] linker `nonexistent-linker` not found ... "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn verify_source_before_recompile() { Package::new("bar", "0.1.0") .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("vendor --respect-source-config").run(); p.change_file( ".cargo/config.toml", r#" [source.crates-io] replace-with = 'vendor' [source.vendor] directory = 'vendor' "#, ); // Sanity check: vendoring works correctly. p.cargo("check -Zchecksum-freshness --verbose") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [CHECKING] bar v0.1.0 [RUNNING] `rustc --crate-name bar [..] [ROOT]/foo/vendor/bar/src/lib.rs [..] [CHECKING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] src/lib.rs [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Now modify vendored crate. p.change_file( "vendor/bar/src/lib.rs", r#"compile_error!("You shall not pass!");"#, ); // Should ignore modified sources without any recompile. p.cargo("check -Zchecksum-freshness --verbose") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .with_stderr_data(str![[r#" [FRESH] bar v0.1.0 [FRESH] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Add a `RUSTFLAGS` to trigger a recompile. // // Cargo should refuse to build because of checksum verification failure. // Cargo shouldn't recompile dependency `bar`. p.cargo("check -Zchecksum-freshness --verbose") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("RUSTFLAGS", "-W warnings") .with_status(101) .with_stderr_data(str![[r#" [ERROR] the listed checksum of `[ROOT]/foo/vendor/bar/src/lib.rs` has changed: expected: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 actual: 66e843918c1d4ea8231af814f9f958958808249d4407de01114acb730ecd9bdf directory sources are not intended to be edited, if modifications are required then it is recommended that `[patch]` is used with a forked copy of the source "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn skip_checksum_check_in_selected_cargo_home_subdirs() { let p = project() .at("cargo_home/registry/foo") .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .build(); let project_root = p.root(); let cargo_home = project_root.parent().unwrap().parent().unwrap(); p.cargo("check -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("CARGO_HOME", &cargo_home) .with_stderr_data(str![[r#" [CHECKING] foo v0.5.0 ([ROOT]/cargo_home/registry/foo) [RUNNING] `rustc --crate-name foo [..] src/lib.rs [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file("src/lib.rs", "illegal syntax"); p.cargo("check -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("CARGO_HOME", &cargo_home) .with_stderr_data(str![[r#" [FRESH] foo v0.5.0 ([ROOT]/cargo_home/registry/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "requires -Zchecksum-hash-algorithm")] fn use_checksum_cache_in_cargo_home() { let p = project() .at("cargo_home/foo") .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .build(); let project_root = p.root(); let cargo_home = project_root.parent().unwrap(); p.cargo("check -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("CARGO_HOME", &cargo_home) .with_stderr_data(str![[r#" [CHECKING] foo v0.5.0 ([ROOT]/cargo_home/foo) [RUNNING] `rustc --crate-name foo [..] src/lib.rs [..] src/lib.rs [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file("src/lib.rs", "illegal syntax"); p.cargo("check -Zchecksum-freshness -v") .masquerade_as_nightly_cargo(&["checksum-freshness"]) .env("CARGO_HOME", &cargo_home) .with_status(101) .with_stderr_data(str![[r#" [DIRTY] foo v0.5.0 ([ROOT]/cargo_home/foo): file size changed (0 != 14) for `src/lib.rs` [CHECKING] foo v0.5.0 ([ROOT]/cargo_home/foo) [RUNNING] `rustc --crate-name foo [..] src/lib.rs [..] ... [ERROR] could not compile `foo` (lib) due to 1 previous error ... "#]]) .run(); } cargo-0.86.0/tests/testsuite/future_incompat_report.rs000064400000000000000000000332501046102023000213550ustar 00000000000000//! Tests for future-incompat-report messages //! //! Note that these tests use the -Zfuture-incompat-test for rustc. //! This causes rustc to treat *every* lint as future-incompatible. //! This is done because future-incompatible lints are inherently //! ephemeral, but we don't want to continually update these tests. //! So we pick some random lint that will likely always be the same //! over time. use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{basic_manifest, project, str, Project}; use super::config::write_config_toml; // An arbitrary lint (unused_variables) that triggers a lint. // We use a special flag to force it to generate a report. const FUTURE_EXAMPLE: &'static str = "fn main() { let x = 1; }"; // Some text that will be displayed when the lint fires. const FUTURE_OUTPUT: &'static str = "[..]unused variable[..]"; fn simple_project() -> Project { project() .file("Cargo.toml", &basic_manifest("foo", "0.0.0")) .file("src/main.rs", FUTURE_EXAMPLE) .build() } #[cargo_test( nightly, reason = "-Zfuture-incompat-test requires nightly (permanently)" )] fn output_on_stable() { let p = simple_project(); p.cargo("check") .env("RUSTFLAGS", "-Zfuture-incompat-test") .with_stderr_data(str![[r#" ... [WARNING] unused variable: `x` ... [NOTE] to see what the problems were, use the option `--future-incompat-report`, or run `cargo report future-incompatibilities --id 1` "#]]) .run(); } // This feature is stable, and should not be gated #[cargo_test] fn no_gate_future_incompat_report() { let p = simple_project(); p.cargo("check --future-incompat-report") .with_status(0) .run(); p.cargo("report future-incompatibilities --id foo") .with_stderr_data(str![[r#" [ERROR] no reports are currently available "#]]) .with_status(101) .run(); } #[cargo_test( nightly, reason = "-Zfuture-incompat-test requires nightly (permanently)" )] fn test_zero_future_incompat() { let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.0.0")) .file("src/main.rs", "fn main() {}") .build(); // No note if --future-incompat-report is not specified. p.cargo("check") .env("RUSTFLAGS", "-Zfuture-incompat-test") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check --future-incompat-report") .env("RUSTFLAGS", "-Zfuture-incompat-test") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [NOTE] 0 dependencies had future-incompatible warnings "#]]) .run(); } #[cargo_test( nightly, reason = "-Zfuture-incompat-test requires nightly (permanently)" )] fn test_single_crate() { let p = simple_project(); for command in &["build", "check", "rustc", "test"] { let check_has_future_compat = || { p.cargo(command) .env("RUSTFLAGS", "-Zfuture-incompat-test") .with_stderr_data("\ ... [WARNING] unused variable: `x` ... [WARNING] the following packages contain code that will be rejected by a future version of Rust: foo v0.0.0 ([ROOT]/foo) ... ") .with_stderr_does_not_contain("[..]incompatibility[..]") .run(); }; // Check that we show a message with no [future-incompat-report] config section write_config_toml(""); check_has_future_compat(); // Check that we show a message with `frequency = "always"` write_config_toml( "\ [future-incompat-report] frequency = 'always' ", ); check_has_future_compat(); // Check that we do not show a message with `frequency = "never"` write_config_toml( "\ [future-incompat-report] frequency = 'never' ", ); p.cargo(command) .env("RUSTFLAGS", "-Zfuture-incompat-test") .with_stderr_data( "\ [WARNING] unused variable: `x` ... ", ) .with_stderr_does_not_contain("[..]rejected[..]") .with_stderr_does_not_contain("[..]incompatibility[..]") .run(); // Check that passing `--future-incompat-report` overrides `frequency = 'never'` p.cargo(command).arg("--future-incompat-report") .env("RUSTFLAGS", "-Zfuture-incompat-test") .with_stderr_data("\ [WARNING] unused variable: `x` ... [WARNING] the following packages contain code that will be rejected by a future version of Rust: foo v0.0.0 ([ROOT]/foo) ... - foo@0.0.0 ... ") .run(); } } #[cargo_test( nightly, reason = "-Zfuture-incompat-test requires nightly (permanently)" )] fn test_multi_crate() { Package::new("first-dep", "0.0.1") .file("src/lib.rs", FUTURE_EXAMPLE) .publish(); Package::new("second-dep", "0.0.2") .file("src/lib.rs", FUTURE_EXAMPLE) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" [dependencies] first-dep = "*" second-dep = "*" "#, ) .file("src/lib.rs", "") .build(); for command in &["build", "check", "rustc", "test"] { p.cargo(command) .env("RUSTFLAGS", "-Zfuture-incompat-test") .with_stderr_does_not_contain(FUTURE_OUTPUT) .with_stderr_data("\ ... [WARNING] the following packages contain code that will be rejected by a future version of Rust: first-dep v0.0.1, second-dep v0.0.2 ... ") // Check that we don't have the 'triggers' message shown at the bottom of this loop, // and that we don't explain how to show a per-package report .with_stderr_does_not_contain("[..]triggers[..]") .with_stderr_does_not_contain("[..]--package[..]") .with_stderr_does_not_contain("[..]-p[..]") .run(); p.cargo(command).arg("--future-incompat-report") .env("RUSTFLAGS", "-Zfuture-incompat-test") .with_stderr_data("\ ... [WARNING] the following packages contain code that will be rejected by a future version of Rust: first-dep v0.0.1, second-dep v0.0.2 ... - first-dep@0.0.1 ... - second-dep@0.0.2 ... ") .run(); p.cargo("report future-incompatibilities") .arg("--package") .arg("first-dep@0.0.1") .with_stdout_data( "\ ... The package `first-dep v0.0.1` currently triggers the following future incompatibility lints: > [WARNING] unused variable: `x` ... ", ) .with_stdout_does_not_contain("[..]second-dep-0.0.2/src[..]") .run(); p.cargo("report future-incompatibilities") .arg("--package") .arg("second-dep@0.0.2") .with_stdout_data( "\ ... The package `second-dep v0.0.2` currently triggers the following future incompatibility lints: > [WARNING] unused variable: `x` ... ", ) .with_stdout_does_not_contain("[..]first-dep-0.0.1/src[..]") .run(); } // Test that passing the correct id via '--id' doesn't generate a warning message let output = p .cargo("check") .env("RUSTFLAGS", "-Zfuture-incompat-test") .run(); // Extract the 'id' from the stdout. We are looking // for the id in a line of the form "run `cargo report future-incompatibilities --id yZ7S`" // which is generated by Cargo to tell the user what command to run // This is just to test that passing the id suppresses the warning mesasge. Any users needing // access to the report from a shell script should use the `--future-incompat-report` flag let stderr = std::str::from_utf8(&output.stderr).unwrap(); // Find '--id ' in the output let mut iter = stderr.split(' '); iter.find(|w| *w == "--id").unwrap(); let id = iter .next() .unwrap_or_else(|| panic!("Unexpected output:\n{}", stderr)); // Strip off the trailing '`' included in the output let id: String = id.chars().take_while(|c| *c != '`').collect(); p.cargo(&format!("report future-incompatibilities --id {}", id)) .with_stdout_data(str![[r#" ... The package `first-dep v0.0.1` currently triggers the following future incompatibility lints: ... The package `second-dep v0.0.2` currently triggers the following future incompatibility lints: ... "#]]) .run(); // Test without --id, and also the full output of the report. let output = p.cargo("report future-incompat").run(); let output = std::str::from_utf8(&output.stdout).unwrap(); assert!(output.starts_with("The following warnings were discovered")); let mut lines = output .lines() // Skip the beginning of the per-package information. .skip_while(|line| !line.starts_with("The package")); for expected in &["first-dep v0.0.1", "second-dep v0.0.2"] { assert_eq!( &format!( "The package `{}` currently triggers the following future incompatibility lints:", expected ), lines.next().unwrap(), "Bad output:\n{}", output ); let mut count = 0; while let Some(line) = lines.next() { if line.is_empty() { break; } count += 1; } assert!(count > 0); } assert_eq!(lines.next(), None); } #[cargo_test( nightly, reason = "-Zfuture-incompat-test requires nightly (permanently)" )] fn color() { let p = simple_project(); p.cargo("check") .env("RUSTFLAGS", "-Zfuture-incompat-test") .masquerade_as_nightly_cargo(&["future-incompat-test"]) .run(); p.cargo("report future-incompatibilities") .with_stdout_does_not_contain("[..]\x1b[[..]") .run(); p.cargo("report future-incompatibilities") .env("CARGO_TERM_COLOR", "always") .with_stdout_contains("[..]\x1b[[..]") .run(); } #[cargo_test( nightly, reason = "-Zfuture-incompat-test requires nightly (permanently)" )] fn bad_ids() { let p = simple_project(); p.cargo("report future-incompatibilities --id 1") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no reports are currently available "#]]) .run(); p.cargo("check") .env("RUSTFLAGS", "-Zfuture-incompat-test") .masquerade_as_nightly_cargo(&["future-incompat-test"]) .run(); p.cargo("report future-incompatibilities --id foo") .with_status(1) .with_stderr_data(str![ "[ERROR] Invalid value: could not parse `foo` as a number" ]) .run(); p.cargo("report future-incompatibilities --id 7") .with_status(101) .with_stderr_data(str![[r#" [ERROR] could not find report with ID 7 Available IDs are: 1 "#]]) .run(); } #[cargo_test( nightly, reason = "-Zfuture-incompat-test requires nightly (permanently)" )] fn suggestions_for_updates() { Package::new("with_updates", "1.0.0") .file("src/lib.rs", FUTURE_EXAMPLE) .publish(); Package::new("big_update", "1.0.0") .file("src/lib.rs", FUTURE_EXAMPLE) .publish(); Package::new("without_updates", "1.0.0") .file("src/lib.rs", FUTURE_EXAMPLE) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] with_updates = "1" big_update = "1" without_updates = "1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); Package::new("with_updates", "1.0.1") .file("src/lib.rs", "") .publish(); Package::new("with_updates", "1.0.2") .file("src/lib.rs", "") .publish(); Package::new("with_updates", "3.0.1") .file("src/lib.rs", "") .publish(); Package::new("big_update", "2.0.0") .file("src/lib.rs", "") .publish(); // This is a hack to force cargo to update the index. Cargo can't do this // automatically because doing a network update on every build would be a // bad idea. Under normal circumstances, we'll hope the user has done // something else along the way to trigger an update (building some other // project or something). This could use some more consideration of how to // handle this better (maybe only trigger an update if it hasn't updated // in a long while?). p.cargo("update without_updates").run(); p.cargo("check --future-incompat-report") .masquerade_as_nightly_cargo(&["future-incompat-test"]) .env("RUSTFLAGS", "-Zfuture-incompat-test") .with_stderr_data(str![[r#" ... - Some affected dependencies have newer versions available. You may want to consider updating them to a newer version to see if the issue has been fixed. big_update v1.0.0 has the following newer versions available: 2.0.0 with_updates v1.0.0 has the following newer versions available: 1.0.1, 1.0.2, 3.0.1 ... "#]]) .run(); p.cargo("report future-incompatibilities") .with_stdout_data(str![[r#" ... - Some affected dependencies have newer versions available. You may want to consider updating them to a newer version to see if the issue has been fixed. big_update v1.0.0 has the following newer versions available: 2.0.0 with_updates v1.0.0 has the following newer versions available: 1.0.1, 1.0.2, 3.0.1 ... "#]]) .run(); } cargo-0.86.0/tests/testsuite/generate_lockfile.rs000064400000000000000000000161511046102023000202210ustar 00000000000000//! Tests for the `cargo generate-lockfile` command. use std::fs; use cargo_test_support::prelude::*; use cargo_test_support::registry::{Package, RegistryBuilder}; use cargo_test_support::{basic_manifest, paths, project, str, ProjectBuilder}; #[cargo_test] fn adding_and_removing_packages() { let p = project() .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); let lock1 = p.read_lockfile(); // add a dep p.change_file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" [dependencies.bar] path = "bar" "#, ); p.cargo("generate-lockfile").run(); let lock2 = p.read_lockfile(); assert_ne!(lock1, lock2); // change the dep p.change_file("bar/Cargo.toml", &basic_manifest("bar", "0.0.2")); p.cargo("generate-lockfile").run(); let lock3 = p.read_lockfile(); assert_ne!(lock1, lock3); assert_ne!(lock2, lock3); // remove the dep println!("lock4"); p.change_file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" "#, ); p.cargo("generate-lockfile").run(); let lock4 = p.read_lockfile(); assert_eq!(lock1, lock4); } #[cargo_test] fn no_index_update_sparse() { let _registry = RegistryBuilder::new().http_index().build(); no_index_update( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version "#]], str![[r#" [LOCKING] 1 package to latest compatible version "#]], ); } #[cargo_test] fn no_index_update_git() { no_index_update( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version "#]], str![[r#" [LOCKING] 1 package to latest compatible version "#]], ); } fn no_index_update(expected: impl IntoData, expected_unstable_option: impl IntoData) { Package::new("serde", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" [dependencies] serde = "1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("generate-lockfile") .with_stderr_data(expected) .run(); p.cargo("generate-lockfile -Zno-index-update") .masquerade_as_nightly_cargo(&["no-index-update"]) .with_stdout_data("") .with_stderr_data(expected_unstable_option) .run(); } #[cargo_test] fn preserve_metadata() { let p = project() .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); let metadata = r#" [metadata] bar = "baz" foo = "bar" "#; let lock = p.read_lockfile(); let data = lock + metadata; p.change_file("Cargo.lock", &data); // Build and make sure the metadata is still there p.cargo("build").run(); let lock = p.read_lockfile(); assert!(lock.contains(metadata.trim()), "{}", lock); // Update and make sure the metadata is still there p.cargo("update").run(); let lock = p.read_lockfile(); assert!(lock.contains(metadata.trim()), "{}", lock); } #[cargo_test] fn preserve_line_endings_issue_2076() { let p = project() .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); let lockfile = p.root().join("Cargo.lock"); p.cargo("generate-lockfile").run(); assert!(lockfile.is_file()); p.cargo("generate-lockfile").run(); let lock0 = p.read_lockfile(); assert!(lock0.starts_with("# This file is automatically @generated by Cargo.\n# It is not intended for manual editing.\n")); let lock1 = lock0.replace("\n", "\r\n"); p.change_file("Cargo.lock", &lock1); p.cargo("generate-lockfile").run(); let lock2 = p.read_lockfile(); assert!(lock2.starts_with("# This file is automatically @generated by Cargo.\r\n# It is not intended for manual editing.\r\n")); assert_eq!(lock1, lock2); } #[cargo_test] fn cargo_update_generate_lockfile() { let p = project().file("src/main.rs", "fn main() {}").build(); let lockfile = p.root().join("Cargo.lock"); assert!(!lockfile.is_file()); p.cargo("update").with_stderr_data("").run(); assert!(lockfile.is_file()); fs::remove_file(p.root().join("Cargo.lock")).unwrap(); assert!(!lockfile.is_file()); p.cargo("update").with_stderr_data("").run(); assert!(lockfile.is_file()); } #[cargo_test] fn duplicate_entries_in_lockfile() { let _a = ProjectBuilder::new(paths::root().join("a")) .file( "Cargo.toml", r#" [package] name = "a" authors = [] version = "0.0.1" [dependencies] common = {path="common"} "#, ) .file("src/lib.rs", "") .build(); let common_toml = &basic_manifest("common", "0.0.1"); let _common_in_a = ProjectBuilder::new(paths::root().join("a/common")) .file("Cargo.toml", common_toml) .file("src/lib.rs", "") .build(); let b = ProjectBuilder::new(paths::root().join("b")) .file( "Cargo.toml", r#" [package] name = "b" authors = [] version = "0.0.1" edition = "2015" [dependencies] common = {path="common"} a = {path="../a"} "#, ) .file("src/lib.rs", "") .build(); let _common_in_b = ProjectBuilder::new(paths::root().join("b/common")) .file("Cargo.toml", common_toml) .file("src/lib.rs", "") .build(); // should fail due to a duplicate package `common` in the lock file b.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package collision in the lockfile: packages common v0.0.1 ([ROOT]/a/common) and common v0.0.1 ([ROOT]/b/common) are different, but only one can be written to lockfile unambiguously "#]]) .run(); } #[cargo_test] fn generate_lockfile_holds_lock_and_offline() { Package::new("syn", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" [dependencies] syn = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version "#]]) .run(); p.cargo("generate-lockfile --offline") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version "#]]) .run(); } cargo-0.86.0/tests/testsuite/git.rs000064400000000000000000003440711046102023000153470ustar 00000000000000//! Tests for git support. use std::fs; use std::io::prelude::*; use std::net::{TcpListener, TcpStream}; use std::path::Path; use std::str; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::thread; use cargo_test_support::git::{add_submodule, cargo_uses_gitoxide}; use cargo_test_support::paths; use cargo_test_support::prelude::IntoData; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{basic_lib_manifest, basic_manifest, git, main_file, project}; use cargo_test_support::{sleep_ms, str, t, Project}; #[cargo_test] fn cargo_compile_simple_git_dep() { let project = project(); let git_project = git::new("dep1", |project| { project .file("Cargo.toml", &basic_lib_manifest("dep1")) .file( "src/dep1.rs", r#" pub fn hello() -> &'static str { "hello world" } "#, ) }); let project = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.dep1] git = '{}' "#, git_project.url() ), ) .file( "src/main.rs", &main_file(r#""{}", dep1::hello()"#, &["dep1"]), ) .build(); project .cargo("build") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/dep1` [LOCKING] 1 package to latest compatible version [COMPILING] dep1 v0.5.0 ([ROOTURL]/dep1#[..]) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(project.bin("foo").is_file()); project .process(&project.bin("foo")) .with_stdout_data(str![[r#" hello world "#]]) .run(); } #[cargo_test] fn cargo_compile_git_dep_branch() { let project = project(); let git_project = git::new("dep1", |project| { project .file("Cargo.toml", &basic_lib_manifest("dep1")) .file( "src/dep1.rs", r#" pub fn hello() -> &'static str { "hello world" } "#, ) }); // Make a new branch based on the current HEAD commit let repo = git2::Repository::open(&git_project.root()).unwrap(); let head = repo.head().unwrap().target().unwrap(); let head = repo.find_commit(head).unwrap(); repo.branch("branchy", &head, true).unwrap(); let project = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.dep1] git = '{}' branch = "branchy" "#, git_project.url() ), ) .file( "src/main.rs", &main_file(r#""{}", dep1::hello()"#, &["dep1"]), ) .build(); project .cargo("build") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/dep1` [LOCKING] 1 package to latest compatible version [COMPILING] dep1 v0.5.0 ([ROOTURL]/dep1?branch=branchy#[..]) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(project.bin("foo").is_file()); project .process(&project.bin("foo")) .with_stdout_data(str![[r#" hello world "#]]) .run(); } #[cargo_test] fn cargo_compile_git_dep_tag() { let project = project(); let git_project = git::new("dep1", |project| { project .file("Cargo.toml", &basic_lib_manifest("dep1")) .file( "src/dep1.rs", r#" pub fn hello() -> &'static str { "hello world" } "#, ) }); // Make a tag corresponding to the current HEAD let repo = git2::Repository::open(&git_project.root()).unwrap(); let head = repo.head().unwrap().target().unwrap(); repo.tag( "v0.1.0", &repo.find_object(head, None).unwrap(), &repo.signature().unwrap(), "make a new tag", false, ) .unwrap(); let project = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.dep1] git = '{}' tag = "v0.1.0" "#, git_project.url() ), ) .file( "src/main.rs", &main_file(r#""{}", dep1::hello()"#, &["dep1"]), ) .build(); project .cargo("build") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/dep1` [LOCKING] 1 package to latest compatible version [COMPILING] dep1 v0.5.0 ([ROOTURL]/dep1?tag=v0.1.0#[..]) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(project.bin("foo").is_file()); project .process(&project.bin("foo")) .with_stdout_data(str![[r#" hello world "#]]) .run(); project.cargo("build").run(); } #[cargo_test] fn cargo_compile_git_dep_pull_request() { let project = project(); let git_project = git::new("dep1", |project| { project .file("Cargo.toml", &basic_lib_manifest("dep1")) .file( "src/dep1.rs", r#" pub fn hello() -> &'static str { "hello world" } "#, ) }); // Make a reference in GitHub's pull request ref naming convention. let repo = git2::Repository::open(&git_project.root()).unwrap(); let oid = repo.refname_to_id("HEAD").unwrap(); let force = false; let log_message = "open pull request"; repo.reference("refs/pull/330/head", oid, force, log_message) .unwrap(); let project = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.0" edition = "2015" [dependencies] dep1 = {{ git = "{}", rev = "refs/pull/330/head" }} "#, git_project.url() ), ) .file( "src/main.rs", &main_file(r#""{}", dep1::hello()"#, &["dep1"]), ) .build(); project .cargo("build") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/dep1` [LOCKING] 1 package to latest compatible version [COMPILING] dep1 v0.5.0 ([ROOTURL]/dep1?rev=refs%2Fpull%2F330%2Fhead#[..]) [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(project.bin("foo").is_file()); } #[cargo_test] fn cargo_compile_with_nested_paths() { let git_project = git::new("dep1", |project| { project .file( "Cargo.toml", r#" [package] name = "dep1" version = "0.5.0" edition = "2015" authors = ["carlhuda@example.com"] [dependencies.dep2] version = "0.5.0" path = "vendor/dep2" [lib] name = "dep1" "#, ) .file( "src/dep1.rs", r#" extern crate dep2; pub fn hello() -> &'static str { dep2::hello() } "#, ) .file("vendor/dep2/Cargo.toml", &basic_lib_manifest("dep2")) .file( "vendor/dep2/src/dep2.rs", r#" pub fn hello() -> &'static str { "hello world" } "#, ) }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.dep1] version = "0.5.0" git = '{}' [[bin]] name = "foo" "#, git_project.url() ), ) .file( "src/foo.rs", &main_file(r#""{}", dep1::hello()"#, &["dep1"]), ) .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" hello world "#]]) .run(); } #[cargo_test] fn cargo_compile_with_malformed_nested_paths() { let git_project = git::new("dep1", |project| { project .file("Cargo.toml", &basic_lib_manifest("dep1")) .file( "src/dep1.rs", r#" pub fn hello() -> &'static str { "hello world" } "#, ) .file("vendor/dep2/Cargo.toml", "!INVALID!") .file( "vendor/dep3/Cargo.toml", r#" [package] name = "dep3" version = "0.5.0" edition = "2015" [dependencies] subdep1 = { path = "../require-extra-build-step" } "#, ) .file("vendor/dep3/src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.dep1] version = "0.5.0" git = '{}' [[bin]] name = "foo" "#, git_project.url() ), ) .file( "src/foo.rs", &main_file(r#""{}", dep1::hello()"#, &["dep1"]), ) .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" hello world "#]]) .run(); } #[cargo_test] fn cargo_compile_with_meta_package() { let git_project = git::new("meta-dep", |project| { project .file("dep1/Cargo.toml", &basic_lib_manifest("dep1")) .file( "dep1/src/dep1.rs", r#" pub fn hello() -> &'static str { "this is dep1" } "#, ) .file("dep2/Cargo.toml", &basic_lib_manifest("dep2")) .file( "dep2/src/dep2.rs", r#" pub fn hello() -> &'static str { "this is dep2" } "#, ) }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.dep1] version = "0.5.0" git = '{}' [dependencies.dep2] version = "0.5.0" git = '{}' [[bin]] name = "foo" "#, git_project.url(), git_project.url() ), ) .file( "src/foo.rs", &main_file( r#""{} {}", dep1::hello(), dep2::hello()"#, &["dep1", "dep2"], ), ) .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" this is dep1 this is dep2 "#]]) .run(); } #[cargo_test] fn cargo_compile_with_short_ssh_git() { let url = "git@github.com:a/dep"; let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.dep] git = "{}" [[bin]] name = "foo" "#, url ), ) .file( "src/foo.rs", &main_file(r#""{}", dep1::hello()"#, &["dep1"]), ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(&format!( "\ [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: invalid url `{}`: relative URL without a base ", url )) .run(); } #[cargo_test] fn recompilation() { let git_project = git::new("bar", |project| { project .file("Cargo.toml", &basic_lib_manifest("bar")) .file("src/bar.rs", "pub fn bar() {}") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] version = "0.5.0" git = '{}' "#, git_project.url() ), ) .file("src/main.rs", &main_file(r#""{:?}", bar::bar()"#, &["bar"])) .build(); // First time around we should compile both foo and bar p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.5.0 ([ROOTURL]/bar#[..]) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Don't recompile the second time p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Modify a file manually, shouldn't trigger a recompile git_project.change_file("src/bar.rs", r#"pub fn bar() { println!("hello!"); }"#); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("update") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 0 packages to latest compatible versions "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Commit the changes and make sure we don't trigger a recompile because the // lock file says not to change let repo = git2::Repository::open(&git_project.root()).unwrap(); git::add(&repo); git::commit(&repo); println!("compile after commit"); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.root().move_into_the_past(); // Update the dependency and carry on! p.cargo("update") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 1 package to latest compatible version [UPDATING] bar v0.5.0 ([ROOTURL]/bar#[..]) -> #[..] "#]]) .run(); println!("going for the last compile"); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] bar v0.5.0 ([ROOTURL]/bar#[..]) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Make sure clean only cleans one dep p.cargo("clean -p foo") .with_stderr_data(str![[r#" [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn update_with_shared_deps() { let git_project = git::new("bar", |project| { project .file("Cargo.toml", &basic_lib_manifest("bar")) .file("src/bar.rs", "pub fn bar() {}") }); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.dep1] path = "dep1" [dependencies.dep2] path = "dep2" "#, ) .file( "src/main.rs", r#" #[allow(unused_extern_crates)] extern crate dep1; #[allow(unused_extern_crates)] extern crate dep2; fn main() {} "#, ) .file( "dep1/Cargo.toml", &format!( r#" [package] name = "dep1" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] version = "0.5.0" git = '{}' "#, git_project.url() ), ) .file("dep1/src/lib.rs", "") .file( "dep2/Cargo.toml", &format!( r#" [package] name = "dep2" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] version = "0.5.0" git = '{}' "#, git_project.url() ), ) .file("dep2/src/lib.rs", "") .build(); // First time around we should compile both foo and bar p.cargo("check") .with_stderr_data( str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 3 packages to latest compatible versions [CHECKING] bar v0.5.0 ([ROOTURL]/bar#[..]) [CHECKING] dep1 v0.5.0 ([ROOT]/foo/dep1) [CHECKING] dep2 v0.5.0 ([ROOT]/foo/dep2) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); // Modify a file manually, and commit it git_project.change_file("src/bar.rs", r#"pub fn bar() { println!("hello!"); }"#); let repo = git2::Repository::open(&git_project.root()).unwrap(); let old_head = repo.head().unwrap().target().unwrap(); git::add(&repo); git::commit(&repo); sleep_ms(1000); // By default, not transitive updates println!("dep1 update"); p.cargo("update dep1") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 1 package to latest compatible version [UPDATING] bar v0.5.0 ([ROOTURL]/bar#[..]) -> #[..] "#]]) .run(); // Don't do anything bad on a weird --precise argument println!("bar bad precise update"); p.cargo("update bar --precise 0.1.2") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [ERROR] Unable to update [ROOTURL]/bar#0.1.2 Caused by: revspec '0.1.2' not found; class=Reference (4); code=NotFound (-3) "#]]) .run(); // Specifying a precise rev to the old rev shouldn't actually update // anything because we already have the rev in the db. println!("bar precise update"); p.cargo("update bar --precise") .arg(&old_head.to_string()) .with_stderr_data(str![[r#" [UPDATING] bar v0.5.0 ([ROOTURL]/bar#[..]) -> #[..] "#]]) .run(); // Updating recursively should, however, update the repo. println!("dep1 recursive update"); p.cargo("update dep1 --recursive") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 1 package to latest compatible version [UPDATING] bar v0.5.0 ([ROOTURL]/bar#[..]) -> #[..] "#]]) .run(); // Make sure we still only compile one version of the git repo println!("build"); p.cargo("check") .with_stderr_data( str![[r#" [CHECKING] bar v0.5.0 ([ROOTURL]/bar#[..]) [CHECKING] dep1 v0.5.0 ([ROOT]/foo/dep1) [CHECKING] dep2 v0.5.0 ([ROOT]/foo/dep2) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); // We should be able to update transitive deps p.cargo("update bar") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 0 packages to latest compatible versions "#]]) .run(); } #[cargo_test] fn dep_with_submodule() { let project = project(); let git_project = git::new("dep1", |project| { project.file("Cargo.toml", &basic_manifest("dep1", "0.5.0")) }); let git_project2 = git::new("dep2", |project| project.file("lib.rs", "pub fn dep() {}")); let repo = git2::Repository::open(&git_project.root()).unwrap(); let url = git_project2.root().to_url().to_string(); git::add_submodule(&repo, &url, Path::new("src")); git::commit(&repo); let project = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.dep1] git = '{}' "#, git_project.url() ), ) .file( "src/lib.rs", "extern crate dep1; pub fn foo() { dep1::dep() }", ) .build(); project .cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/dep1` [UPDATING] git submodule `[ROOTURL]/dep2` [LOCKING] 1 package to latest compatible version [CHECKING] dep1 v0.5.0 ([ROOTURL]/dep1#[..]) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn dep_with_relative_submodule() { let foo = project(); let base = git::new("base", |project| { project .file( "Cargo.toml", r#" [package] name = "base" version = "0.5.0" edition = "2015" [dependencies] deployment.path = "deployment" "#, ) .file( "src/lib.rs", r#" pub fn dep() { deployment::deployment_func(); } "#, ) }); let _deployment = git::new("deployment", |project| { project .file("src/lib.rs", "pub fn deployment_func() {}") .file("Cargo.toml", &basic_lib_manifest("deployment")) }); let base_repo = git2::Repository::open(&base.root()).unwrap(); git::add_submodule(&base_repo, "../deployment", Path::new("deployment")); git::commit(&base_repo); let project = foo .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" [dependencies.base] git = '{}' "#, base.url() ), ) .file("src/lib.rs", "pub fn foo() { }") .build(); project .cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/base` [UPDATING] git submodule `[ROOTURL]/deployment` [LOCKING] 2 packages to latest compatible versions [CHECKING] deployment v0.5.0 ([ROOTURL]/base#[..]) [CHECKING] base v0.5.0 ([ROOTURL]/base#[..]) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn dep_with_bad_submodule() { let project = project(); let git_project = git::new("dep1", |project| { project.file("Cargo.toml", &basic_manifest("dep1", "0.5.0")) }); let git_project2 = git::new("dep2", |project| project.file("lib.rs", "pub fn dep() {}")); let repo = git2::Repository::open(&git_project.root()).unwrap(); let url = git_project2.root().to_url().to_string(); git::add_submodule(&repo, &url, Path::new("src")); git::commit(&repo); // now amend the first commit on git_project2 to make submodule ref point to not-found // commit let repo = git2::Repository::open(&git_project2.root()).unwrap(); let original_submodule_ref = repo.refname_to_id("refs/heads/master").unwrap(); let commit = repo.find_commit(original_submodule_ref).unwrap(); commit .amend( Some("refs/heads/master"), None, None, None, Some("something something"), None, ) .unwrap(); let p = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.dep1] git = '{}' "#, git_project.url() ), ) .file( "src/lib.rs", "extern crate dep1; pub fn foo() { dep1::dep() }", ) .build(); let expected = str![[r#" [UPDATING] git repository `[ROOTURL]/dep1` [UPDATING] git submodule `[ROOTURL]/dep2` [ERROR] failed to get `dep1` as a dependency of package `foo v0.5.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `dep1` Caused by: Unable to update [ROOTURL]/dep1 Caused by: failed to update submodule `src` Caused by: object not found - no match for id ([..]); class=Odb (9); code=NotFound (-3) "#]]; p.cargo("check") .with_stderr_data(expected) .with_status(101) .run(); } #[cargo_test] fn dep_with_skipped_submodule() { // Ensure we skip dependency submodules if their update strategy is `none`. let qux = git::new("qux", |project| { project.no_manifest().file("README", "skip me") }); let bar = git::new("bar", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.0.0")) .file("src/lib.rs", "") }); // `qux` is a submodule of `bar`, but we don't want to update it. let repo = git2::Repository::open(&bar.root()).unwrap(); git::add_submodule(&repo, qux.url().as_str(), Path::new("qux")); let mut conf = git2::Config::open(&bar.root().join(".gitmodules")).unwrap(); conf.set_str("submodule.qux.update", "none").unwrap(); git::add(&repo); git::commit(&repo); let foo = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies.bar] git = "{}" "#, bar.url() ), ) .file("src/main.rs", "fn main() {}") .build(); foo.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [SKIPPING] git submodule `[ROOTURL]/qux` due to update strategy in .gitmodules [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.0.0 ([ROOTURL]/bar#[..]) [CHECKING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn ambiguous_published_deps() { let project = project(); let git_project = git::new("dep", |project| { project .file( "duplicate1/Cargo.toml", &format!( r#" [package] name = "duplicate" version = "0.5.0" edition = "2015" publish = true "# ), ) .file("duplicate1/src/lib.rs", "") .file( "duplicate2/Cargo.toml", &format!( r#" [package] name = "duplicate" version = "0.5.0" edition = "2015" publish = true "# ), ) .file("duplicate2/src/lib.rs", "") }); let p = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.duplicate] git = '{}' "#, git_project.url() ), ) .file("src/main.rs", "fn main() { }") .build(); p.cargo("build").run(); p.cargo("run") .with_stderr_data(str![[r#" [WARNING] skipping duplicate package `duplicate v0.5.0 ([ROOTURL]/dep#[..])`: [ROOT]/home/.cargo/git/checkouts/dep-[HASH]/[..]/duplicate2/Cargo.toml in favor of [ROOT]/home/.cargo/git/checkouts/dep-[HASH]/[..]/duplicate1/Cargo.toml [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); } #[cargo_test] fn unused_ambiguous_published_deps() { let project = project(); let git_project = git::new("dep", |project| { project .file( "unique/Cargo.toml", &format!( r#" [package] name = "unique" version = "0.5.0" edition = "2015" publish = true "# ), ) .file("unique/src/lib.rs", "") .file( "duplicate1/Cargo.toml", &format!( r#" [package] name = "duplicate" version = "0.5.0" edition = "2015" publish = true "# ), ) .file("duplicate1/src/lib.rs", "") .file( "duplicate2/Cargo.toml", &format!( r#" [package] name = "duplicate" version = "0.5.0" edition = "2015" publish = true "# ), ) .file("duplicate2/src/lib.rs", "") .file( "invalid/Cargo.toml", &format!( r#" [package name = "bar" version = "0.5.0" edition = "2015" publish = true "# ), ) .file("invalid/src/lib.rs", "") }); let p = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.unique] git = '{}' "#, git_project.url() ), ) .file("src/main.rs", "fn main() { }") .build(); p.cargo("build").run(); p.cargo("run") .with_stderr_data(str![[r#" [ERROR] invalid table header expected `.`, `]` --> ../home/.cargo/git/checkouts/dep-[HASH]/[..]/invalid/Cargo.toml:2:29 | 2 | [package | ^ | [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); } #[cargo_test] fn two_deps_only_update_one() { let project = project(); let git1 = git::new("dep1", |project| { project .file("Cargo.toml", &basic_manifest("dep1", "0.5.0")) .file("src/lib.rs", "") }); let git2 = git::new("dep2", |project| { project .file("Cargo.toml", &basic_manifest("dep2", "0.5.0")) .file("src/lib.rs", "") }); let p = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.dep1] git = '{}' [dependencies.dep2] git = '{}' "#, git1.url(), git2.url() ), ) .file("src/main.rs", "fn main() {}") .build(); fn oid_to_short_sha(oid: git2::Oid) -> String { oid.to_string()[..8].to_string() } fn git_repo_head_sha(p: &Project) -> String { let repo = git2::Repository::open(p.root()).unwrap(); let head = repo.head().unwrap().target().unwrap(); oid_to_short_sha(head) } println!("dep1 head sha: {}", git_repo_head_sha(&git1)); println!("dep2 head sha: {}", git_repo_head_sha(&git2)); p.cargo("check") .with_stderr_data( str![[r#" [UPDATING] git repository `[ROOTURL]/dep1` [UPDATING] git repository `[ROOTURL]/dep2` [LOCKING] 2 packages to latest compatible versions [CHECKING] dep1 v0.5.0 ([ROOTURL]/dep1#[..]) [CHECKING] dep2 v0.5.0 ([ROOTURL]/dep2#[..]) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); git1.change_file("src/lib.rs", "pub fn foo() {}"); let repo = git2::Repository::open(&git1.root()).unwrap(); git::add(&repo); let oid = git::commit(&repo); println!("dep1 head sha: {}", oid_to_short_sha(oid)); p.cargo("update dep1") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/dep1` [LOCKING] 1 package to latest compatible version [UPDATING] dep1 v0.5.0 ([ROOTURL]/dep1#[..]) -> #[..] "#]]) .run(); } #[cargo_test] fn stale_cached_version() { let bar = git::new("meta-dep", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.0.0")) .file("src/lib.rs", "pub fn bar() -> i32 { 1 }") }); // Update the git database in the cache with the current state of the git // repo let foo = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies.bar] git = '{}' "#, bar.url() ), ) .file( "src/main.rs", r#" extern crate bar; fn main() { assert_eq!(bar::bar(), 1) } "#, ) .build(); foo.cargo("build").run(); foo.process(&foo.bin("foo")).run(); // Update the repo, and simulate someone else updating the lock file and then // us pulling it down. bar.change_file("src/lib.rs", "pub fn bar() -> i32 { 1 + 0 }"); let repo = git2::Repository::open(&bar.root()).unwrap(); git::add(&repo); git::commit(&repo); sleep_ms(1000); let rev = repo.revparse_single("HEAD").unwrap().id(); foo.change_file( "Cargo.lock", &format!( r#" [[package]] name = "foo" version = "0.0.0" dependencies = [ 'bar 0.0.0 (git+{url}#{hash})' ] [[package]] name = "bar" version = "0.0.0" source = 'git+{url}#{hash}' "#, url = bar.url(), hash = rev ), ); // Now build! foo.cargo("build") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/meta-dep` [COMPILING] bar v0.0.0 ([ROOTURL]/meta-dep#[..]) [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); foo.process(&foo.bin("foo")).run(); } #[cargo_test] fn dep_with_changed_submodule() { let project = project(); let git_project = git::new("dep1", |project| { project.file("Cargo.toml", &basic_manifest("dep1", "0.5.0")) }); let git_project2 = git::new("dep2", |project| { project.file("lib.rs", "pub fn dep() -> &'static str { \"project2\" }") }); let git_project3 = git::new("dep3", |project| { project.file("lib.rs", "pub fn dep() -> &'static str { \"project3\" }") }); let repo = git2::Repository::open(&git_project.root()).unwrap(); let mut sub = git::add_submodule(&repo, &git_project2.url().to_string(), Path::new("src")); git::commit(&repo); let p = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.dep1] git = '{}' "#, git_project.url() ), ) .file( "src/main.rs", " extern crate dep1; pub fn main() { println!(\"{}\", dep1::dep()) } ", ) .build(); println!("first run"); p.cargo("run") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/dep1` [UPDATING] git submodule `[ROOTURL]/dep2` [LOCKING] 1 package to latest compatible version [COMPILING] dep1 v0.5.0 ([ROOTURL]/dep1#[..]) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .with_stdout_data(str![[r#" project2 "#]]) .run(); git_project.change_file( ".gitmodules", &format!( "[submodule \"src\"]\n\tpath = src\n\turl={}", git_project3.url() ), ); // Sync the submodule and reset it to the new remote. sub.sync().unwrap(); { let subrepo = sub.open().unwrap(); subrepo .remote_add_fetch("origin", "refs/heads/*:refs/heads/*") .unwrap(); subrepo .remote_set_url("origin", &git_project3.url().to_string()) .unwrap(); let mut origin = subrepo.find_remote("origin").unwrap(); origin.fetch(&Vec::::new(), None, None).unwrap(); let id = subrepo.refname_to_id("refs/remotes/origin/master").unwrap(); let obj = subrepo.find_object(id, None).unwrap(); subrepo.reset(&obj, git2::ResetType::Hard, None).unwrap(); } sub.add_to_index(true).unwrap(); git::add(&repo); git::commit(&repo); sleep_ms(1000); // Update the dependency and carry on! println!("update"); p.cargo("update") .with_stdout_data(str![]) .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/dep1` [UPDATING] git submodule `[ROOTURL]/dep3` [LOCKING] 1 package to latest compatible version [UPDATING] dep1 v0.5.0 ([ROOTURL]/dep1#[..]) -> #[..] "#]]) .run(); println!("last run"); p.cargo("run") .with_stderr_data(str![[r#" [COMPILING] dep1 v0.5.0 ([ROOTURL]/dep1#[..]) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .with_stdout_data(str![[r#" project3 "#]]) .run(); } #[cargo_test] fn dev_deps_with_testing() { let p2 = git::new("bar", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file( "src/lib.rs", r#" pub fn gimme() -> &'static str { "zoidberg" } "#, ) }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dev-dependencies.bar] version = "0.5.0" git = '{}' "#, p2.url() ), ) .file( "src/main.rs", r#" fn main() {} #[cfg(test)] mod tests { extern crate bar; #[test] fn foo() { bar::gimme(); } } "#, ) .build(); // Generate a lock file which did not use `bar` to compile, but had to update // `bar` to generate the lock file p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 1 package to latest compatible version [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Make sure we use the previous resolution of `bar` instead of updating it // a second time. p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] bar v0.5.0 ([ROOTURL]/bar#[..]) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/main.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" ... test tests::foo ... ok ... "#]]) .run(); } #[cargo_test] fn git_build_cmd_freshness() { let foo = git::new("foo", |project| { project .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "pub fn bar() -> i32 { 1 }") .file(".gitignore", "src/bar.rs") }); foo.root().move_into_the_past(); sleep_ms(1000); foo.cargo("check") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Smoke test to make sure it doesn't compile again println!("first pass"); foo.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Modify an ignored file and make sure we don't rebuild println!("second pass"); foo.change_file("src/bar.rs", ""); foo.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn git_name_not_always_needed() { let p2 = git::new("bar", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file( "src/lib.rs", r#" pub fn gimme() -> &'static str { "zoidberg" } "#, ) }); let repo = git2::Repository::open(&p2.root()).unwrap(); let mut cfg = repo.config().unwrap(); let _ = cfg.remove("user.name"); let _ = cfg.remove("user.email"); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dev-dependencies.bar] git = '{}' "#, p2.url() ), ) .file("src/main.rs", "fn main() {}") .build(); // Generate a lock file which did not use `bar` to compile, but had to update // `bar` to generate the lock file p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 1 package to latest compatible version [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn git_repo_changing_no_rebuild() { let bar = git::new("bar", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "pub fn bar() -> i32 { 1 }") }); // Lock p1 to the first rev in the git repo let p1 = project() .at("p1") .file( "Cargo.toml", &format!( r#" [package] name = "p1" version = "0.5.0" edition = "2015" authors = [] build = 'build.rs' [dependencies.bar] git = '{}' "#, bar.url() ), ) .file("src/main.rs", "fn main() {}") .file("build.rs", "fn main() {}") .build(); p1.root().move_into_the_past(); p1.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 1 package to latest compatible version [COMPILING] p1 v0.5.0 ([ROOT]/p1) [CHECKING] bar v0.5.0 ([ROOTURL]/bar#[..]) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Make a commit to lock p2 to a different rev bar.change_file("src/lib.rs", "pub fn bar() -> i32 { 2 }"); let repo = git2::Repository::open(&bar.root()).unwrap(); git::add(&repo); git::commit(&repo); // Lock p2 to the second rev let p2 = project() .at("p2") .file( "Cargo.toml", &format!( r#" [package] name = "p2" version = "0.5.0" edition = "2015" authors = [] [dependencies.bar] git = '{}' "#, bar.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p2.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.5.0 ([ROOTURL]/bar#[..]) [CHECKING] p2 v0.5.0 ([ROOT]/p2) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // And now for the real test! Make sure that p1 doesn't get rebuilt // even though the git repo has changed. p1.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn git_dep_build_cmd() { let p = git::new("foo", |project| { project .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] version = "0.5.0" path = "bar" [[bin]] name = "foo" "#, ) .file("src/foo.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"])) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] build = "build.rs" [lib] name = "bar" path = "src/bar.rs" "#, ) .file( "bar/src/bar.rs.in", r#" pub fn gimme() -> i32 { 0 } "#, ) .file( "bar/build.rs", r#" use std::fs; fn main() { fs::copy("src/bar.rs.in", "src/bar.rs").unwrap(); } "#, ) }); p.root().join("bar").move_into_the_past(); p.cargo("build").run(); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" 0 "#]]) .run(); // Touching bar.rs.in should cause the `build` command to run again. p.change_file("bar/src/bar.rs.in", "pub fn gimme() -> i32 { 1 }"); p.cargo("build").run(); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" 1 "#]]) .run(); } #[cargo_test] fn fetch_downloads() { let bar = git::new("bar", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "pub fn bar() -> i32 { 1 }") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies.bar] git = '{}' "#, bar.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("fetch") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 1 package to latest compatible version "#]]) .run(); p.cargo("fetch").with_stderr_data(str![]).run(); } #[cargo_test] fn fetch_downloads_with_git2_first_then_with_gitoxide_and_vice_versa() { let bar = git::new("bar", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "pub fn bar() -> i32 { 1 }") }); let feature_configuration = if cargo_uses_gitoxide() { // When we are always using `gitoxide` by default, create the registry with git2 as well as the download… "-Zgitoxide=internal-use-git2" } else { // …otherwise create the registry and the git download with `gitoxide`. "-Zgitoxide=fetch" }; let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies.bar] git = '{url}' "#, url = bar.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("fetch") .arg(feature_configuration) .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 1 package to latest compatible version "#]]) .run(); Package::new("bar", "1.0.0").publish(); // trigger a crates-index change. p.cargo("fetch").with_stderr_data(str![]).run(); } #[cargo_test] fn warnings_in_git_dep() { let bar = git::new("bar", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "fn unused() {}") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies.bar] git = '{}' "#, bar.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.5.0 ([ROOTURL]/bar#[..]) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn update_ambiguous() { let bar1 = git::new("bar1", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "") }); let bar2 = git::new("bar2", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.6.0")) .file("src/lib.rs", "") }); let baz = git::new("baz", |project| { project .file( "Cargo.toml", &format!( r#" [package] name = "baz" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] git = '{}' "#, bar2.url() ), ) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies.bar] git = '{}' [dependencies.baz] git = '{}' "#, bar1.url(), baz.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("generate-lockfile").run(); p.cargo("update bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] There are multiple `bar` packages in your project, and the specification `bar` is ambiguous. Please re-run this command with one of the following specifications: bar@0.5.0 bar@0.6.0 "#]]) .run(); } #[cargo_test] fn update_one_dep_in_repo_with_many_deps() { let bar = git::new("bar", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("a", "0.5.0")) .file("a/src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies.bar] git = '{}' [dependencies.a] git = '{}' "#, bar.url(), bar.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("generate-lockfile").run(); p.cargo("update bar") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 0 packages to latest compatible versions "#]]) .run(); } #[cargo_test] fn switch_deps_does_not_update_transitive() { let transitive = git::new("transitive", |project| { project .file("Cargo.toml", &basic_manifest("transitive", "0.5.0")) .file("src/lib.rs", "") }); let dep1 = git::new("dep1", |project| { project .file( "Cargo.toml", &format!( r#" [package] name = "dep" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.transitive] git = '{}' "#, transitive.url() ), ) .file("src/lib.rs", "") }); let dep2 = git::new("dep2", |project| { project .file( "Cargo.toml", &format!( r#" [package] name = "dep" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.transitive] git = '{}' "#, transitive.url() ), ) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies.dep] git = '{}' "#, dep1.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/dep1` [UPDATING] git repository `[ROOTURL]/transitive` [LOCKING] 2 packages to latest compatible versions [CHECKING] transitive v0.5.0 ([ROOTURL]/transitive#[..]) [CHECKING] dep v0.5.0 ([ROOTURL]/dep1#[..]) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Update the dependency to point to the second repository, but this // shouldn't update the transitive dependency which is the same. p.change_file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies.dep] git = '{}' "#, dep2.url() ), ); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/dep2` [LOCKING] 1 package to latest compatible version [ADDING] dep v0.5.0 ([ROOTURL]/dep2#[..]) [CHECKING] dep v0.5.0 ([ROOTURL]/dep2#[..]) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn update_one_source_updates_all_packages_in_that_git_source() { let dep = git::new("dep", |project| { project .file( "Cargo.toml", r#" [package] name = "dep" version = "0.5.0" edition = "2015" authors = [] [dependencies.a] path = "a" "#, ) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("a", "0.5.0")) .file("a/src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies.dep] git = '{}' "#, dep.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check").run(); let repo = git2::Repository::open(&dep.root()).unwrap(); let rev1 = repo.revparse_single("HEAD").unwrap().id(); // Just be sure to change a file dep.change_file("src/lib.rs", "pub fn bar() -> i32 { 2 }"); git::add(&repo); git::commit(&repo); p.cargo("update dep").run(); let lockfile = p.read_lockfile(); assert!( !lockfile.contains(&rev1.to_string()), "{} in {}", rev1, lockfile ); } #[cargo_test] fn switch_sources() { let a1 = git::new("a1", |project| { project .file("Cargo.toml", &basic_manifest("a", "0.5.0")) .file("src/lib.rs", "") }); let a2 = git::new("a2", |project| { project .file("Cargo.toml", &basic_manifest("a", "0.5.1")) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies.b] path = "b" "#, ) .file("src/main.rs", "fn main() {}") .file( "b/Cargo.toml", &format!( r#" [package] name = "b" version = "0.5.0" edition = "2015" authors = [] [dependencies.a] git = '{}' "#, a1.url() ), ) .file("b/src/lib.rs", "pub fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/a1` [LOCKING] 2 packages to latest compatible versions [CHECKING] a v0.5.0 ([ROOTURL]/a1#[..]) [CHECKING] b v0.5.0 ([ROOT]/foo/b) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file( "b/Cargo.toml", &format!( r#" [package] name = "b" version = "0.5.0" edition = "2015" authors = [] [dependencies.a] git = '{}' "#, a2.url() ), ); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/a2` [LOCKING] 1 package to latest compatible version [ADDING] a v0.5.1 ([ROOTURL]/a2#[..]) [CHECKING] a v0.5.1 ([ROOTURL]/a2#[..]) [CHECKING] b v0.5.0 ([ROOT]/foo/b) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn dont_require_submodules_are_checked_out() { let p = project().build(); let git1 = git::new("dep1", |p| { p.file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] build = "build.rs" "#, ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "") .file("a/foo", "") }); let git2 = git::new("dep2", |p| p); let repo = git2::Repository::open(&git1.root()).unwrap(); let url = git2.root().to_url().to_string(); git::add_submodule(&repo, &url, Path::new("a/submodule")); git::commit(&repo); git2::Repository::init(&p.root()).unwrap(); let url = git1.root().to_url().to_string(); let dst = paths::home().join("foo"); git2::Repository::clone(&url, &dst).unwrap(); git1.cargo("check -v").cwd(&dst).run(); } #[cargo_test] fn doctest_same_name() { let a2 = git::new("a2", |p| { p.file("Cargo.toml", &basic_manifest("a", "0.5.0")) .file("src/lib.rs", "pub fn a2() {}") }); let a1 = git::new("a1", |p| { p.file( "Cargo.toml", &format!( r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = {{ git = '{}' }} "#, a2.url() ), ) .file("src/lib.rs", "extern crate a; pub fn a1() {}") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = {{ git = '{}' }} "#, a1.url() ), ) .file( "src/lib.rs", r#" #[macro_use] extern crate a; "#, ) .build(); p.cargo("test -v").run(); } #[cargo_test] fn lints_are_suppressed() { let a = git::new("a", |p| { p.file("Cargo.toml", &basic_manifest("a", "0.5.0")).file( "src/lib.rs", " use std::option; ", ) }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = {{ git = '{}' }} "#, a.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/a` [LOCKING] 1 package to latest compatible version [CHECKING] a v0.5.0 ([ROOTURL]/a#[..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn denied_lints_are_allowed() { let a = git::new("a", |p| { p.file("Cargo.toml", &basic_manifest("a", "0.5.0")).file( "src/lib.rs", " #![deny(warnings)] use std::option; ", ) }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = {{ git = '{}' }} "#, a.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/a` [LOCKING] 1 package to latest compatible version [CHECKING] a v0.5.0 ([ROOTURL]/a#[..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn add_a_git_dep() { let git = git::new("git", |p| { p.file("Cargo.toml", &basic_manifest("git", "0.5.0")) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = {{ path = 'a' }} git = {{ git = '{}' }} "#, git.url() ), ) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/src/lib.rs", "") .build(); p.cargo("check").run(); assert!(paths::home().join(".cargo/git/CACHEDIR.TAG").is_file()); p.change_file( "a/Cargo.toml", &format!( r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [dependencies] git = {{ git = '{}' }} "#, git.url() ), ); p.cargo("check").run(); } #[cargo_test] fn two_at_rev_instead_of_tag() { let git = git::new("git", |p| { p.file("Cargo.toml", &basic_manifest("git1", "0.5.0")) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("git2", "0.5.0")) .file("a/src/lib.rs", "") }); // Make a tag corresponding to the current HEAD let repo = git2::Repository::open(&git.root()).unwrap(); let head = repo.head().unwrap().target().unwrap(); repo.tag( "v0.1.0", &repo.find_object(head, None).unwrap(), &repo.signature().unwrap(), "make a new tag", false, ) .unwrap(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] git1 = {{ git = '{0}', rev = 'v0.1.0' }} git2 = {{ git = '{0}', rev = 'v0.1.0' }} "#, git.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); p.cargo("check -v").run(); } #[cargo_test] fn include_overrides_gitignore() { // Make sure that `package.include` takes precedence over .gitignore. let p = git::new("foo", |repo| { repo.file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" include = ["src/lib.rs", "ignored.txt", "Cargo.toml"] "#, ) .file( ".gitignore", r#" /target Cargo.lock ignored.txt "#, ) .file("src/lib.rs", "") .file("ignored.txt", "") .file("build.rs", "fn main() {}") }); p.cargo("check").run(); p.change_file("ignored.txt", "Trigger rebuild."); p.cargo("check -v") .with_stderr_data(str![[r#" [DIRTY] foo v0.5.0 ([ROOT]/foo): the precalculated components changed [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("package --list --allow-dirty") .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig ignored.txt src/lib.rs "#]]) .run(); } #[cargo_test] fn invalid_git_dependency_manifest() { let project = project(); let git_project = git::new("dep1", |project| { project .file( "Cargo.toml", r#" [package] name = "dep1" version = "0.5.0" edition = "2015" authors = ["carlhuda@example.com"] categories = ["algorithms"] categories = ["algorithms"] [lib] name = "dep1" "#, ) .file( "src/dep1.rs", r#" pub fn hello() -> &'static str { "hello world" } "#, ) }); let project = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.dep1] git = '{}' "#, git_project.url() ), ) .file( "src/main.rs", &main_file(r#""{}", dep1::hello()"#, &["dep1"]), ) .build(); project .cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/dep1` [ERROR] duplicate key `categories` in table `package` --> ../home/.cargo/git/checkouts/dep1-[HASH]/[..]/Cargo.toml:9:21 | 9 | categories = ["algorithms"] | ^ | [ERROR] failed to get `dep1` as a dependency of package `foo v0.5.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `dep1` Caused by: Unable to update [ROOTURL]/dep1 "#]]) .run(); } #[cargo_test] fn failed_submodule_checkout() { let project = project(); let git_project = git::new("dep1", |project| { project.file("Cargo.toml", &basic_manifest("dep1", "0.5.0")) }); let git_project2 = git::new("dep2", |project| project.file("lib.rs", "")); let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = listener.local_addr().unwrap(); let done = Arc::new(AtomicBool::new(false)); let done2 = done.clone(); let t = thread::spawn(move || { while !done2.load(Ordering::SeqCst) { if let Ok((mut socket, _)) = listener.accept() { drop(socket.write_all(b"foo\r\n")); } } }); let repo = git2::Repository::open(&git_project2.root()).unwrap(); let url = format!("https://{}:{}/", addr.ip(), addr.port()); { let mut s = repo.submodule(&url, Path::new("bar"), false).unwrap(); let subrepo = s.open().unwrap(); let mut cfg = subrepo.config().unwrap(); cfg.set_str("user.email", "foo@bar.com").unwrap(); cfg.set_str("user.name", "Foo Bar").unwrap(); git::commit(&subrepo); s.add_finalize().unwrap(); } git::commit(&repo); drop((repo, url)); let repo = git2::Repository::open(&git_project.root()).unwrap(); let url = git_project2.root().to_url().to_string(); git::add_submodule(&repo, &url, Path::new("src")); git::commit(&repo); drop(repo); let project = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] dep1 = {{ git = '{}' }} "#, git_project.url() ), ) .file("src/lib.rs", "") .build(); project .cargo("check") .with_status(101) .with_stderr_data(str![[r#" ... failed to update submodule `src` ... failed to update submodule `bar` ... "#]]) .run(); project .cargo("check") .with_status(101) .with_stderr_data(str![[r#" ... failed to update submodule `src` ... failed to update submodule `bar` ... "#]]) .run(); done.store(true, Ordering::SeqCst); drop(TcpStream::connect(&addr)); t.join().unwrap(); } #[cargo_test(requires = "git")] fn use_the_cli() { let project = project(); let git_project = git::new("dep1", |project| { project .file("Cargo.toml", &basic_manifest("dep1", "0.5.0")) .file("src/lib.rs", "") }); let project = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] dep1 = {{ git = '{}' }} "#, git_project.url() ), ) .file("src/lib.rs", "") .file( ".cargo/config.toml", " [net] git-fetch-with-cli = true ", ) .build(); let stderr = str![[r#" [UPDATING] git repository `[ROOTURL]/dep1` [RUNNING] `git fetch --no-tags --verbose --force --update-head-ok [..][ROOTURL]/dep1[..] [..]+HEAD:refs/remotes/origin/HEAD[..]` From [ROOTURL]/dep1 * [new ref] [..] -> origin/HEAD[..] [LOCKING] 1 package to latest compatible version [CHECKING] dep1 v0.5.0 ([ROOTURL]/dep1#[..]) [RUNNING] `rustc --crate-name dep1 [..]` [CHECKING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]; project .cargo("check -v") .env("LC_ALL", "C") .with_stderr_data(stderr) .run(); assert!(paths::home().join(".cargo/git/CACHEDIR.TAG").is_file()); } #[cargo_test] fn templatedir_doesnt_cause_problems() { let git_project2 = git::new("dep2", |project| { project .file("Cargo.toml", &basic_manifest("dep2", "0.5.0")) .file("src/lib.rs", "") }); let git_project = git::new("dep1", |project| { project .file("Cargo.toml", &basic_manifest("dep1", "0.5.0")) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "fo" version = "0.5.0" edition = "2015" authors = [] [dependencies] dep1 = {{ git = '{}' }} "#, git_project.url() ), ) .file("src/main.rs", "fn main() {}") .build(); fs::write( paths::home().join(".gitconfig"), format!( r#" [init] templatedir = {} "#, git_project2 .url() .to_file_path() .unwrap() .to_str() .unwrap() .replace("\\", "/") ), ) .unwrap(); p.cargo("check").run(); } #[cargo_test(requires = "git")] fn git_with_cli_force() { // Supports a force-pushed repo. let git_project = git::new("dep1", |project| { project .file("Cargo.toml", &basic_lib_manifest("dep1")) .file("src/lib.rs", r#"pub fn f() { println!("one"); }"#) }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2018" [dependencies] dep1 = {{ git = "{}" }} "#, git_project.url() ), ) .file("src/main.rs", "fn main() { dep1::f(); }") .file( ".cargo/config.toml", " [net] git-fetch-with-cli = true ", ) .build(); p.cargo("build").run(); p.rename_run("foo", "foo1") .with_stdout_data(str![[r#" one "#]]) .run(); // commit --amend a change that will require a force fetch. let repo = git2::Repository::open(&git_project.root()).unwrap(); git_project.change_file("src/lib.rs", r#"pub fn f() { println!("two"); }"#); git::add(&repo); let id = repo.refname_to_id("HEAD").unwrap(); let commit = repo.find_commit(id).unwrap(); let tree_id = t!(t!(repo.index()).write_tree()); t!(commit.amend( Some("HEAD"), None, None, None, None, Some(&t!(repo.find_tree(tree_id))) )); // Perform the fetch. p.cargo("update").run(); p.cargo("build").run(); p.rename_run("foo", "foo2") .with_stdout_data(str![[r#" two "#]]) .run(); } #[cargo_test(requires = "git")] fn git_fetch_cli_env_clean() { // This tests that git-fetch-with-cli works when GIT_DIR environment // variable is set (for whatever reason). let git_dep = git::new("dep1", |project| { project .file("Cargo.toml", &basic_manifest("dep1", "0.5.0")) .file("src/lib.rs", "") }); let git_proj = git::new("foo", |project| { project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] dep1 = {{ git = '{}' }} "#, git_dep.url() ), ) .file("src/lib.rs", "pub extern crate dep1;") .file( ".cargo/config.toml", " [net] git-fetch-with-cli = true ", ) }); // The directory set here isn't too important. Pointing to our own git // directory causes git to be confused and fail. Can also point to an // empty directory, or a nonexistent one. git_proj .cargo("fetch") .env("GIT_DIR", git_proj.root().join(".git")) .run(); } #[cargo_test] fn dirty_submodule() { // `cargo package` warns for dirty file in submodule. let (git_project, repo) = git::new_repo("foo", |project| { project .file("Cargo.toml", &basic_manifest("foo", "0.5.0")) // This is necessary because `git::add` is too eager. .file(".gitignore", "/target") }); let git_project2 = git::new("src", |project| { project.no_manifest().file("lib.rs", "pub fn f() {}") }); let url = git_project2.root().to_url().to_string(); git::add_submodule(&repo, &url, Path::new("src")); // Submodule added, but not committed. git_project .cargo("package --no-verify") .with_status(101) .with_stderr_data(str![[r#" [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [ERROR] 1 files in the working directory contain changes that were not yet committed into git: .gitmodules to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag "#]]) .run(); git::commit(&repo); git_project.cargo("package --no-verify").run(); // Modify file, check for warning. git_project.change_file("src/lib.rs", ""); git_project .cargo("package --no-verify") .with_status(101) .with_stderr_data(str![[r#" [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [ERROR] 1 files in the working directory contain changes that were not yet committed into git: src/lib.rs to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag "#]]) .run(); // Commit the change. let sub_repo = git2::Repository::open(git_project.root().join("src")).unwrap(); git::add(&sub_repo); git::commit(&sub_repo); git::add(&repo); git::commit(&repo); git_project.cargo("package --no-verify").run(); // Try with a nested submodule. let git_project3 = git::new("bar", |project| project.no_manifest().file("mod.rs", "")); let url = git_project3.root().to_url().to_string(); git::add_submodule(&sub_repo, &url, Path::new("bar")); git_project .cargo("package --no-verify") .with_status(101) .with_stderr_data(str![[r#" [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [ERROR] 1 files in the working directory contain changes that were not yet committed into git: src/.gitmodules to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag "#]]) .run(); // Commit the submodule addition. git::commit(&sub_repo); git::add(&repo); git::commit(&repo); git_project.cargo("package --no-verify").run(); // Modify within nested submodule. git_project.change_file("src/bar/new_file.rs", "//test"); git_project .cargo("package --no-verify") .with_status(101) .with_stderr_data(str![[r#" [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [ERROR] 1 files in the working directory contain changes that were not yet committed into git: src/bar/new_file.rs to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag "#]]) .run(); // And commit the change. let sub_sub_repo = git2::Repository::open(git_project.root().join("src/bar")).unwrap(); git::add(&sub_sub_repo); git::commit(&sub_sub_repo); git::add(&sub_repo); git::commit(&sub_repo); git::add(&repo); git::commit(&repo); git_project.cargo("package --no-verify").run(); } #[cargo_test] fn default_not_master() { let project = project(); // Create a repository with a `master` branch, but switch the head to a // branch called `main` at the same time. let (git_project, repo) = git::new_repo("dep1", |project| { project .file("Cargo.toml", &basic_lib_manifest("dep1")) .file("src/lib.rs", "pub fn foo() {}") }); let head_id = repo.head().unwrap().target().unwrap(); let head = repo.find_commit(head_id).unwrap(); repo.branch("main", &head, false).unwrap(); repo.set_head("refs/heads/main").unwrap(); // Then create a commit on the new `main` branch so `master` and `main` // differ. git_project.change_file("src/lib.rs", "pub fn bar() {}"); git::add(&repo); git::commit(&repo); let project = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" [dependencies] dep1 = {{ git = '{}' }} "#, git_project.url() ), ) .file("src/lib.rs", "pub fn foo() { dep1::bar() }") .build(); project .cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/dep1` [LOCKING] 1 package to latest compatible version [CHECKING] dep1 v0.5.0 ([ROOTURL]/dep1#[..]) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn historical_lockfile_works() { let project = project(); let (git_project, repo) = git::new_repo("dep1", |project| { project .file("Cargo.toml", &basic_lib_manifest("dep1")) .file("src/lib.rs", "") }); let head_id = repo.head().unwrap().target().unwrap(); let project = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" [dependencies] dep1 = {{ git = '{}', branch = 'master' }} "#, git_project.url() ), ) .file("src/lib.rs", "") .build(); project.cargo("check").run(); project.change_file( "Cargo.lock", &format!( r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "dep1" version = "0.5.0" source = "git+{}#{}" [[package]] name = "foo" version = "0.5.0" dependencies = [ "dep1", ] "#, git_project.url(), head_id ), ); project .cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [ADDING] dep1 v0.5.0 ([ROOTURL]/dep1?branch=master#[..]) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn historical_lockfile_works_with_vendor() { let project = project(); let (git_project, repo) = git::new_repo("dep1", |project| { project .file("Cargo.toml", &basic_lib_manifest("dep1")) .file("src/lib.rs", "") }); let head_id = repo.head().unwrap().target().unwrap(); let project = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" [dependencies] dep1 = {{ git = '{}', branch = 'master' }} "#, git_project.url() ), ) .file("src/lib.rs", "") .build(); let output = project.cargo("vendor").run(); project.change_file( ".cargo/config.toml", str::from_utf8(&output.stdout).unwrap(), ); project.change_file( "Cargo.lock", &format!( r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "dep1" version = "0.5.0" source = "git+{}#{}" [[package]] name = "foo" version = "0.5.0" dependencies = [ "dep1", ] "#, git_project.url(), head_id ), ); project.cargo("check").run(); } #[cargo_test] fn two_dep_forms() { let project = project(); let (git_project, _repo) = git::new_repo("dep1", |project| { project .file("Cargo.toml", &basic_lib_manifest("dep1")) .file("src/lib.rs", "") }); let project = project .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" [dependencies] dep1 = {{ git = '{}', branch = 'master' }} a = {{ path = 'a' }} "#, git_project.url() ), ) .file("src/lib.rs", "") .file( "a/Cargo.toml", &format!( r#" [package] name = "a" version = "0.5.0" edition = "2015" [dependencies] dep1 = {{ git = '{}' }} "#, git_project.url() ), ) .file("a/src/lib.rs", "") .build(); // This'll download the git repository twice, one with HEAD and once with // the master branch. Then it'll compile 4 crates, the 2 git deps, then // the two local deps. project .cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/dep1` [UPDATING] git repository `[ROOTURL]/dep1` [LOCKING] 3 packages to latest compatible versions [CHECKING] dep1 v0.5.0 ([ROOTURL]/dep1#[..]) [CHECKING] dep1 v0.5.0 ([ROOTURL]/dep1?branch=master#[..]) [CHECKING] a v0.5.0 ([ROOT]/foo/a) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn metadata_master_consistency() { // SourceId consistency in the `cargo metadata` output when `master` is // explicit or implicit, using new or old Cargo.lock. let (git_project, git_repo) = git::new_repo("bar", |project| { project .file("Cargo.toml", &basic_manifest("bar", "1.0.0")) .file("src/lib.rs", "") }); let bar_hash = git_repo.head().unwrap().target().unwrap().to_string(); // Explicit branch="master" with a lock file created before 1.47 (does not contain ?branch=master). let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = {{ git = "{}", branch = "master" }} "#, git_project.url() ), ) .file( "Cargo.lock", &format!( r#" [[package]] name = "bar" version = "1.0.0" source = "git+{}#{}" [[package]] name = "foo" version = "0.1.0" dependencies = [ "bar", ] "#, git_project.url(), bar_hash, ), ) .file("src/lib.rs", "") .build(); let metadata = |bar_source| -> String { r#" { "packages": [ { "name": "bar", "version": "1.0.0", "id": "__BAR_SOURCE__#1.0.0", "license": null, "license_file": null, "description": null, "source": "__BAR_SOURCE__#__BAR_HASH__", "dependencies": [], "targets": "{...}", "features": {}, "manifest_path": "[..]", "metadata": null, "publish": null, "authors": [], "categories": [], "default_run": null, "keywords": [], "readme": null, "repository": null, "rust_version": null, "homepage": null, "documentation": null, "edition": "2015", "links": null }, { "name": "foo", "version": "0.1.0", "id": "[..]foo#0.1.0", "license": null, "license_file": null, "description": null, "source": null, "dependencies": [ { "name": "bar", "source": "__BAR_SOURCE__", "req": "*", "kind": null, "rename": null, "optional": false, "uses_default_features": true, "features": [], "target": null, "registry": null } ], "targets": "{...}", "features": {}, "manifest_path": "[..]", "metadata": null, "publish": null, "authors": [], "categories": [], "default_run": null, "keywords": [], "readme": null, "repository": null, "rust_version": null, "homepage": null, "documentation": null, "edition": "2015", "links": null } ], "workspace_members": [ "[..]foo#0.1.0" ], "workspace_default_members": [ "[..]foo#0.1.0" ], "resolve": { "nodes": [ { "id": "__BAR_SOURCE__#1.0.0", "dependencies": [], "deps": [], "features": [] }, { "id": "[..]foo#0.1.0", "dependencies": [ "__BAR_SOURCE__#1.0.0" ], "deps": [ { "name": "bar", "pkg": "__BAR_SOURCE__#1.0.0", "dep_kinds": [ { "kind": null, "target": null } ] } ], "features": [] } ], "root": "[..]foo#0.1.0" }, "target_directory": "[..]", "version": 1, "workspace_root": "[..]", "metadata": null } "# .replace("__BAR_SOURCE__", bar_source) .replace("__BAR_HASH__", &bar_hash) }; let bar_source = "git+[ROOTURL]/bar?branch=master"; p.cargo("metadata") .with_stdout_data(&metadata(&bar_source).is_json()) .run(); // Conversely, remove branch="master" from Cargo.toml, but use a new Cargo.lock that has ?branch=master. let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = {{ git = "{}" }} "#, git_project.url() ), ) .file( "Cargo.lock", &format!( r#" [[package]] name = "bar" version = "1.0.0" source = "git+{}?branch=master#{}" [[package]] name = "foo" version = "0.1.0" dependencies = [ "bar", ] "#, git_project.url(), bar_hash ), ) .file("src/lib.rs", "") .build(); // No ?branch=master! let bar_source = "git+[ROOTURL]/bar"; p.cargo("metadata") .with_stdout_data(&metadata(&bar_source).is_json()) .run(); } #[cargo_test] fn git_with_force_push() { // Checks that cargo can handle force-pushes to git repos. // This works by having a git dependency that is updated with an amend // commit, and tries with various forms (default branch, branch, rev, // tag). let main = |text| format!(r#"pub fn f() {{ println!("{}"); }}"#, text); let (git_project, repo) = git::new_repo("dep1", |project| { project .file("Cargo.toml", &basic_lib_manifest("dep1")) .file("src/lib.rs", &main("one")) }); let manifest = |extra| { format!( r#" [package] name = "foo" version = "0.0.1" edition = "2018" [dependencies] dep1 = {{ git = "{}"{} }} "#, git_project.url(), extra ) }; let p = project() .file("Cargo.toml", &manifest("")) .file("src/main.rs", "fn main() { dep1::f(); }") .build(); // Download the original and make sure it is OK. p.cargo("build").run(); p.rename_run("foo", "foo1") .with_stdout_data(str![[r#" one "#]]) .run(); let find_head = || t!(t!(repo.head()).peel_to_commit()); let amend_commit = |text| { // commit --amend a change that will require a force fetch. git_project.change_file("src/lib.rs", &main(text)); git::add(&repo); let commit = find_head(); let tree_id = t!(t!(repo.index()).write_tree()); t!(commit.amend( Some("HEAD"), None, None, None, None, Some(&t!(repo.find_tree(tree_id))) )); }; let mut rename_annoyance = 1; let mut verify = |text| { // Perform the fetch. p.cargo("update").run(); p.cargo("build").run(); rename_annoyance += 1; p.rename_run("foo", &format!("foo{}", rename_annoyance)) .with_stdout_data(text) .run(); }; amend_commit("two"); verify(str![[r#" two "#]]); // Try with a rev. let head1 = find_head().id().to_string(); let extra = format!(", rev = \"{}\"", head1); p.change_file("Cargo.toml", &manifest(&extra)); verify(str![[r#" two "#]]); amend_commit("three"); let head2 = find_head().id().to_string(); assert_ne!(&head1, &head2); let extra = format!(", rev = \"{}\"", head2); p.change_file("Cargo.toml", &manifest(&extra)); verify(str![[r#" three "#]]); // Try with a tag. git::tag(&repo, "my-tag"); p.change_file("Cargo.toml", &manifest(", tag = \"my-tag\"")); verify(str![[r#" three "#]]); amend_commit("tag-three"); let head = t!(t!(repo.head()).peel(git2::ObjectType::Commit)); t!(repo.tag("my-tag", &head, &t!(repo.signature()), "move tag", true)); verify(str![[r#" tag-three "#]]); // Try with a branch. let br = t!(repo.branch("awesome-stuff", &find_head(), false)); t!(repo.checkout_tree(&t!(br.get().peel(git2::ObjectType::Tree)), None)); t!(repo.set_head("refs/heads/awesome-stuff")); git_project.change_file("src/lib.rs", &main("awesome-three")); git::add(&repo); git::commit(&repo); p.change_file("Cargo.toml", &manifest(", branch = \"awesome-stuff\"")); verify(str![[r#" awesome-three "#]]); amend_commit("awesome-four"); verify(str![[r#" awesome-four "#]]); } #[cargo_test] fn corrupted_checkout() { // Test what happens if the checkout is corrupted somehow. _corrupted_checkout(false); } #[cargo_test] fn corrupted_checkout_with_cli() { // Test what happens if the checkout is corrupted somehow with git cli. _corrupted_checkout(true); } fn _corrupted_checkout(with_cli: bool) { let (git_project, repository) = git::new_repo("dep1", |project| { project .file("Cargo.toml", &basic_manifest("dep1", "0.5.0")) .file("src/lib.rs", "") }); let project2 = git::new("dep2", |project| { project.no_manifest().file("README.md", "") }); let url = project2.root().to_url().to_string(); add_submodule(&repository, &url, Path::new("dep2")); git::commit(&repository); drop(repository); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] dep1 = {{ git = "{}" }} "#, git_project.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("fetch").run(); let mut dep1_co_paths = t!(glob::glob( paths::home() .join(".cargo/git/checkouts/dep1-*/*") .to_str() .unwrap() )); let dep1_co_path = dep1_co_paths.next().unwrap().unwrap(); let dep1_ok = dep1_co_path.join(".cargo-ok"); let dep1_manifest = dep1_co_path.join("Cargo.toml"); let dep2_readme = dep1_co_path.join("dep2/README.md"); // Deleting this file simulates an interrupted checkout. t!(fs::remove_file(&dep1_ok)); t!(fs::remove_file(&dep1_manifest)); t!(fs::remove_file(&dep2_readme)); // This should refresh the checkout. let mut e = p.cargo("fetch"); if with_cli { e.env("CARGO_NET_GIT_FETCH_WITH_CLI", "true"); } e.run(); assert!(dep1_ok.exists()); assert!(dep1_manifest.exists()); assert!(dep2_readme.exists()); } #[cargo_test] fn cleans_temp_pack_files() { // Checks that cargo removes temp files left by libgit2 when it is // interrupted (see clean_repo_temp_files). Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch").run(); // Simulate what happens when libgit2 is interrupted while indexing a pack file. let tmp_path = super::git_gc::find_index().join(".git/objects/pack/pack_git2_91ab40da04fdc2e7"); fs::write(&tmp_path, "test").unwrap(); let mut perms = fs::metadata(&tmp_path).unwrap().permissions(); perms.set_readonly(true); fs::set_permissions(&tmp_path, perms).unwrap(); // Trigger an index update. 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" edition = "2015" [dependencies.dep1] git = '{}' "#, user1_git_project.url() ), ) .file("src/main.rs", &main_file(r#""hello""#, &[])) .build(); project .cargo("build") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/user1/dep1` [UPDATING] git submodule `[ROOTURL]/user2/dep1` [UPDATING] git submodule `[ROOTURL]/user2/dep2` [LOCKING] 1 package to latest compatible version [COMPILING] dep1 v0.5.0 ([ROOTURL]/user1/dep1#[..]) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(project.bin("foo").is_file()); } #[cargo_test] fn git_worktree_with_original_repo_renamed() { let project = project().build(); let git_project = git::new("foo", |project| { project .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] license = "MIR OR Apache-2.0" description = "A test!" homepage = "https://example.org" documentation = "" repository = "https://example.org" readme = "./README.md" "#, ) .file("src/lib.rs", "") .file("README.md", "") }); let repo = git2::Repository::open(&git_project.root()).unwrap(); let repo_root = repo.workdir().unwrap().parent().unwrap(); let opts = git2::WorktreeAddOptions::new(); let _ = repo .worktree("bar", &repo_root.join("bar"), Some(&opts)) .unwrap(); // Rename the original repository let new = repo_root.join("foo2"); fs::rename(&git_project.root(), &new).unwrap(); project .cargo("package --list") .cwd(&new) .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig README.md src/lib.rs "#]]) .run(); project .cargo("check") .cwd(&new) .with_stderr_data(str![[r#" [CHECKING] foo v0.5.0 ([ROOT]/foo2) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(public_network_test, requires = "git")] fn github_fastpath_error_message() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bitflags = { git = "https://github.com/rust-lang/bitflags.git", rev="11111b376b93484341c68fbca3ca110ae5cd2790" } "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .env("CARGO_NET_GIT_FETCH_WITH_CLI", "true") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] git repository `https://github.com/rust-lang/bitflags.git` fatal: remote [ERROR] upload-pack: not our ref 11111b376b93484341c68fbca3ca110ae5cd2790 [ERROR] failed to get `bitflags` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bitflags` Caused by: Unable to update https://github.com/rust-lang/bitflags.git?rev=11111b376b93484341c68fbca3ca110ae5cd2790 Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/bitflags-[HASH] Caused by: revision 11111b376b93484341c68fbca3ca110ae5cd2790 not found Caused by: process didn't exit successfully: `git fetch --no-tags --force --update-head-ok [..] "#]]) .run(); } #[cargo_test(public_network_test)] fn git_fetch_libgit2_error_message() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bitflags = { git = "https://github.com/rust-lang/bitflags.git", rev="11111b376b93484341c68fbca3ca110ae5cd2790" } "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] git repository `https://github.com/rust-lang/bitflags.git` ... [ERROR] failed to get `bitflags` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bitflags` Caused by: Unable to update https://github.com/rust-lang/bitflags.git?rev=11111b376b93484341c68fbca3ca110ae5cd2790 Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/bitflags-[HASH] Caused by: revision 11111b376b93484341c68fbca3ca110ae5cd2790 not found ... "#]]) .run(); } #[cargo_test] fn git_worktree_with_bare_original_repo() { let project = project().build(); let git_project = git::new("foo", |project| { project .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] license = "MIR OR Apache-2.0" description = "A test!" homepage = "https://example.org" documentation = "" repository = "https://example.org" readme = "./README.md" "#, ) .file("src/lib.rs", "") .file("README.md", "") }); // Create a "bare" Git repository. // Keep the `.git` folder and delete the others. let repo = { let mut repo_builder = git2::build::RepoBuilder::new(); repo_builder .bare(true) .clone_local(git2::build::CloneLocal::Local) .clone( git_project.root().to_url().as_str(), &paths::root().join("foo-bare"), ) .unwrap() }; assert!(repo.is_bare()); let opts = git2::WorktreeAddOptions::new(); let wt = repo .worktree("bar", &paths::root().join("bar"), Some(&opts)) .unwrap(); project .cargo("package --list") .cwd(wt.path()) .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig README.md src/lib.rs "#]]) .run(); project .cargo("check") .cwd(wt.path()) .with_stderr_data(str![[r#" [CHECKING] foo v0.5.0 ([ROOT]/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] #[cfg(unix)] fn simple_with_fifo() { let git_project = git::new("foo", |project| { project .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") }); std::process::Command::new("mkfifo") .current_dir(git_project.root()) .arg(git_project.root().join("blocks-when-read")) .status() .expect("a FIFO can be created"); // Avoid actual blocking even in case of failure, assuming that what it lists here // would also be read eventually. git_project .cargo("package -l") .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); } cargo-0.86.0/tests/testsuite/git_auth.rs000064400000000000000000000336621046102023000163710ustar 00000000000000//! Tests for git authentication. use std::collections::HashSet; use std::io::prelude::*; use std::io::BufReader; use std::net::{SocketAddr, TcpListener}; use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use std::sync::Arc; use std::thread::{self, JoinHandle}; use cargo_test_support::basic_manifest; use cargo_test_support::git::cargo_uses_gitoxide; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::project; fn setup_failed_auth_test() -> (SocketAddr, JoinHandle<()>, Arc) { let server = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = server.local_addr().unwrap(); fn headers(rdr: &mut dyn BufRead) -> HashSet { let valid = ["GET", "Authorization", "Accept"]; rdr.lines() .map(|s| s.unwrap()) .take_while(|s| s.len() > 2) .map(|s| s.trim().to_string()) .filter(|s| valid.iter().any(|prefix| s.starts_with(*prefix))) .collect() } let connections = Arc::new(AtomicUsize::new(0)); let connections2 = connections.clone(); let t = thread::spawn(move || { let mut conn = BufReader::new(server.accept().unwrap().0); let req = headers(&mut conn); connections2.fetch_add(1, SeqCst); conn.get_mut() .write_all( b"HTTP/1.1 401 Unauthorized\r\n\ WWW-Authenticate: Basic realm=\"wheee\"\r\n\ Content-Length: 0\r\n\ \r\n", ) .unwrap(); assert_eq!( req, vec![ "GET /foo/bar/info/refs?service=git-upload-pack HTTP/1.1", "Accept: */*", ] .into_iter() .map(|s| s.to_string()) .collect() ); let req = headers(&mut conn); connections2.fetch_add(1, SeqCst); conn.get_mut() .write_all( b"HTTP/1.1 401 Unauthorized\r\n\ WWW-Authenticate: Basic realm=\"wheee\"\r\n\ \r\n", ) .unwrap(); assert_eq!( req, vec![ "GET /foo/bar/info/refs?service=git-upload-pack HTTP/1.1", "Authorization: Basic Zm9vOmJhcg==", "Accept: */*", ] .into_iter() .map(|s| s.to_string()) .collect() ); }); let script = project() .at("script") .file("Cargo.toml", &basic_manifest("script", "0.1.0")) .file( "src/main.rs", r#" fn main() { println!("username=foo"); println!("password=bar"); } "#, ) .build(); script.cargo("build -v").run(); let script = script.bin("script"); let config = paths::home().join(".gitconfig"); let mut config = git2::Config::open(&config).unwrap(); config .set_str( "credential.helper", // This is a bash script so replace `\` with `/` for Windows &script.display().to_string().replace("\\", "/"), ) .unwrap(); (addr, t, connections) } // Tests that HTTP auth is offered from `credential.helper`. #[cargo_test] fn http_auth_offered() { let (addr, t, connections) = setup_failed_auth_test(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] git = "http://127.0.0.1:{}/foo/bar" "#, addr.port() ), ) .file("src/main.rs", "") .file( ".cargo/config.toml", "[net] retry = 0 ", ) .build(); // This is a "contains" check because the last error differs by platform, // may span multiple lines, and isn't relevant to this test. p.cargo("check") .with_status(101) .with_stderr_data(&format!( "\ [UPDATING] git repository `http://{addr}/foo/bar` [ERROR] failed to get `bar` as a dependency of package `foo v0.0.1 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update http://{addr}/foo/bar Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/bar-[HASH] Caused by: failed to authenticate when downloading repository * attempted to find username/password via `credential.helper`, but maybe the found credentials were incorrect if the git CLI succeeds then `net.git-fetch-with-cli` may help here https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli Caused by: {trailer} ", trailer = if cargo_uses_gitoxide() { format!(r#"[CREDENTIAL]s provided for "http://{addr}/foo/bar" were not accepted by the remote Caused by: Received HTTP status 401"#) } else { " no authentication methods succeeded".to_string() } )) .run(); assert_eq!(connections.load(SeqCst), 2); t.join().ok().unwrap(); } // Boy, sure would be nice to have a TLS implementation in rust! #[cargo_test] fn https_something_happens() { let server = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = server.local_addr().unwrap(); let t = thread::spawn(move || { let mut conn = server.accept().unwrap().0; drop(conn.write(b"1234")); drop(conn.shutdown(std::net::Shutdown::Write)); drop(conn.read(&mut [0; 16])); }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] git = "https://127.0.0.1:{}/foo/bar" "#, addr.port() ), ) .file("src/main.rs", "") .file( ".cargo/config.toml", "[net] retry = 0 ", ) .build(); p.cargo("check -v") .with_status(101) .with_stderr_data(&format!( "\ [UPDATING] git repository `https://{addr}/foo/bar` [ERROR] failed to get `bar` as a dependency of package `foo v0.0.1 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update https://{addr}/foo/bar Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/bar-[HASH] Caused by: {errmsg} ", errmsg = if cargo_uses_gitoxide() { r" network failure seems to have happened if a proxy or similar is necessary `net.git-fetch-with-cli` may help here https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli Caused by: An IO error occurred when talking to the server Caused by: [35] SSL connect error ([..])" } else if cfg!(windows) { "[..]failed to send request: [..]\n..." } else if cfg!(target_os = "macos") { // macOS is difficult to tests as some builds may use Security.framework, // while others may use OpenSSL. In that case, let's just not verify the error // message here. "..." } else { "[..]SSL [ERROR][..]" } )) .run(); t.join().ok().unwrap(); } // It would sure be nice to have an SSH implementation in Rust! #[cargo_test] fn ssh_something_happens() { let server = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = server.local_addr().unwrap(); let t = thread::spawn(move || { drop(server.accept().unwrap()); }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] git = "ssh://127.0.0.1:{}/foo/bar" "#, addr.port() ), ) .file("src/main.rs", "") .build(); let expected = if cargo_uses_gitoxide() { // Due to the usage of `ssh` and `ssh.exe` respectively, the messages change. // This will be adjusted to use `ssh2` to get rid of this dependency and have uniform messaging. let message = if cfg!(windows) { // The order of multiple possible messages isn't deterministic within `ssh`, and `gitoxide` detects both // but gets to report only the first. Thus this test can flip-flop from one version of the error to the other // and we can't test for that. // We'd want to test for: // "[..]ssh: connect to host 127.0.0.1 [..]" // ssh: connect to host example.org port 22: No route to host // "[..]banner exchange: Connection to 127.0.0.1 [..]" // banner exchange: Connection to 127.0.0.1 port 62250: Software caused connection abort // But since there is no common meaningful sequence or word, we can only match a small telling sequence of characters. "[..]onnect[..]" } else { "[..]Connection [..] by [..]" }; format!( "\ [UPDATING] git repository `ssh://{addr}/foo/bar` ... {message} ... " ) } else { format!( "\ [UPDATING] git repository `ssh://{addr}/foo/bar` [ERROR] failed to get `bar` as a dependency of package `foo v0.0.1 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update ssh://{addr}/foo/bar Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/bar-[HASH] Caused by: network failure seems to have happened if a proxy or similar is necessary `net.git-fetch-with-cli` may help here https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli Caused by: failed to start SSH session: Failed getting banner; class=Ssh (23) " ) }; p.cargo("check -v") .with_status(101) .with_stderr_data(expected) .run(); t.join().ok().unwrap(); } #[cargo_test] fn net_err_suggests_fetch_with_cli() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [dependencies] foo = { git = "ssh://needs-proxy.invalid/git" } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -v") .with_status(101) .with_stderr_data(format!( "\ [UPDATING] git repository `ssh://needs-proxy.invalid/git` [WARNING] spurious network error (3 tries remaining): [..] resolve [..] needs-proxy.invalid: [..] known[..] [WARNING] spurious network error (2 tries remaining): [..] resolve [..] needs-proxy.invalid: [..] known[..] [WARNING] spurious network error (1 tries remaining): [..] resolve [..] needs-proxy.invalid: [..] known[..] [ERROR] failed to get `foo` as a dependency of package `foo v0.0.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `foo` Caused by: Unable to update ssh://needs-proxy.invalid/git Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/git-[HASH] Caused by: network failure seems to have happened if a proxy or similar is necessary `net.git-fetch-with-cli` may help here https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli Caused by: {trailer} ", trailer = if cargo_uses_gitoxide() { r" An IO error occurred when talking to the server Caused by: ssh: Could not resolve hostname needs-proxy.invalid[..]" } else { " failed to resolve address for needs-proxy.invalid: [..] known[..]; class=Net (12)" } )) .run(); p.change_file( ".cargo/config.toml", " [net] git-fetch-with-cli = true ", ); p.cargo("check -v") .with_status(101) .with_stderr_contains("[..]Unable to update[..]") .with_stderr_does_not_contain("[..]try enabling `git-fetch-with-cli`[..]") .run(); } #[cargo_test] fn instead_of_url_printed() { let (addr, t, _connections) = setup_failed_auth_test(); let config = paths::home().join(".gitconfig"); let mut config = git2::Config::open(&config).unwrap(); config .set_str( &format!("url.http://{}/.insteadOf", addr), "https://foo.bar/", ) .unwrap(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] git = "https://foo.bar/foo/bar" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(&format!( "\ [UPDATING] git repository `https://foo.bar/foo/bar` [ERROR] failed to get `bar` as a dependency of package `foo v0.0.1 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update https://foo.bar/foo/bar Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/bar-[HASH] Caused by: failed to authenticate when downloading repository: http://{addr}/foo/bar * attempted to find username/password via `credential.helper`, but maybe the found credentials were incorrect if the git CLI succeeds then `net.git-fetch-with-cli` may help here https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli Caused by: ... " )) .run(); t.join().ok().unwrap(); } cargo-0.86.0/tests/testsuite/git_gc.rs000064400000000000000000000061701046102023000160130ustar 00000000000000//! Tests for git garbage collection. use std::env; use std::ffi::OsStr; use std::path::PathBuf; use cargo_test_support::git; use cargo_test_support::git::cargo_uses_gitoxide; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry::Package; use url::Url; pub fn find_index() -> PathBuf { let dir = paths::home().join(".cargo/registry/index"); dir.read_dir().unwrap().next().unwrap().unwrap().path() } fn run_test(path_env: Option<&OsStr>) { const N: usize = 50; let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [dependencies] bar = "*" "#, ) .file("src/lib.rs", "") .build(); Package::new("bar", "0.1.0").publish(); foo.cargo("check").run(); let index = find_index(); let path = paths::home().join("tmp"); let url = Url::from_file_path(&path).unwrap().to_string(); let repo = git2::Repository::init(&path).unwrap(); let index = git2::Repository::open(&index).unwrap(); let mut cfg = repo.config().unwrap(); cfg.set_str("user.email", "foo@bar.com").unwrap(); cfg.set_str("user.name", "Foo Bar").unwrap(); let mut cfg = index.config().unwrap(); cfg.set_str("user.email", "foo@bar.com").unwrap(); cfg.set_str("user.name", "Foo Bar").unwrap(); for _ in 0..N { git::commit(&repo); index .remote_anonymous(&url) .unwrap() .fetch(&["refs/heads/master:refs/remotes/foo/master"], None, None) .unwrap(); } drop((repo, index)); Package::new("bar", "0.1.1").publish(); let before = find_index() .join(".git/objects/pack") .read_dir() .unwrap() .count(); assert!(before > N); let mut cmd = foo.cargo("update"); cmd.env("__CARGO_PACKFILE_LIMIT", "10"); if let Some(path) = path_env { cmd.env("PATH", path); } cmd.env("CARGO_LOG", "trace"); cmd.run(); let after = find_index() .join(".git/objects/pack") .read_dir() .unwrap() .count(); assert!( after < before, "packfiles before: {}\n\ packfiles after: {}", before, after ); } #[cargo_test(requires = "git")] fn use_git_gc() { run_test(None); } #[cargo_test] fn avoid_using_git() { if cargo_uses_gitoxide() { // file protocol without git binary is currently not possible - needs built-in upload-pack. // See https://github.com/Byron/gitoxide/issues/734 (support for the file protocol) progress updates. return; } let path = env::var_os("PATH").unwrap_or_default(); let mut paths = env::split_paths(&path).collect::>(); let idx = paths .iter() .position(|p| p.join("git").exists() || p.join("git.exe").exists()); match idx { Some(i) => { paths.remove(i); } None => return, } run_test(Some(&env::join_paths(&paths).unwrap())); } cargo-0.86.0/tests/testsuite/git_shallow.rs000064400000000000000000000604771046102023000171050ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{basic_manifest, git, paths, project}; use crate::git_gc::find_index; enum RepoMode { Shallow, Complete, } #[cargo_test] fn gitoxide_clones_shallow_two_revs_same_deps() { perform_two_revs_same_deps(true) } fn perform_two_revs_same_deps(shallow: bool) { let bar = git::new("meta-dep", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.0.0")) .file("src/lib.rs", "pub fn bar() -> i32 { 1 }") }); let repo = git2::Repository::open(&bar.root()).unwrap(); let rev1 = repo.revparse_single("HEAD").unwrap().id(); // Commit the changes and make sure we trigger a recompile bar.change_file("src/lib.rs", "pub fn bar() -> i32 { 2 }"); git::add(&repo); let rev2 = git::commit(&repo); let foo = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.0" authors = [] [dependencies.bar] git = '{}' rev = "{}" [dependencies.baz] path = "../baz" "#, bar.url(), rev1 ), ) .file( "src/main.rs", r#" extern crate bar; extern crate baz; fn main() { assert_eq!(bar::bar(), 1); assert_eq!(baz::baz(), 2); } "#, ) .build(); let _baz = project() .at("baz") .file( "Cargo.toml", &format!( r#" [package] name = "baz" version = "0.0.0" authors = [] [dependencies.bar] git = '{}' rev = "{}" "#, bar.url(), rev2 ), ) .file( "src/lib.rs", r#" extern crate bar; pub fn baz() -> i32 { bar::bar() } "#, ) .build(); let args = if shallow { "build -v -Zgitoxide=fetch -Zgit=shallow-deps" } else { "build -v" }; foo.cargo(args) .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]) .run(); assert!(foo.bin("foo").is_file()); foo.process(&foo.bin("foo")).run(); } #[cargo_test] fn two_revs_same_deps() { perform_two_revs_same_deps(false) } #[cargo_test] fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_with_git2_fetch( ) -> anyhow::Result<()> { Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-index") .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]) .run(); let shallow_repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; assert_eq!( shallow_repo .rev_parse_single("origin/HEAD")? .ancestors() .all()? .count(), 1, "shallow clones always start at depth of 1 to minimize download size" ); assert!(shallow_repo.is_shallow()); Package::new("bar", "1.1.0").publish(); p.cargo("update") .env("__CARGO_USE_GITOXIDE_INSTEAD_OF_GIT2", "0") .run(); let repo = gix::open_opts( find_remote_index(RepoMode::Complete), gix::open::Options::isolated(), )?; assert_eq!( repo.rev_parse_single("origin/HEAD")? .ancestors() .all()? .count(), 3, "an entirely new repo was cloned which is never shallow" ); assert!(!repo.is_shallow()); Ok(()) } #[cargo_test] fn gitoxide_clones_git_dependency_with_shallow_protocol_and_git2_is_used_for_followup_fetches( ) -> anyhow::Result<()> { // Example where an old lockfile with an explicit branch="master" in Cargo.toml. Package::new("bar", "1.0.0").publish(); let (bar, bar_repo) = git::new_repo("bar", |p| { p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) .file("src/lib.rs", "") }); bar.change_file("src/lib.rs", "// change"); git::add(&bar_repo); git::commit(&bar_repo); { let mut walk = bar_repo.revwalk()?; walk.push_head()?; assert_eq!( walk.count(), 2, "original repo has initial commit and change commit" ); } let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = {{ version = "1.0", git = "{}", branch = "master" }} "#, bar.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("update") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-deps") .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]) .run(); let db_clone = gix::open_opts( find_bar_db(RepoMode::Shallow), gix::open::Options::isolated(), )?; assert!(db_clone.is_shallow()); assert_eq!( db_clone .rev_parse_single("origin/master")? .ancestors() .all()? .count(), 1, "db clones are shallow and have a shortened history" ); let dep_checkout = gix::open_opts( find_lexicographically_first_bar_checkout(), gix::open::Options::isolated(), )?; assert!(dep_checkout.is_shallow()); assert_eq!( dep_checkout.head_id()?.ancestors().all()?.count(), 1, "db checkouts are hard-linked clones with the shallow file copied separately." ); bar.change_file("src/lib.rs", "// another change"); git::add(&bar_repo); git::commit(&bar_repo); { let mut walk = bar_repo.revwalk()?; walk.push_head()?; assert_eq!( walk.count(), 3, "original repo has initial commit and change commit, and another change" ); } p.cargo("update") .env("__CARGO_USE_GITOXIDE_INSTEAD_OF_GIT2", "0") .run(); let db_clone = gix::open_opts( find_bar_db(RepoMode::Complete), gix::open::Options::isolated(), )?; assert_eq!( db_clone .rev_parse_single("origin/master")? .ancestors() .all()? .count(), 3, "the db clone was re-initialized and has all commits" ); assert!( !db_clone.is_shallow(), "shallow-ness was removed as git2 does not support it" ); assert_eq!( dep_checkout.head_id()?.ancestors().all()?.count(), 1, "the original dep checkout didn't change - there is a new one for each update we get locally" ); let max_history_depth = glob::glob( paths::home() .join(".cargo/git/checkouts/bar-*/*/.git") .to_str() .unwrap(), )? .map(|path| -> anyhow::Result { let dep_checkout = gix::open_opts(path?, gix::open::Options::isolated())?; let depth = dep_checkout.head_id()?.ancestors().all()?.count(); assert_eq!(dep_checkout.is_shallow(), depth == 1, "the first checkout is done with gitoxide and shallow, the second one is git2 non-shallow"); Ok(depth) }) .map(Result::unwrap) .max() .expect("two checkout repos"); assert_eq!( max_history_depth, 3, "the new checkout sees all commits of the non-shallow DB repository" ); Ok(()) } #[cargo_test] fn gitoxide_shallow_clone_followed_by_non_shallow_update() -> anyhow::Result<()> { Package::new("bar", "1.0.0").publish(); let (bar, bar_repo) = git::new_repo("bar", |p| { p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) .file("src/lib.rs", "") }); bar.change_file("src/lib.rs", "// change"); git::add(&bar_repo); git::commit(&bar_repo); { let mut walk = bar_repo.revwalk()?; walk.push_head()?; assert_eq!( walk.count(), 2, "original repo has initial commit and change commit" ); } let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = {{ version = "1.0", git = "{}", branch = "master" }} "#, bar.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("update") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-deps") .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]) .run(); let shallow_db_clone = gix::open_opts( find_bar_db(RepoMode::Shallow), gix::open::Options::isolated(), )?; assert!(shallow_db_clone.is_shallow()); assert_eq!( shallow_db_clone .rev_parse_single("origin/master")? .ancestors() .all()? .count(), 1, "db clones are shallow and have a shortened history" ); let dep_checkout = gix::open_opts( find_lexicographically_first_bar_checkout(), gix::open::Options::isolated(), )?; assert!(dep_checkout.is_shallow()); assert_eq!( dep_checkout.head_id()?.ancestors().all()?.count(), 1, "db checkouts are hard-linked clones with the shallow file copied separately." ); bar.change_file("src/lib.rs", "// another change"); git::add(&bar_repo); git::commit(&bar_repo); { let mut walk = bar_repo.revwalk()?; walk.push_head()?; assert_eq!( walk.count(), 3, "original repo has initial commit and change commit, and another change" ); } p.cargo("update") .arg("-Zgitoxide=fetch") // shallow-deps is omitted intentionally .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) .run(); let db_clone = gix::open_opts( find_bar_db(RepoMode::Complete), gix::open::Options::isolated(), )?; assert_eq!( db_clone .rev_parse_single("origin/master")? .ancestors() .all()? .count(), 3, "we created an entirely new non-shallow clone" ); assert!(!db_clone.is_shallow()); assert_eq!( dep_checkout.head_id()?.ancestors().all()?.count(), 1, "the original dep checkout didn't change - there is a new one for each update we get locally" ); let max_history_depth = glob::glob( paths::home() .join(".cargo/git/checkouts/bar-*/*/.git") .to_str() .unwrap(), )? .map(|path| -> anyhow::Result { let path = path?; let dep_checkout = gix::open_opts(&path, gix::open::Options::isolated())?; assert_eq!( dep_checkout.is_shallow(), path.to_string_lossy().contains("-shallow"), "checkouts of shallow db repos are shallow as well" ); let depth = dep_checkout.head_id()?.ancestors().all()?.count(); Ok(depth) }) .map(Result::unwrap) .max() .expect("two checkout repos"); assert_eq!( max_history_depth, 3, "we see the previous shallow checkout as well as new unshallow one" ); Ok(()) } #[cargo_test] fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_fetch_maintains_shallowness( ) -> anyhow::Result<()> { Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-index") .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]) .run(); let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; assert_eq!( repo.rev_parse_single("origin/HEAD")? .ancestors() .all()? .count(), 1, "shallow clones always start at depth of 1 to minimize download size" ); assert!(repo.is_shallow()); Package::new("bar", "1.1.0").publish(); p.cargo("update") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-index") // NOTE: the flag needs to be consistent or else a different index is created .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]) .run(); assert_eq!( repo.rev_parse_single("origin/HEAD")? .ancestors() .all()? .count(), 1, "subsequent shallow fetches wont' fetch what's inbetween, only the single commit that we need while leveraging existing commits" ); assert!(repo.is_shallow()); Package::new("bar", "1.2.0").publish(); Package::new("bar", "1.3.0").publish(); p.cargo("update") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-index") .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]) .run(); assert_eq!( repo.rev_parse_single("origin/HEAD")? .ancestors() .all()? .count(), 1, "shallow boundaries are moved with each fetch to maintain only a single commit of history" ); assert!(repo.is_shallow()); Ok(()) } /// If there is shallow *and* non-shallow clones, non-shallow will naturally be returned due to sort order. #[cargo_test] fn gitoxide_clones_registry_without_shallow_protocol_and_follow_up_fetch_uses_shallowness( ) -> anyhow::Result<()> { Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .arg("-Zgitoxide=fetch") .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) .run(); let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; assert_eq!( repo.rev_parse_single("origin/HEAD")? .ancestors() .all()? .count(), 2, "initial commit and the first crate" ); assert!(!repo.is_shallow()); Package::new("bar", "1.1.0").publish(); p.cargo("update") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-index") .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]) .run(); let shallow_repo = gix::open_opts( find_remote_index(RepoMode::Shallow), gix::open::Options::isolated(), )?; assert_eq!( shallow_repo.rev_parse_single("origin/HEAD")? .ancestors() .all()? .count(), 1, "the follow up clones an entirely new index which is now shallow and which is in its own location" ); assert!(shallow_repo.is_shallow()); Package::new("bar", "1.2.0").publish(); Package::new("bar", "1.3.0").publish(); p.cargo("update") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-index") .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]) .run(); assert_eq!( shallow_repo .rev_parse_single("origin/HEAD")? .ancestors() .all()? .count(), 1, "subsequent shallow fetches wont' fetch what's inbetween, only the single commit that we need while leveraging existing commits" ); assert!(shallow_repo.is_shallow()); p.cargo("update") .arg("-Zgitoxide=fetch") .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) .run(); assert_eq!( repo.rev_parse_single("origin/HEAD")? .ancestors() .all()? .count(), 5, "we can separately fetch the non-shallow index as well and it sees all commits" ); Ok(()) } #[cargo_test] fn gitoxide_git_dependencies_switch_from_branch_to_rev() -> anyhow::Result<()> { // db exists from previous build, then dependency changes to refer to revision that isn't // available in the shallow clone. let (bar, bar_repo) = git::new_repo("bar", |p| { p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) .file("src/lib.rs", "") }); // this commit would not be available in a shallow clone. let first_commit_pre_change = bar_repo.head().unwrap().target().unwrap(); bar.change_file("src/lib.rs", "// change"); git::add(&bar_repo); git::commit(&bar_repo); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = {{ git = "{}", branch = "master" }} "#, bar.url(), ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-deps") .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]) .run(); let db_clone = gix::open_opts( find_bar_db(RepoMode::Shallow), gix::open::Options::isolated(), )?; assert!(db_clone.is_shallow()); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = {{ git = "{}", rev = "{}" }} "#, bar.url(), first_commit_pre_change ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-deps") .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]) .run(); assert!( db_clone.is_shallow(), "we maintain shallowness and never unshallow" ); Ok(()) } #[cargo_test] fn shallow_deps_work_with_revisions_and_branches_mixed_on_same_dependency() -> anyhow::Result<()> { let (bar, bar_repo) = git::new_repo("bar", |p| { p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) .file("src/lib.rs", "") }); // this commit would not be available in a shallow clone. let first_commit_pre_change = bar_repo.head().unwrap().target().unwrap(); bar.change_file("src/lib.rs", "// change"); git::add(&bar_repo); git::commit(&bar_repo); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] bar-renamed = {{ package = "bar", git = "{}", rev = "{}" }} bar = {{ git = "{}", branch = "master" }} "#, bar.url(), first_commit_pre_change, bar.url(), ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-deps") .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]) .run(); let db_paths = glob::glob(paths::home().join(".cargo/git/db/bar-*").to_str().unwrap())? .map(Result::unwrap) .collect::>(); assert_eq!( db_paths.len(), 1, "only one db checkout source is used per dependency" ); let db_clone = gix::open_opts(&db_paths[0], gix::open::Options::isolated())?; assert!( db_clone.is_shallow(), "the repo is shallow while having all data it needs" ); Ok(()) } #[cargo_test] fn gitoxide_clones_registry_with_shallow_protocol_and_aborts_and_updates_again( ) -> anyhow::Result<()> { Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-index") .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]) .run(); let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; assert_eq!( repo.rev_parse_single("origin/HEAD")? .ancestors() .all()? .count(), 1, "shallow clones always start at depth of 1 to minimize download size" ); assert!(repo.is_shallow()); let shallow_lock = repo.shallow_file().with_extension("lock"); // adding a lock file and deleting the original simulates a left-over clone that was aborted, leaving a lock file // in place without ever having moved it to the right location. std::fs::write(&shallow_lock, &[])?; std::fs::remove_file(repo.shallow_file())?; Package::new("bar", "1.1.0").publish(); p.cargo("update") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-index") .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]) .run(); assert!(!shallow_lock.is_file(), "the repository was re-initialized"); assert!(repo.is_shallow()); assert_eq!( repo.rev_parse_single("origin/HEAD")? .ancestors() .all()? .count(), 1, "it's a fresh shallow clone - otherwise it would have 2 commits if the previous shallow clone would still be present" ); Ok(()) } fn find_lexicographically_first_bar_checkout() -> std::path::PathBuf { glob::glob( paths::home() .join(".cargo/git/checkouts/bar-*/*/.git") .to_str() .unwrap(), ) .unwrap() .next() .unwrap() .unwrap() .to_owned() } fn find_remote_index(mode: RepoMode) -> std::path::PathBuf { glob::glob( paths::home() .join(".cargo/registry/index/*") .to_str() .unwrap(), ) .unwrap() .map(Result::unwrap) .filter(|p| p.to_string_lossy().ends_with("-shallow") == matches!(mode, RepoMode::Shallow)) .next() .unwrap() } /// Find a checkout directory for bar, `shallow` or not. fn find_bar_db(mode: RepoMode) -> std::path::PathBuf { glob::glob(paths::home().join(".cargo/git/db/bar-*").to_str().unwrap()) .unwrap() .map(Result::unwrap) .filter(|p| p.to_string_lossy().ends_with("-shallow") == matches!(mode, RepoMode::Shallow)) .next() .unwrap() .to_owned() } cargo-0.86.0/tests/testsuite/glob_targets.rs000064400000000000000000000323401046102023000172310ustar 00000000000000//! Tests for target filter flags with glob patterns. use cargo_test_support::prelude::*; use cargo_test_support::{project, str, Project}; #[cargo_test] fn build_example() { full_project() .cargo("build -v --example 'ex*1'") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name example1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_bin() { full_project() .cargo("build -v --bin 'bi*1'") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name bin1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_bench() { full_project() .cargo("build -v --bench 'be*1'") .with_stderr_data( str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]` [RUNNING] `rustc --crate-name bench1 [..]` [RUNNING] `rustc --crate-name bin2 [..]` [RUNNING] `rustc --crate-name bin1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn build_test() { full_project() .cargo("build -v --test 'te*1'") .with_stderr_data( str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name bin1 [..]` [RUNNING] `rustc --crate-name foo [..]` [RUNNING] `rustc --crate-name bin2 [..]` [RUNNING] `rustc --crate-name test1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn check_example() { full_project() .cargo("check -v --example 'ex*1'") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name example1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn check_bin() { full_project() .cargo("check -v --bin 'bi*1'") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name bin1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn check_bench() { full_project() .cargo("check -v --bench 'be*1'") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name bench1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn check_test() { full_project() .cargo("check -v --test 'te*1'") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name test1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn doc_bin() { full_project() .cargo("doc -v --bin 'bi*1'") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustdoc --edition=2015 --crate-type bin --crate-name bin1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/bin1/index.html "#]]) .run(); } #[cargo_test] fn fix_example() { full_project() .cargo("fix -v --example 'ex*1' --allow-no-vcs") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name example1 [..]` [FIXING] examples/example1.rs [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn fix_bin() { full_project() .cargo("fix -v --bin 'bi*1' --allow-no-vcs") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name bin1 [..]` [FIXING] src/bin/bin1.rs [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn fix_bench() { full_project() .cargo("fix -v --bench 'be*1' --allow-no-vcs") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name bench1 [..]` [FIXING] benches/bench1.rs [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn fix_test() { full_project() .cargo("fix -v --test 'te*1' --allow-no-vcs") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name test1 [..]` [FIXING] tests/test1.rs [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn run_example_and_bin() { let p = full_project(); p.cargo("run -v --bin 'bi*1'") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `cargo run` does not support glob patterns on target selection "#]]) .run(); p.cargo("run -v --example 'ex*1'") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `cargo run` does not support glob patterns on target selection "#]]) .run(); } #[cargo_test] fn test_example() { full_project() .cargo("test -v --example 'ex*1'") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name example1 [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/examples/example1-[HASH][EXE]` "#]]) .run(); } #[cargo_test] fn test_bin() { full_project() .cargo("test -v --bin 'bi*1'") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name bin1 [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/bin1-[HASH][EXE]` "#]]) .run(); } #[cargo_test] fn test_bench() { full_project() .cargo("test -v --bench 'be*1'") .with_stderr_data( str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name bin2 [..]` [RUNNING] `rustc --crate-name foo [..]` [RUNNING] `rustc --crate-name bench1 [..]` [RUNNING] `rustc --crate-name bin1 [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/bench1-[HASH][EXE]` "#]] .unordered(), ) .run(); } #[cargo_test] fn test_test() { full_project() .cargo("test -v --test 'te*1'") .with_stderr_data( str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name test1 [..]` [RUNNING] `rustc --crate-name bin1 [..]` [RUNNING] `rustc --crate-name foo [..]` [RUNNING] `rustc --crate-name bin2 [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/test1-[HASH][EXE]` "#]] .unordered(), ) .run(); } #[cargo_test] fn bench_example() { full_project() .cargo("bench -v --example 'ex*1'") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name example1 [..]` [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/release/examples/example1-[HASH][EXE] --bench` "#]]) .run(); } #[cargo_test] fn bench_bin() { full_project() .cargo("bench -v --bin 'bi*1'") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name bin1 [..]` [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/release/deps/bin1-[HASH][EXE] --bench` "#]]) .run(); } #[cargo_test] fn bench_bench() { full_project() .cargo("bench -v --bench 'be*1'") .with_stderr_data( str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name bin1 [..]` [RUNNING] `rustc --crate-name bin2 [..]` [RUNNING] `rustc --crate-name foo [..]` [RUNNING] `rustc --crate-name bench1 [..]` [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/release/deps/bench1-[HASH][EXE] --bench` "#]] .unordered(), ) .run(); } #[cargo_test] fn bench_test() { full_project() .cargo("bench -v --test 'te*1'") .with_stderr_data( str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name bin2 [..]` [RUNNING] `rustc --crate-name foo [..]` [RUNNING] `rustc --crate-name test1 [..]` [RUNNING] `rustc --crate-name bin1 [..]` [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/release/deps/test1-[HASH][EXE] --bench` "#]] .unordered(), ) .run(); } #[cargo_test] fn install_example() { full_project() .cargo("install --path . --example 'ex*1'") .with_stderr_data(str![[r#" [INSTALLING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/example1[EXE] [INSTALLED] package `foo v0.0.1 ([ROOT]/foo)` (executable `example1[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); } #[cargo_test] fn install_bin() { full_project() .cargo("install --path . --bin 'bi*1'") .with_stderr_data(str![[r#" [INSTALLING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/bin1[EXE] [INSTALLED] package `foo v0.0.1 ([ROOT]/foo)` (executable `bin1[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); } #[cargo_test] fn rustdoc_example() { full_project() .cargo("rustdoc -v --example 'ex*1'") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustdoc --edition=2015 --crate-type bin --crate-name example1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/example1/index.html "#]]) .run(); } #[cargo_test] fn rustdoc_bin() { full_project() .cargo("rustdoc -v --bin 'bi*1'") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustdoc --edition=2015 --crate-type bin --crate-name bin1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/bin1/index.html "#]]) .run(); } #[cargo_test] fn rustdoc_bench() { full_project() .cargo("rustdoc -v --bench 'be*1'") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustdoc --edition=2015 --crate-type bin --crate-name bench1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/bench1/index.html "#]]) .run(); } #[cargo_test] fn rustdoc_test() { full_project() .cargo("rustdoc -v --test 'te*1'") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustdoc --edition=2015 --crate-type bin --crate-name test1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/test1/index.html "#]]) .run(); } #[cargo_test] fn rustc_example() { full_project() .cargo("rustc -v --example 'ex*1'") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name example1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rustc_bin() { full_project() .cargo("rustc -v --bin 'bi*1'") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name bin1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rustc_bench() { full_project() .cargo("rustc -v --bench 'be*1'") .with_stderr_data( str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name bin1 [..]` [RUNNING] `rustc --crate-name bench1 [..]` [RUNNING] `rustc --crate-name bin2 [..]` [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn rustc_test() { full_project() .cargo("rustc -v --test 'te*1'") .with_stderr_data( str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name bin1 [..]` [RUNNING] `rustc --crate-name bin2 [..]` [RUNNING] `rustc --crate-name foo [..]` [RUNNING] `rustc --crate-name test1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } fn full_project() -> Project { project() .file("examples/example1.rs", "fn main() { }") .file("examples/example2.rs", "fn main() { }") .file("benches/bench1.rs", "") .file("benches/bench2.rs", "") .file("tests/test1.rs", "") .file("tests/test2.rs", "") .file("src/main.rs", "fn main() { }") .file("src/bin/bin1.rs", "fn main() { }") .file("src/bin/bin2.rs", "fn main() { }") .build() } cargo-0.86.0/tests/testsuite/global_cache_tracker.rs000064400000000000000000002052001046102023000206500ustar 00000000000000//! Tests for last-use tracking and auto-gc. //! //! Cargo supports an environment variable called `__CARGO_TEST_LAST_USE_NOW` //! to have cargo pretend that the current time is the given time (in seconds //! since the unix epoch). This is used throughout these tests to simulate //! what happens when time passes. The [`days_ago_unix`] and //! [`months_ago_unix`] functions help with setting this value. use std::env; use std::fmt::Write; use std::path::Path; use std::path::PathBuf; use std::process::Stdio; use std::sync::OnceLock; use std::time::{Duration, SystemTime}; use cargo::core::global_cache_tracker::{self, DeferredGlobalLastUse, GlobalCacheTracker}; use cargo::util::cache_lock::CacheLockMode; use cargo::util::interning::InternedString; use cargo::GlobalContext; use cargo_test_support::compare::assert_e2e; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::{Package, RegistryBuilder}; use cargo_test_support::{ basic_manifest, cargo_process, execs, git, process, project, retry, sleep_ms, str, thread_wait_timeout, Execs, Project, }; use itertools::Itertools; use super::config::GlobalContextBuilder; /// Helper to create a simple `foo` project which depends on a registry /// dependency called `bar`. fn basic_foo_bar_project() -> Project { Package::new("bar", "1.0.0").publish(); project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build() } /// Helper to get the names of files in a directory as strings. fn get_names(glob: &str) -> Vec { let mut names: Vec<_> = glob::glob(paths::home().join(glob).to_str().unwrap()) .unwrap() .map(|p| p.unwrap().file_name().unwrap().to_str().unwrap().to_owned()) .collect(); names.sort(); names } fn get_registry_names(which: &str) -> Vec { get_names(&format!(".cargo/registry/{which}/*/*")) } fn get_index_names() -> Vec { get_names(&format!(".cargo/registry/index/*")) } fn get_git_db_names() -> Vec { get_names(&format!(".cargo/git/db/*")) } fn get_git_checkout_names(db_name: &str) -> Vec { get_names(&format!(".cargo/git/checkouts/{db_name}/*")) } fn days_ago(n: u64) -> SystemTime { now() - Duration::from_secs(60 * 60 * 24 * n) } fn now() -> SystemTime { // This captures the time once to avoid potential time boundaries or // inconsistencies affecting a test. For example, on a fast system // `days_ago(1)` called twice in a row will return the same answer. // However, on a slower system, or if the clock happens to flip over from // one second to the next, then it would return different answers. This // ensures that it always returns the same answer. static START: OnceLock = OnceLock::new(); *START.get_or_init(|| SystemTime::now()) } /// Helper for simulating running cargo in the past. Use with the /// `__CARGO_TEST_LAST_USE_NOW` environment variable. fn days_ago_unix(n: u64) -> String { days_ago(n) .duration_since(SystemTime::UNIX_EPOCH) .unwrap() .as_secs() .to_string() } /// Helper for simulating running cargo in the past. Use with the /// `__CARGO_TEST_LAST_USE_NOW` environment variable. fn months_ago_unix(n: u64) -> String { days_ago_unix(n * 30) } /// Populates last-use database and the cache files. /// /// This makes it easier to more accurately specify exact sizes. Creating /// specific sizes with `Package` is too difficult. fn populate_cache( gctx: &GlobalContext, test_crates: &[(&str, u64, u64, u64)], ) -> (PathBuf, PathBuf) { let cache_dir = paths::home().join(".cargo/registry/cache/example.com-a6c4a5adcb232b9a"); let src_dir = paths::home().join(".cargo/registry/src/example.com-a6c4a5adcb232b9a"); GlobalCacheTracker::db_path(&gctx) .into_path_unlocked() .rm_rf(); let _lock = gctx .acquire_package_cache_lock(CacheLockMode::MutateExclusive) .unwrap(); let mut tracker = GlobalCacheTracker::new(&gctx).unwrap(); let mut deferred = DeferredGlobalLastUse::new(); cache_dir.rm_rf(); cache_dir.mkdir_p(); src_dir.rm_rf(); src_dir.mkdir_p(); paths::home() .join(".cargo/registry/index/example.com-a6c4a5adcb232b9a") .mkdir_p(); let mut create = |name: &str, age, crate_size: u64, src_size: u64| { let crate_filename = InternedString::new(&format!("{name}.crate")); deferred.mark_registry_crate_used_stamp( global_cache_tracker::RegistryCrate { encoded_registry_name: "example.com-a6c4a5adcb232b9a".into(), crate_filename, size: crate_size, }, Some(&days_ago(age)), ); deferred.mark_registry_src_used_stamp( global_cache_tracker::RegistrySrc { encoded_registry_name: "example.com-a6c4a5adcb232b9a".into(), package_dir: name.into(), size: Some(src_size), }, Some(&days_ago(age)), ); std::fs::write( cache_dir.join(crate_filename), "x".repeat(crate_size as usize), ) .unwrap(); let path = src_dir.join(name); path.mkdir_p(); std::fs::write(path.join("data"), "x".repeat(src_size as usize)).unwrap() }; for (name, age, crate_size, src_size) in test_crates { create(name, *age, *crate_size, *src_size); } deferred.save(&mut tracker).unwrap(); (cache_dir, src_dir) } /// Returns an `Execs` that will run the rustup `cargo` proxy from the global /// system's cargo home directory. fn rustup_cargo() -> Execs { // Modify the PATH to ensure that `cargo` and `rustc` comes from // CARGO_HOME. This is necessary because cargo adds the "deps" directory // into PATH on Windows, which points to the wrong cargo. let real_cargo_home_bin = Path::new(&std::env::var_os("CARGO_HOME").unwrap()).join("bin"); let mut paths = vec![real_cargo_home_bin]; paths.extend(env::split_paths(&env::var_os("PATH").unwrap_or_default())); let path = env::join_paths(paths).unwrap(); let mut e = execs().with_process_builder(process("cargo")); e.env("PATH", path); e } #[cargo_test] fn auto_gc_gated() { // Requires -Zgc to run auto-gc. let p = basic_foo_bar_project(); p.cargo("check") .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(4)) .run(); // Check that it created a database. let gctx = GlobalContextBuilder::new().build(); assert!(GlobalCacheTracker::db_path(&gctx) .into_path_unlocked() .exists()); assert_eq!(get_index_names().len(), 1); // Again in the future, shouldn't auto-gc. p.cargo("check").run(); assert_eq!(get_index_names().len(), 1); } #[cargo_test] fn clean_gc_gated() { cargo_process("clean gc") .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `cargo clean gc` command is unstable, and only available on the nightly channel of Cargo, but this is the `stable` channel See https://doc.rust-lang.org/book/appendix-07-nightly-rust.html for more information about Rust release channels. See https://github.com/rust-lang/cargo/issues/12633 for more information about the `cargo clean gc` command. "#]] ) .run(); } #[cargo_test] fn implies_source() { // Checks that when a src, crate, or checkout is marked as used, the // corresponding index or git db also gets marked as used. let gctx = GlobalContextBuilder::new().build(); let _lock = gctx .acquire_package_cache_lock(CacheLockMode::MutateExclusive) .unwrap(); let mut deferred = DeferredGlobalLastUse::new(); let mut tracker = GlobalCacheTracker::new(&gctx).unwrap(); deferred.mark_registry_crate_used(global_cache_tracker::RegistryCrate { encoded_registry_name: "example.com-a6c4a5adcb232b9a".into(), crate_filename: "regex-1.8.4.crate".into(), size: 123, }); deferred.mark_registry_src_used(global_cache_tracker::RegistrySrc { encoded_registry_name: "index.crates.io-6f17d22bba15001f".into(), package_dir: "rand-0.8.5".into(), size: None, }); deferred.mark_git_checkout_used(global_cache_tracker::GitCheckout { encoded_git_name: "cargo-e7ff1db891893a9e".into(), short_name: "f0a4ee0".into(), size: None, }); deferred.save(&mut tracker).unwrap(); let mut indexes = tracker.registry_index_all().unwrap(); assert_eq!(indexes.len(), 2); indexes.sort_by(|a, b| a.0.encoded_registry_name.cmp(&b.0.encoded_registry_name)); assert_eq!( indexes[0].0.encoded_registry_name, "example.com-a6c4a5adcb232b9a" ); assert_eq!( indexes[1].0.encoded_registry_name, "index.crates.io-6f17d22bba15001f" ); let dbs = tracker.git_db_all().unwrap(); assert_eq!(dbs.len(), 1); assert_eq!(dbs[0].0.encoded_git_name, "cargo-e7ff1db891893a9e"); } #[cargo_test] fn auto_gc_defaults() { // Checks that the auto-gc deletes old entries, and leaves new ones intact. Package::new("old", "1.0.0").publish(); Package::new("new", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] old = "1.0" new = "1.0" "#, ) .file("src/lib.rs", "") .build(); // Populate the last-use data. p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(4)) .run(); assert_eq!(get_registry_names("src"), ["new-1.0.0", "old-1.0.0"]); assert_eq!( get_registry_names("cache"), ["new-1.0.0.crate", "old-1.0.0.crate"] ); // Run again with just one package. Make sure the old src gets deleted, // but .crate does not. p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] new = "1.0" "#, ); p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(2)) .run(); assert_eq!(get_registry_names("src"), ["new-1.0.0"]); assert_eq!( get_registry_names("cache"), ["new-1.0.0.crate", "old-1.0.0.crate"] ); // Run again after the .crate should have aged out. p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .run(); assert_eq!(get_registry_names("src"), ["new-1.0.0"]); assert_eq!(get_registry_names("cache"), ["new-1.0.0.crate"]); } #[cargo_test] fn auto_gc_config() { // Can configure auto gc settings. Package::new("old", "1.0.0").publish(); Package::new("new", "1.0.0").publish(); let p = project() .file( ".cargo/config.toml", r#" [gc.auto] frequency = "always" max-src-age = "1 day" max-crate-age = "3 days" max-index-age = "3 days" max-git-co-age = "1 day" max-git-db-age = "3 days" "#, ) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] old = "1.0" new = "1.0" "#, ) .file("src/lib.rs", "") .build(); // Populate the last-use data. p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", days_ago_unix(4)) .run(); assert_eq!(get_registry_names("src"), ["new-1.0.0", "old-1.0.0"]); assert_eq!( get_registry_names("cache"), ["new-1.0.0.crate", "old-1.0.0.crate"] ); // Run again with just one package. Make sure the old src gets deleted, // but .crate does not. p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] new = "1.0" "#, ); p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", days_ago_unix(2)) .run(); assert_eq!(get_registry_names("src"), ["new-1.0.0"]); assert_eq!( get_registry_names("cache"), ["new-1.0.0.crate", "old-1.0.0.crate"] ); // Run again after the .crate should have aged out. p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .run(); assert_eq!(get_registry_names("src"), ["new-1.0.0"]); assert_eq!(get_registry_names("cache"), ["new-1.0.0.crate"]); } #[cargo_test] fn frequency() { // gc.auto.frequency settings let p = basic_foo_bar_project(); p.change_file( ".cargo/config.toml", r#" [gc.auto] frequency = "never" "#, ); // Populate data in the past. p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(4)) .run(); assert_eq!(get_index_names().len(), 1); assert_eq!(get_registry_names("src"), ["bar-1.0.0"]); assert_eq!(get_registry_names("cache"), ["bar-1.0.0.crate"]); p.change_file("Cargo.toml", &basic_manifest("foo", "0.2.0")); // Try after the default expiration time, with "never" it shouldn't gc. p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .run(); assert_eq!(get_index_names().len(), 1); assert_eq!(get_registry_names("src"), ["bar-1.0.0"]); assert_eq!(get_registry_names("cache"), ["bar-1.0.0.crate"]); // Try again with a setting that allows it to run. p.cargo("check -Zgc") .env("CARGO_GC_AUTO_FREQUENCY", "1 day") .masquerade_as_nightly_cargo(&["gc"]) .run(); assert_eq!(get_index_names().len(), 0); assert_eq!(get_registry_names("src").len(), 0); assert_eq!(get_registry_names("cache").len(), 0); } #[cargo_test] fn auto_gc_index() { // Deletes the index if it hasn't been used in a while. let p = basic_foo_bar_project(); p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(4)) .run(); assert_eq!(get_index_names().len(), 1); // Make sure it stays within the time frame. p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ); p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(2)) .run(); assert_eq!(get_index_names().len(), 1); // After it expires, it should be deleted. p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .run(); assert_eq!(get_index_names().len(), 0); } #[cargo_test] fn auto_gc_git() { // auto-gc should delete git checkouts and dbs. // Returns the short git name of a checkout. let short_id = |repo: &git2::Repository| -> String { let head = repo.revparse_single("HEAD").unwrap(); let short_id = head.short_id().unwrap(); short_id.as_str().unwrap().to_owned() }; // Set up a git dependency and fetch it and populate the database, // 6 months in the past. let (git_project, git_repo) = git::new_repo("bar", |p| { p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = {{ git = '{}' }} "#, git_project.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(6)) .run(); let db_names = get_git_db_names(); assert_eq!(db_names.len(), 1); let first_short_oid = short_id(&git_repo); assert_eq!( get_git_checkout_names(&db_names[0]), [first_short_oid.clone()] ); // Use a new git checkout, should keep both. git_project.change_file("src/lib.rs", "// modified"); git::add(&git_repo); git::commit(&git_repo); p.cargo("update -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(6)) .run(); assert_eq!(get_git_db_names().len(), 1); let second_short_oid = short_id(&git_repo); let mut both = vec![first_short_oid, second_short_oid.clone()]; both.sort(); assert_eq!(get_git_checkout_names(&db_names[0]), both); // In the future, using the second checkout should delete the first. p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(4)) .run(); assert_eq!(get_git_db_names().len(), 1); assert_eq!( get_git_checkout_names(&db_names[0]), [second_short_oid.clone()] ); // After three months, the db should get deleted. p.change_file("Cargo.toml", &basic_manifest("foo", "0.2.0")); p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .run(); assert_eq!(get_git_db_names().len(), 0); assert_eq!(get_git_checkout_names(&db_names[0]).len(), 0); } #[cargo_test] fn auto_gc_various_commands() { // Checks that auto gc works with a variety of commands. // // Auto-gc is only run on a subset of commands. Generally it is run on // commands that are already doing a lot of work, or heavily involve the // use of the registry. Package::new("bar", "1.0.0").publish(); let cmds = ["check", "fetch"]; for cmd in cmds { eprintln!("checking command {cmd}"); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); // Populate the last-use data. p.cargo(cmd) .arg("-Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(4)) .run(); let gctx = GlobalContextBuilder::new().build(); let lock = gctx .acquire_package_cache_lock(CacheLockMode::MutateExclusive) .unwrap(); let tracker = GlobalCacheTracker::new(&gctx).unwrap(); let indexes = tracker.registry_index_all().unwrap(); assert_eq!(indexes.len(), 1); let crates = tracker.registry_crate_all().unwrap(); assert_eq!(crates.len(), 1); let srcs = tracker.registry_src_all().unwrap(); assert_eq!(srcs.len(), 1); drop(lock); // After everything is aged out, it should all be deleted. p.change_file("Cargo.toml", &basic_manifest("foo", "0.2.0")); p.cargo(cmd) .arg("-Zgc") .masquerade_as_nightly_cargo(&["gc"]) .run(); let lock = gctx .acquire_package_cache_lock(CacheLockMode::MutateExclusive) .unwrap(); let indexes = tracker.registry_index_all().unwrap(); assert_eq!(indexes.len(), 0); let crates = tracker.registry_crate_all().unwrap(); assert_eq!(crates.len(), 0); let srcs = tracker.registry_src_all().unwrap(); assert_eq!(srcs.len(), 0); drop(tracker); drop(lock); paths::home().join(".cargo/registry").rm_rf(); GlobalCacheTracker::db_path(&gctx) .into_path_unlocked() .rm_rf(); } } #[cargo_test] fn updates_last_use_various_commands() { // Checks that last-use tracking is updated by various commands. // // Not *all* commands update the index tracking, even though they // technically involve reading the index. There isn't a convenient place // to ensure it gets saved while avoiding saving too often in other // commands. For the most part, this should be fine, since these commands // usually aren't run without running one of the commands that does save // the tracking. Some of the commands are: // // - login, owner, yank, search // - report future-incompatibilities // - package --no-verify // - fetch --locked Package::new("bar", "1.0.0").publish(); let cmds = [ // name, expected_crates (0=doesn't download) ("check", 1), ("fetch", 1), ("tree", 1), ("generate-lockfile", 0), ("update", 0), ("metadata", 1), ("vendor --respect-source-config", 1), ]; for (cmd, expected_crates) in cmds { eprintln!("checking command {cmd}"); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); // Populate the last-use data. p.cargo(cmd) .arg("-Zgc") .masquerade_as_nightly_cargo(&["gc"]) .run(); let gctx = GlobalContextBuilder::new().build(); let lock = gctx .acquire_package_cache_lock(CacheLockMode::MutateExclusive) .unwrap(); let tracker = GlobalCacheTracker::new(&gctx).unwrap(); let indexes = tracker.registry_index_all().unwrap(); assert_eq!(indexes.len(), 1); let crates = tracker.registry_crate_all().unwrap(); assert_eq!(crates.len(), expected_crates); let srcs = tracker.registry_src_all().unwrap(); assert_eq!(srcs.len(), expected_crates); drop(tracker); drop(lock); paths::home().join(".cargo/registry").rm_rf(); GlobalCacheTracker::db_path(&gctx) .into_path_unlocked() .rm_rf(); } } #[cargo_test] fn both_git_and_http_index_cleans() { // Checks that either the git or http index cache gets cleaned. let _crates_io = RegistryBuilder::new().build(); let _alternative = RegistryBuilder::new().alternative().http_index().build(); Package::new("from_git", "1.0.0").publish(); Package::new("from_http", "1.0.0") .alternative(true) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] from_git = "1.0" from_http = { version = "1.0", registry = "alternative" } "#, ) .file("src/lib.rs", "") .build(); p.cargo("update -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(4)) .run(); let gctx = GlobalContextBuilder::new().build(); let lock = gctx .acquire_package_cache_lock(CacheLockMode::MutateExclusive) .unwrap(); let tracker = GlobalCacheTracker::new(&gctx).unwrap(); let indexes = tracker.registry_index_all().unwrap(); assert_eq!(indexes.len(), 2); assert_eq!(get_index_names().len(), 2); drop(lock); // Running in the future without these indexes should delete them. p.change_file("Cargo.toml", &basic_manifest("foo", "0.2.0")); p.cargo("clean gc -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .run(); let lock = gctx .acquire_package_cache_lock(CacheLockMode::MutateExclusive) .unwrap(); let indexes = tracker.registry_index_all().unwrap(); assert_eq!(indexes.len(), 0); assert_eq!(get_index_names().len(), 0); drop(lock); } #[cargo_test] fn clean_gc_dry_run() { // Basic `clean --gc --dry-run` test. let p = basic_foo_bar_project(); // Populate the last-use data. p.cargo("fetch -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(4)) .run(); let registry_root = paths::home().join(".cargo/registry"); let glob_registry = |name| -> PathBuf { let mut paths: Vec<_> = glob::glob(registry_root.join(name).join("*").to_str().unwrap()) .unwrap() .map(|p| p.unwrap()) .collect(); assert_eq!(paths.len(), 1); paths.pop().unwrap() }; let index = glob_registry("index").ls_r(); let src = glob_registry("src").ls_r(); let cache = glob_registry("cache").ls_r(); let mut expected_files = index .iter() .chain(src.iter()) .chain(cache.iter()) .map(|p| p.to_str().unwrap()) .join("\n"); expected_files.push_str("\n"); let expected_files = snapbox::filter::normalize_paths(&expected_files); let expected_files = assert_e2e().redactions().redact(&expected_files); p.cargo("clean gc --dry-run -v -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .with_stdout_data(expected_files.as_str().unordered()) .with_stderr_data(str![[r#" [SUMMARY] [FILE_NUM] files, [FILE_SIZE]B total [WARNING] no files deleted due to --dry-run "#]]) .run(); // Again, make sure the information is still tracked. p.cargo("clean gc --dry-run -v -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .with_stdout_data(expected_files.as_str().unordered()) .with_stderr_data(str![[r#" [SUMMARY] [FILE_NUM] files, [FILE_SIZE]B total [WARNING] no files deleted due to --dry-run "#]]) .run(); } #[cargo_test] fn clean_default_gc() { // `clean gc` without options should also gc let p = basic_foo_bar_project(); // Populate the last-use data. p.cargo("fetch -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(4)) .run(); p.cargo("clean gc -v -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data( str![[r#" [REMOVING] [ROOT]/home/.cargo/registry/index/-[HASH] [REMOVING] [ROOT]/home/.cargo/registry/src/-[HASH] [REMOVING] [ROOT]/home/.cargo/registry/cache/-[HASH] [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]] .unordered(), ) .run(); } #[cargo_test] fn tracks_sizes() { // Checks that sizes are properly tracked in the db. Package::new("dep1", "1.0.0") .file("src/lib.rs", "") .publish(); Package::new("dep2", "1.0.0") .file("src/lib.rs", "") .file("data", &"abcdefghijklmnopqrstuvwxyz".repeat(1000)) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] dep1 = "1.0" dep2 = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .run(); // Check that the crate sizes are the same as on disk. let gctx = GlobalContextBuilder::new().build(); let _lock = gctx .acquire_package_cache_lock(CacheLockMode::MutateExclusive) .unwrap(); let tracker = GlobalCacheTracker::new(&gctx).unwrap(); let mut crates = tracker.registry_crate_all().unwrap(); crates.sort_by(|a, b| a.0.crate_filename.cmp(&b.0.crate_filename)); let db_sizes: Vec<_> = crates.iter().map(|c| c.0.size).collect(); let mut actual: Vec<_> = p .glob(paths::home().join(".cargo/registry/cache/*/*")) .map(|p| p.unwrap()) .collect(); actual.sort(); let actual_sizes: Vec<_> = actual .iter() .map(|path| std::fs::metadata(path).unwrap().len()) .collect(); assert_eq!(db_sizes, actual_sizes); // Also check the src sizes are computed. let mut srcs = tracker.registry_src_all().unwrap(); srcs.sort_by(|a, b| a.0.package_dir.cmp(&b.0.package_dir)); let db_sizes: Vec<_> = srcs.iter().map(|c| c.0.size.unwrap()).collect(); let mut actual: Vec<_> = p .glob(paths::home().join(".cargo/registry/src/*/*")) .map(|p| p.unwrap()) .collect(); actual.sort(); // .cargo-ok is not tracked in the size. actual.iter().for_each(|p| p.join(".cargo-ok").rm_rf()); let actual_sizes: Vec<_> = actual .iter() .map(|path| cargo_util::du(path, &[]).unwrap()) .collect(); assert_eq!(db_sizes, actual_sizes); assert!(db_sizes[1] > 26000); } #[cargo_test] fn max_size() { // Checks --max-crate-size and --max-src-size with various cleaning thresholds. let gctx = GlobalContextBuilder::new().build(); let test_crates = [ // name, age, crate_size, src_size ("a-1.0.0", 5, 1, 1), ("b-1.0.0", 6, 2, 2), ("c-1.0.0", 3, 3, 3), ("d-1.0.0", 2, 4, 4), ("e-1.0.0", 2, 5, 5), ("f-1.0.0", 9, 6, 6), ("g-1.0.0", 1, 1, 1), ]; // Determine the order things get deleted so they can be verified. let mut names_by_timestamp: Vec<_> = test_crates .iter() .map(|(name, age, _, _)| (days_ago_unix(*age), name)) .collect(); names_by_timestamp.sort(); let names_by_timestamp: Vec<_> = names_by_timestamp .into_iter() .map(|(_, name)| name) .collect(); // This exercises the different boundary conditions. for (clean_size, files) in [ (22, 0), (21, 1), (16, 1), (15, 2), (14, 2), (13, 3), (12, 4), (10, 4), (9, 5), (6, 5), (5, 6), (1, 6), (0, 7), ] { let (removed, kept) = names_by_timestamp.split_at(files); // --max-crate-size let (cache_dir, src_dir) = populate_cache(&gctx, &test_crates); let mut stderr = String::new(); for name in removed { writeln!(stderr, "[REMOVING] [..]{name}.crate").unwrap(); } let total_display = if removed.is_empty() { "" } else { ", [FILE_SIZE]B total" }; let files_display = if files == 0 { "0 files" } else if files == 1 { "1 file" } else { "[FILE_NUM] files" }; writeln!(stderr, "[REMOVED] {files_display}{total_display}").unwrap(); cargo_process(&format!("clean gc -Zgc -v --max-crate-size={clean_size}")) .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(stderr.unordered()) .run(); for name in kept { assert!(cache_dir.join(format!("{name}.crate")).exists()); } for name in removed { assert!(!cache_dir.join(format!("{name}.crate")).exists()); } // --max-src-size populate_cache(&gctx, &test_crates); let mut stderr = String::new(); for name in removed { writeln!(stderr, "[REMOVING] [..]{name}").unwrap(); } let total_display = if removed.is_empty() { "" } else { ", [FILE_SIZE]B total" }; writeln!(stderr, "[REMOVED] {files_display}{total_display}").unwrap(); cargo_process(&format!("clean gc -Zgc -v --max-src-size={clean_size}")) .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(stderr.unordered()) .run(); for name in kept { assert!(src_dir.join(name).exists()); } for name in removed { assert!(!src_dir.join(name).exists()); } } } #[cargo_test] fn max_size_untracked_crate() { // When a .crate file exists from an older version of cargo that did not // track sizes, `clean --max-crate-size` should populate the db with the // sizes. let gctx = GlobalContextBuilder::new().build(); let cache = paths::home().join(".cargo/registry/cache/example.com-a6c4a5adcb232b9a"); cache.mkdir_p(); paths::home() .join(".cargo/registry/index/example.com-a6c4a5adcb232b9a") .mkdir_p(); // Create the `.crate files. let test_crates = [ // name, size ("a-1.0.0.crate", 1234), ("b-1.0.0.crate", 42), ("c-1.0.0.crate", 0), ]; for (name, size) in test_crates { std::fs::write(cache.join(name), "x".repeat(size as usize)).unwrap() } // This should scan the directory and populate the db with the size information. cargo_process("clean gc -Zgc -v --max-crate-size=100000") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVED] 0 files "#]]) .run(); // Check that it stored the size data. let _lock = gctx .acquire_package_cache_lock(CacheLockMode::MutateExclusive) .unwrap(); let tracker = GlobalCacheTracker::new(&gctx).unwrap(); let crates = tracker.registry_crate_all().unwrap(); let mut actual: Vec<_> = crates .iter() .map(|(rc, _time)| (rc.crate_filename.as_str(), rc.size)) .collect(); actual.sort(); assert_eq!(test_crates, actual.as_slice()); } /// Helper to prepare the max-size test. fn max_size_untracked_prepare() -> (GlobalContext, Project) { // First, publish and download a dependency. let p = basic_foo_bar_project(); p.cargo("fetch").run(); // Pretend it was an older version that did not track last-use. let gctx = GlobalContextBuilder::new().build(); GlobalCacheTracker::db_path(&gctx) .into_path_unlocked() .rm_rf(); (gctx, p) } /// Helper to verify the max-size test. fn max_size_untracked_verify(gctx: &GlobalContext) { let actual: Vec<_> = glob::glob( paths::home() .join(".cargo/registry/src/*/*") .to_str() .unwrap(), ) .unwrap() .map(|p| p.unwrap()) .collect(); assert_eq!(actual.len(), 1); let actual_size = cargo_util::du(&actual[0], &[]).unwrap(); let lock = gctx .acquire_package_cache_lock(CacheLockMode::MutateExclusive) .unwrap(); let tracker = GlobalCacheTracker::new(&gctx).unwrap(); let srcs = tracker.registry_src_all().unwrap(); assert_eq!(srcs.len(), 1); assert_eq!(srcs[0].0.size, Some(actual_size)); drop(lock); } #[cargo_test] fn max_size_untracked_src_from_use() { // When a src directory exists from an older version of cargo that did not // track sizes, doing a build should populate the db with an entry with an // unknown size. `clean --max-src-size` should then fix the size. let (gctx, p) = max_size_untracked_prepare(); // Run a command that will update the db with an unknown src size. p.cargo("tree -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .run(); // Check that it is None. let lock = gctx .acquire_package_cache_lock(CacheLockMode::MutateExclusive) .unwrap(); let tracker = GlobalCacheTracker::new(&gctx).unwrap(); let srcs = tracker.registry_src_all().unwrap(); assert_eq!(srcs.len(), 1); assert_eq!(srcs[0].0.size, None); drop(lock); // Fix the size. p.cargo("clean gc -v --max-src-size=10000 -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVED] 0 files "#]]) .run(); max_size_untracked_verify(&gctx); } #[cargo_test] fn max_size_untracked_src_from_clean() { // When a src directory exists from an older version of cargo that did not // track sizes, `clean --max-src-size` should populate the db with the // sizes. let (gctx, p) = max_size_untracked_prepare(); // Clean should scan the src and update the db. p.cargo("clean gc -v --max-src-size=10000 -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVED] 0 files "#]]) .run(); max_size_untracked_verify(&gctx); } #[cargo_test] fn max_download_size() { // --max-download-size // // This creates some sample crates of specific sizes, and then tries // deleting at various specific size thresholds that exercise different // edge conditions. let gctx = GlobalContextBuilder::new().build(); let test_crates = [ // name, age, crate_size, src_size ("d-1.0.0", 4, 4, 5), ("c-1.0.0", 3, 3, 3), ("a-1.0.0", 1, 2, 5), ("b-1.0.0", 1, 1, 7), ]; for (max_size, num_deleted, files_deleted) in [ (30, 0, 0), (29, 1, 1), (24, 2, 2), (20, 3, 3), (1, 7, 7), (0, 8, 8), ] { populate_cache(&gctx, &test_crates); // Determine the order things will be deleted. let delete_order: Vec = test_crates .iter() .flat_map(|(name, _, _, _)| [name.to_string(), format!("{name}.crate")]) .collect(); let (removed, _kept) = delete_order.split_at(num_deleted); let mut stderr = String::new(); for name in removed { writeln!(stderr, "[REMOVING] [..]{name}").unwrap(); } let files_display = if files_deleted == 0 { "0 files" } else if files_deleted == 1 { "1 file" } else { "[FILE_NUM] files" }; let total_display = if removed.is_empty() { "" } else { ", [FILE_SIZE]B total" }; writeln!(stderr, "[REMOVED] {files_display}{total_display}",).unwrap(); cargo_process(&format!("clean gc -Zgc -v --max-download-size={max_size}")) .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(stderr.unordered()) .run(); } } #[cargo_test] fn package_cache_lock_during_build() { // Verifies that a shared lock is held during a build. Resolution and // downloads should be OK while that is held, but mutation should block. // // This works by launching a build with a build script that will pause. // Then it performs other cargo commands and verifies their behavior. Package::new("bar", "1.0.0").publish(); let p_foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { std::fs::write("blocking", "").unwrap(); let path = std::path::Path::new("ready"); loop { if path.exists() { break; } else { std::thread::sleep(std::time::Duration::from_millis(100)) } } } "#, ) .build(); let p_foo2 = project() .at("foo2") .file( "Cargo.toml", r#" [package] name = "foo2" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); // Start a build that will pause once the build starts. let mut foo_child = p_foo .cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .build_command() .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn() .unwrap(); // Wait for it to enter build script. retry(100, || p_foo.root().join("blocking").exists().then_some(())); // Start a build with a different target directory. It should not block, // even though it gets a download lock, and then a shared lock. // // Also verify that auto-gc gets disabled. p_foo2 .cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("CARGO_GC_AUTO_FREQUENCY", "always") .env("CARGO_LOG", "gc=debug") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [..]s DEBUG gc: unable to acquire mutate lock, auto gc disabled [CHECKING] bar v1.0.0 [CHECKING] foo2 v0.1.0 ([ROOT]/foo2) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Ensure that the first build really blocked. assert!(matches!(foo_child.try_wait(), Ok(None))); // Cleaning while a command is running should block. let mut clean_cmd = p_foo2 .cargo("clean gc --max-download-size=0 -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .build_command(); clean_cmd.stderr(Stdio::piped()); let mut clean_child = clean_cmd.spawn().unwrap(); // Give the clean command a chance to finish (it shouldn't). sleep_ms(500); // They should both still be running. assert!(matches!(foo_child.try_wait(), Ok(None))); assert!(matches!(clean_child.try_wait(), Ok(None))); // Let the original build finish. p_foo.change_file("ready", ""); // Wait for clean to finish. let thread = std::thread::spawn(|| clean_child.wait_with_output().unwrap()); let output = thread_wait_timeout(100, thread); assert!(output.status.success()); // Validate the output of the clean. execs() .with_stderr_data(str![[r#" [BLOCKING] waiting for file lock on package cache mutation [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run_output(&output); } #[cargo_test] fn read_only_locking_auto_gc() { // Tests the behavior for auto-gc on a read-only directory. let p = basic_foo_bar_project(); // Populate cache. p.cargo("fetch -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .run(); let cargo_home = paths::home().join(".cargo"); let mut perms = std::fs::metadata(&cargo_home).unwrap().permissions(); // Test when it can't update auto-gc db. perms.set_readonly(true); std::fs::set_permissions(&cargo_home, perms.clone()).unwrap(); p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [CHECKING] bar v1.0.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Try again without the last-use existing (such as if the cache was // populated by an older version of cargo). perms.set_readonly(false); std::fs::set_permissions(&cargo_home, perms.clone()).unwrap(); let gctx = GlobalContextBuilder::new().build(); GlobalCacheTracker::db_path(&gctx) .into_path_unlocked() .rm_rf(); perms.set_readonly(true); std::fs::set_permissions(&cargo_home, perms.clone()).unwrap(); p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); perms.set_readonly(false); std::fs::set_permissions(&cargo_home, perms).unwrap(); } #[cargo_test] fn delete_index_also_deletes_crates() { // Checks that when an index is delete that src and cache directories also get deleted. let p = basic_foo_bar_project(); p.cargo("fetch -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(4)) .run(); assert_eq!(get_registry_names("src"), ["bar-1.0.0"]); assert_eq!(get_registry_names("cache"), ["bar-1.0.0.crate"]); p.cargo("clean gc") .arg("--max-index-age=0 days") .arg("-Zgc") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); assert_eq!(get_registry_names("src").len(), 0); assert_eq!(get_registry_names("cache").len(), 0); } #[cargo_test] fn clean_syncs_missing_files() { // When files go missing in the cache, clean operations that need to track // the size should also remove them from the database. Package::new("bar", "1.0.0").publish(); Package::new("baz", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" baz = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .run(); // Verify things are tracked. let gctx = GlobalContextBuilder::new().build(); let lock = gctx .acquire_package_cache_lock(CacheLockMode::MutateExclusive) .unwrap(); let tracker = GlobalCacheTracker::new(&gctx).unwrap(); let crates = tracker.registry_crate_all().unwrap(); assert_eq!(crates.len(), 2); let srcs = tracker.registry_src_all().unwrap(); assert_eq!(srcs.len(), 2); drop(lock); // Remove the files. for pattern in [ ".cargo/registry/cache/*/bar-1.0.0.crate", ".cargo/registry/src/*/bar-1.0.0", ] { p.glob(paths::home().join(pattern)) .map(|p| p.unwrap()) .next() .unwrap() .rm_rf(); } // Clean should update the db. p.cargo("clean gc -v --max-download-size=1GB -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVED] 0 files "#]]) .run(); // Verify let crates = tracker.registry_crate_all().unwrap(); assert_eq!(crates.len(), 1); let srcs = tracker.registry_src_all().unwrap(); assert_eq!(srcs.len(), 1); } #[cargo_test] fn offline_doesnt_auto_gc() { // When running offline, auto-gc shouldn't run. let p = basic_foo_bar_project(); p.cargo("fetch -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(4)) .run(); // Remove the dependency. p.change_file("Cargo.toml", &basic_manifest("foo", "0.1.0")); // Run offline, make sure it doesn't delete anything p.cargo("check --offline -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert_eq!(get_registry_names("src"), ["bar-1.0.0"]); assert_eq!(get_registry_names("cache"), ["bar-1.0.0.crate"]); // Run online, make sure auto-gc runs. p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert_eq!(get_registry_names("src"), &[] as &[String]); assert_eq!(get_registry_names("cache"), &[] as &[String]); } #[cargo_test] fn can_handle_future_schema() -> anyhow::Result<()> { // It should work when a future version of cargo has made schema changes // to the database. let p = basic_foo_bar_project(); p.cargo("fetch -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(4)) .run(); // Modify the schema to pretend this is done by a future version of cargo. let gctx = GlobalContextBuilder::new().build(); let db_path = GlobalCacheTracker::db_path(&gctx).into_path_unlocked(); let conn = rusqlite::Connection::open(&db_path)?; let user_version: u32 = conn.query_row("SELECT user_version FROM pragma_user_version", [], |row| { row.get(0) })?; conn.execute("ALTER TABLE global_data ADD COLUMN foo DEFAULT 123", [])?; conn.pragma_update(None, "user_version", &(user_version + 1))?; drop(conn); // Verify it doesn't blow up. p.cargo("clean gc --max-download-size=0 -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); Ok(()) } #[cargo_test] fn clean_max_git_age() { // --max-git-*-age flags let (git_a, git_a_repo) = git::new_repo("git_a", |p| { p.file("Cargo.toml", &basic_manifest("git_a", "1.0.0")) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] git_a = {{ git = '{}' }} "#, git_a.url() ), ) .file("src/lib.rs", "") .build(); // Populate last-use tracking. p.cargo("fetch -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", days_ago_unix(4)) .run(); // Update git_a to create a separate checkout. git_a.change_file("src/lib.rs", "// test"); git::add(&git_a_repo); git::commit(&git_a_repo); // Update last-use tracking, where the first git checkout will stay "old". p.cargo("update -p git_a -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", days_ago_unix(2)) .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/git_a` [LOCKING] 1 package to latest compatible version [UPDATING] git_a v1.0.0 ([ROOTURL]/git_a#[..]) -> #[..] "#]]) .run(); let db_names = get_git_db_names(); assert_eq!(db_names.len(), 1); let db_name = &db_names[0]; let co_names = get_git_checkout_names(&db_name); assert_eq!(co_names.len(), 2); // Delete the first checkout p.cargo("clean gc -v -Zgc") .arg("--max-git-co-age=3 days") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/git/checkouts/git_a-[HASH]/[..] [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); let db_names = get_git_db_names(); assert_eq!(db_names.len(), 1); let co_names = get_git_checkout_names(&db_name); assert_eq!(co_names.len(), 1); // delete the second checkout p.cargo("clean gc -v -Zgc") .arg("--max-git-co-age=0 days") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/git/checkouts/git_a-[HASH]/[..] [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); let db_names = get_git_db_names(); assert_eq!(db_names.len(), 1); let co_names = get_git_checkout_names(&db_name); assert_eq!(co_names.len(), 0); // delete the db p.cargo("clean gc -v -Zgc") .arg("--max-git-db-age=1 days") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/git/db/git_a-[HASH] [REMOVING] [ROOT]/home/.cargo/git/checkouts/git_a-[HASH] [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); let db_names = get_git_db_names(); assert_eq!(db_names.len(), 0); let co_names = get_git_checkout_names(&db_name); assert_eq!(co_names.len(), 0); } #[cargo_test] fn clean_max_src_crate_age() { // --max-src-age and --max-crate-age flags let p = basic_foo_bar_project(); // Populate last-use tracking. p.cargo("fetch -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", days_ago_unix(4)) .run(); // Update bar to create a separate copy with a different timestamp. Package::new("bar", "1.0.1").publish(); p.cargo("update -p bar -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", days_ago_unix(2)) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] bar v1.0.0 -> v1.0.1 "#]]) .run(); p.cargo("fetch -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", days_ago_unix(2)) .with_stderr_data(str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.1 (registry `dummy-registry`) "#]]) .run(); assert_eq!(get_registry_names("src"), ["bar-1.0.0", "bar-1.0.1"]); assert_eq!( get_registry_names("cache"), ["bar-1.0.0.crate", "bar-1.0.1.crate"] ); // Delete the old src. p.cargo("clean gc -v -Zgc") .arg("--max-src-age=3 days") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/registry/src/-[HASH]/bar-1.0.0 [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); // delete the second src p.cargo("clean gc -v -Zgc") .arg("--max-src-age=0 days") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/registry/src/-[HASH]/bar-1.0.1 [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); // delete the old crate p.cargo("clean gc -v -Zgc") .arg("--max-crate-age=3 days") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/registry/cache/-[HASH]/bar-1.0.0.crate [REMOVED] 1 file, [FILE_SIZE]B total "#]]) .run(); // delete the seecond crate p.cargo("clean gc -v -Zgc") .arg("--max-crate-age=0 days") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/registry/cache/-[HASH]/bar-1.0.1.crate [REMOVED] 1 file, [FILE_SIZE]B total "#]]) .run(); } #[cargo_test] fn clean_max_git_size() { // clean --max-git-size // // Creates two checkouts. The sets a size threshold to delete one. And // then with 0 max size to delete everything. let (git_project, git_repo) = git::new_repo("bar", |p| { p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = {{ git = '{}' }} "#, git_project.url() ), ) .file("src/lib.rs", "") .build(); // Fetch and populate db. p.cargo("fetch -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", days_ago_unix(3)) .run(); // Figure out the name of the first checkout. let git_root = paths::home().join(".cargo/git"); let db_names = get_git_db_names(); assert_eq!(db_names.len(), 1); let db_name = &db_names[0]; let co_names = get_git_checkout_names(&db_name); assert_eq!(co_names.len(), 1); let first_co_name = &co_names[0]; // Make an update and create a new checkout. git_project.change_file("src/lib.rs", "// modified"); git::add(&git_repo); git::commit(&git_repo); p.cargo("update -Zgc") .masquerade_as_nightly_cargo(&["gc"]) // Use a different time so that the first checkout timestamp is less // than the second. .env("__CARGO_TEST_LAST_USE_NOW", days_ago_unix(2)) .run(); // Figure out the threshold to use. let mut co_names = get_git_checkout_names(&db_name); assert_eq!(co_names.len(), 2); co_names.retain(|name| name != first_co_name); assert_eq!(co_names.len(), 1); let second_co_name = &co_names[0]; let second_co_path = git_root .join("checkouts") .join(db_name) .join(second_co_name); let second_co_size = cargo_util::du(&second_co_path, &["!.git"]).unwrap(); let db_size = cargo_util::du(&git_root.join("db").join(db_name), &[]).unwrap(); let threshold = db_size + second_co_size; p.cargo(&format!("clean gc --max-git-size={threshold} -Zgc -v")) .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(&format!( "\ [REMOVING] [ROOT]/home/.cargo/git/checkouts/bar-[HASH]/{first_co_name} [REMOVED] [..] " )) .run(); // And then try cleaning everything. p.cargo("clean gc --max-git-size=0 -Zgc -v") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data( format!( "\ [REMOVING] [ROOT]/home/.cargo/git/checkouts/bar-[HASH]/{second_co_name} [REMOVING] [ROOT]/home/.cargo/git/db/bar-[HASH] [REMOVED] [..] " ) .unordered(), ) .run(); } // Helper for setting up fake git sizes for git size cleaning. fn setup_fake_git_sizes(db_name: &str, db_size: usize, co_sizes: &[usize]) { let base_git = paths::home().join(".cargo/git"); let db_path = base_git.join("db").join(db_name); db_path.mkdir_p(); std::fs::write(db_path.join("test"), "x".repeat(db_size)).unwrap(); let base_co = base_git.join("checkouts").join(db_name); for (i, size) in co_sizes.iter().enumerate() { let co_name = format!("co{i}"); let co_path = base_co.join(co_name); co_path.mkdir_p(); std::fs::write(co_path.join("test"), "x".repeat(*size)).unwrap(); } } #[cargo_test] fn clean_max_git_size_untracked() { // If there are git directories that aren't tracked in the database, // `--max-git-size` should pick it up. // // The db_name of "example" depends on the sorting order of the names ("e" // should be after "c"), so that the db comes after the checkouts. setup_fake_git_sizes("example", 5000, &[1000, 2000]); cargo_process(&format!("clean gc -Zgc -v --max-git-size=7000")) .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/git/checkouts/example/co0 [REMOVED] 1 file, [FILE_SIZE]B total "#]]) .run(); cargo_process(&format!("clean gc -Zgc -v --max-git-size=5000")) .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/git/checkouts/example/co1 [REMOVED] 1 file, [FILE_SIZE]B total "#]]) .run(); cargo_process(&format!("clean gc -Zgc -v --max-git-size=0")) .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/git/db/example [REMOVED] 1 file, [FILE_SIZE]B total "#]]) .run(); } #[cargo_test] fn clean_max_git_size_deletes_co_from_db() { // In the scenario where it thinks it needs to delete the db, it should // also delete all the checkouts. // // The db_name of "abc" depends on the sorting order of the names ("a" // should be before "c"), so that the db comes before the checkouts. setup_fake_git_sizes("abc", 5000, &[1000, 2000]); // This deletes everything because it tries to delete the db, which then // deletes all checkouts. cargo_process(&format!("clean gc -Zgc -v --max-git-size=3000")) .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/git/db/abc [REMOVING] [ROOT]/home/.cargo/git/checkouts/abc/co1 [REMOVING] [ROOT]/home/.cargo/git/checkouts/abc/co0 [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); } #[cargo_test] fn handles_missing_index() { // Checks behavior when index is missing. let p = basic_foo_bar_project(); p.cargo("fetch -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .run(); paths::home().join(".cargo/registry/index").rm_rf(); cargo_process("clean gc -v --max-download-size=0 -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data( str![[r#" [REMOVING] [ROOT]/home/.cargo/registry/cache/-[HASH] [REMOVING] [ROOT]/home/.cargo/registry/src/-[HASH] [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]] .unordered(), ) .run(); } #[cargo_test] fn handles_missing_git_db() { // Checks behavior when git db is missing. let git_project = git::new("bar", |p| { p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = {{ git = '{}' }} "#, git_project.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("fetch -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .run(); paths::home().join(".cargo/git/db").rm_rf(); cargo_process("clean gc -v --max-git-size=0 -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/git/checkouts/bar-[HASH] [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); } #[cargo_test] fn clean_gc_quiet_is_quiet() { // Checks that --quiet works with `cargo clean gc`, since there was a // subtle issue with how the flag is defined as a global flag. let p = basic_foo_bar_project(); p.cargo("fetch -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(4)) .run(); p.cargo("clean gc --quiet -Zgc --dry-run") .masquerade_as_nightly_cargo(&["gc"]) .with_stdout_data("") .with_stderr_data("") .run(); // Verify exact same command without -q would actually display something. p.cargo("clean gc -Zgc --dry-run") .masquerade_as_nightly_cargo(&["gc"]) .with_stdout_data("") .with_stderr_data(str![[r#" [SUMMARY] [FILE_NUM] files, [FILE_SIZE]B total [WARNING] no files deleted due to --dry-run "#]]) .run(); } #[cargo_test(requires_rustup_stable)] fn compatible_with_older_cargo() { // Ensures that db stays backwards compatible across versions. // T-4 months: Current version, build the database. Package::new("old", "1.0.0").publish(); Package::new("middle", "1.0.0").publish(); Package::new("new", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] old = "1.0" middle = "1.0" new = "1.0" "#, ) .file("src/lib.rs", "") .build(); // Populate the last-use data. p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(4)) .run(); assert_eq!( get_registry_names("src"), ["middle-1.0.0", "new-1.0.0", "old-1.0.0"] ); assert_eq!( get_registry_names("cache"), ["middle-1.0.0.crate", "new-1.0.0.crate", "old-1.0.0.crate"] ); // T-2 months: Stable version, make sure it reads and deletes old src. p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] new = "1.0" middle = "1.0" "#, ); rustup_cargo() .args(&["+stable", "check", "-Zgc"]) .cwd(p.root()) .masquerade_as_nightly_cargo(&["gc"]) .env("__CARGO_TEST_LAST_USE_NOW", months_ago_unix(2)) .run(); assert_eq!(get_registry_names("src"), ["middle-1.0.0", "new-1.0.0"]); assert_eq!( get_registry_names("cache"), // Duplicate crates from two different cache location // because we're changing how SourceId is hashed. // This change should be reverted once rust-lang/cargo#14917 lands. [ "middle-1.0.0.crate", "middle-1.0.0.crate", "new-1.0.0.crate", "new-1.0.0.crate", "old-1.0.0.crate" ] ); // T-0 months: Current version, make sure it can read data from stable, // deletes old crate and middle src. p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] new = "1.0" "#, ); p.cargo("check -Zgc") .masquerade_as_nightly_cargo(&["gc"]) .run(); assert_eq!(get_registry_names("src"), ["new-1.0.0"]); assert_eq!( get_registry_names("cache"), // Duplicate crates from two different cache location // because we're changing how SourceId is hashed. // This change should be reverted once rust-lang/cargo#14917 lands. ["middle-1.0.0.crate", "new-1.0.0.crate", "new-1.0.0.crate"] ); } #[cargo_test(requires_rustup_stable)] fn forward_compatible() { // Checks that db created in an older version can be read in a newer version. Package::new("bar", "1.0.0").publish(); let git_project = git::new("from_git", |p| { p.file("Cargo.toml", &basic_manifest("from_git", "1.0.0")) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" [dependencies] bar = "1.0.0" from_git = {{ git = '{}' }} "#, git_project.url() ), ) .file("src/lib.rs", "") .build(); rustup_cargo() .args(&["+stable", "check", "-Zgc"]) .cwd(p.root()) .masquerade_as_nightly_cargo(&["gc"]) .run(); let config = GlobalContextBuilder::new().build(); let lock = config .acquire_package_cache_lock(CacheLockMode::MutateExclusive) .unwrap(); let tracker = GlobalCacheTracker::new(&config).unwrap(); // Don't want to check the actual index name here, since although the // names are semi-stable, they might change over long periods of time. let indexes = tracker.registry_index_all().unwrap(); assert_eq!(indexes.len(), 1); let crates = tracker.registry_crate_all().unwrap(); let names: Vec<_> = crates .iter() .map(|(krate, _timestamp)| krate.crate_filename) .collect(); assert_eq!(names, &["bar-1.0.0.crate"]); let srcs = tracker.registry_src_all().unwrap(); let names: Vec<_> = srcs .iter() .map(|(src, _timestamp)| src.package_dir) .collect(); assert_eq!(names, &["bar-1.0.0"]); let dbs: Vec<_> = tracker.git_db_all().unwrap(); assert_eq!(dbs.len(), 1); let cos: Vec<_> = tracker.git_checkout_all().unwrap(); assert_eq!(cos.len(), 1); drop(lock); } cargo-0.86.0/tests/testsuite/help.rs000064400000000000000000000111511046102023000155020ustar 00000000000000//! Tests for cargo's help output. use std::fs; use std::path::Path; use std::str::from_utf8; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::{basic_manifest, cargo_process, paths, project}; #[cargo_test] fn help() { cargo_process("").run(); cargo_process("help").run(); cargo_process("-h").run(); cargo_process("help build").run(); cargo_process("build -h").run(); cargo_process("help help").run(); } #[cargo_test] fn help_external_subcommand() { // Check that `help external-subcommand` forwards the --help flag to the // given subcommand. Package::new("cargo-fake-help", "1.0.0") .file( "src/main.rs", r#" fn main() { if ::std::env::args().nth(2) == Some(String::from("--help")) { println!("fancy help output"); } } "#, ) .publish(); cargo_process("install cargo-fake-help").run(); cargo_process("help fake-help") .with_stdout_data(str![[r#" fancy help output "#]]) .run(); } fn help_with_man(display_command: &str) { // Build a "man" process that just echoes the contents. let p = project() .at(display_command) .file("Cargo.toml", &basic_manifest(display_command, "1.0.0")) .file( "src/main.rs", &r#" fn main() { eprintln!("custom __COMMAND__"); let path = std::env::args().skip(1).next().unwrap(); let mut f = std::fs::File::open(path).unwrap(); std::io::copy(&mut f, &mut std::io::stdout()).unwrap(); } "# .replace("__COMMAND__", display_command), ) .build(); p.cargo("build").run(); help_with_man_and_path(display_command, "build", "build", &p.target_debug_dir()); } fn help_with_man_and_path( display_command: &str, subcommand: &str, actual_subcommand: &str, path: &Path, ) { let contents = if display_command == "man" { fs::read_to_string(format!("src/etc/man/cargo-{}.1", actual_subcommand)).unwrap() } else { fs::read_to_string(format!( "src/doc/man/generated_txt/cargo-{}.txt", actual_subcommand )) .unwrap() }; let output = cargo_process(&format!("help {subcommand}")) .env("PATH", path) .run(); let stderr = from_utf8(&output.stderr).unwrap(); if display_command.is_empty() { assert_eq!(stderr, ""); } else { assert_eq!(stderr, format!("custom {}\n", display_command)); } let stdout = from_utf8(&output.stdout).unwrap(); assert_eq!(stdout, contents); } fn help_with_stdout_and_path(subcommand: &str, path: &Path) -> String { let output = cargo_process(&format!("help {subcommand}")) .env("PATH", path) .run(); let stderr = from_utf8(&output.stderr).unwrap(); assert_eq!(stderr, ""); let stdout = from_utf8(&output.stdout).unwrap(); stdout.to_string() } #[cargo_test] fn help_man() { // Checks that `help command` displays the man page using the given command. help_with_man("man"); help_with_man("less"); help_with_man("more"); // Check with no commands in PATH. help_with_man_and_path("", "build", "build", Path::new("")); } #[cargo_test] fn help_alias() { // Check that `help some_alias` will resolve. help_with_man_and_path("", "b", "build", Path::new("")); let config = paths::root().join(".cargo/config.toml"); fs::create_dir_all(config.parent().unwrap()).unwrap(); fs::write( config, r#" [alias] empty-alias = "" simple-alias = "build" complex-alias = ["build", "--release"] "#, ) .unwrap(); // The `empty-alias` returns an error. cargo_process("help empty-alias") .env("PATH", Path::new("")) .with_status(101) .with_stderr_data(str![[r#" [ERROR] no such command: `empty-alias` Did you mean `empty-alias`? View all installed commands with `cargo --list` Find a package to install `empty-alias` with `cargo search cargo-empty-alias` "#]]) .run(); // Because `simple-alias` aliases a subcommand with no arguments, help shows the manpage. help_with_man_and_path("", "simple-alias", "build", Path::new("")); // Help for `complex-alias` displays the full alias command. let out = help_with_stdout_and_path("complex-alias", Path::new("")); assert_eq!(out, "`complex-alias` is aliased to `build --release`\n"); } cargo-0.86.0/tests/testsuite/https.rs000064400000000000000000000121441046102023000157170ustar 00000000000000//! Network tests for https transport. //! //! Note that these tests will generally require setting `CARGO_CONTAINER_TESTS` //! or `CARGO_PUBLIC_NETWORK_TESTS`. use cargo_test_support::containers::Container; use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; #[cargo_test(container_test)] fn self_signed_should_fail() { // Cargo should not allow a connection to a self-signed certificate. let apache = Container::new("apache").launch(); let port = apache.port_mappings[&443]; let url = format!("https://127.0.0.1:{port}/repos/bar.git"); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = {{ git = "{url}" }} "# ), ) .file("src/lib.rs", "") .build(); // I think the text here depends on the curl backend. let err_msg = if cfg!(target_os = "macos") { "untrusted connection error; class=Ssl (16); code=Certificate (-17)" } else if cfg!(unix) { "the SSL certificate is invalid; class=Ssl (16)[..]" } else if cfg!(windows) { "user cancelled certificate check; class=Http (34); code=Certificate (-17)" } else { panic!("target not supported"); }; p.cargo("fetch") .with_status(101) .with_stderr_data(&format!( "\ [UPDATING] git repository `https://127.0.0.1:[..]/repos/bar.git` [ERROR] failed to get `bar` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update https://127.0.0.1:[..]/repos/bar.git Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/bar-[HASH] Caused by: network failure seems to have happened if a proxy or similar is necessary `net.git-fetch-with-cli` may help here https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli Caused by: {err_msg} " )) .run(); } #[cargo_test(container_test)] fn self_signed_with_cacert() { // When using cainfo, that should allow a connection to a self-signed cert. if cfg!(target_os = "macos") { // This test only seems to work with the // curl-sys/force-system-lib-on-osx feature enabled. For some reason // SecureTransport doesn't seem to like the self-signed certificate. // It works if the certificate is manually approved via Keychain // Access. The system libcurl is built with a LibreSSL fallback which // is used when CAINFO is set, which seems to work correctly. This // could use some more investigation. The official Rust binaries use // curl-sys/force-system-lib-on-osx so it is mostly an issue for local // testing. // // The error is: // [60] SSL peer certificate or SSH remote key was not OK (SSL: // certificate verification failed (result: 5)); class=Net (12) let curl_v = curl::Version::get(); if curl_v.vendored() { eprintln!( "vendored curl not supported on macOS, \ set curl-sys/force-system-lib-on-osx to enable" ); return; } } let apache = Container::new("apache").launch(); let port = apache.port_mappings[&443]; let url = format!("https://127.0.0.1:{port}/repos/bar.git"); let server_crt = apache.read_file("/usr/local/apache2/conf/server.crt"); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = {{ git = "{url}" }} "# ), ) .file("src/lib.rs", "") .file( ".cargo/config.toml", &format!( r#" [http] cainfo = "server.crt" "# ), ) .file("server.crt", &server_crt) .build(); p.cargo("fetch") .with_stderr_data(str![[r#" [UPDATING] git repository `https://127.0.0.1:[..]/repos/bar.git` [LOCKING] 1 package to latest compatible version "#]]) .run(); } #[cargo_test(public_network_test)] fn github_works() { // Check that an https connection to github.com works. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bitflags = { git = "https://github.com/rust-lang/bitflags.git", tag="1.3.2" } "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .with_stderr_data(str![[r#" [UPDATING] git repository `https://github.com/rust-lang/bitflags.git` [LOCKING] 1 package to latest compatible version "#]]) .run(); } cargo-0.86.0/tests/testsuite/inheritable_workspace_fields.rs000064400000000000000000001506711046102023000224570ustar 00000000000000//! Tests for inheriting Cargo.toml fields with field.workspace = true use cargo_test_support::prelude::*; use cargo_test_support::registry::{Dependency, Package, RegistryBuilder}; use cargo_test_support::{ basic_lib_manifest, basic_manifest, git, paths, project, publish, registry, str, }; #[cargo_test] fn permit_additional_workspace_fields() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] [workspace.package] version = "1.2.3" authors = ["Rustaceans"] description = "This is a crate" documentation = "https://www.rust-lang.org/learn" readme = "README.md" homepage = "https://www.rust-lang.org" repository = "https://github.com/example/example" license = "MIT" license-file = "LICENSE" keywords = ["cli"] categories = ["development-tools"] publish = false edition = "2018" rust-version = "1.60" exclude = ["foo.txt"] include = ["bar.txt", "**/*.rs", "Cargo.toml", "LICENSE", "README.md"] [workspace.dependencies] dep = "0.1" "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = ".." "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check") // Should not warn about unused fields. .with_stderr_data(str![[r#" [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check").run(); let lockfile = p.read_lockfile(); assert!(!lockfile.contains("dep")); } #[cargo_test] fn deny_optional_dependencies() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] [workspace.dependencies] dep1 = { version = "0.1", optional = true } "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = ".." "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: dep1 is optional, but workspace dependencies cannot be optional "#]]) .run(); } #[cargo_test] fn inherit_own_workspace_fields() { let registry = RegistryBuilder::new().http_api().http_index().build(); let p = project().build(); let _ = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "foo" version.workspace = true authors.workspace = true description.workspace = true documentation.workspace = true homepage.workspace = true repository.workspace = true license.workspace = true keywords.workspace = true categories.workspace = true publish.workspace = true edition.workspace = true rust-version.workspace = true exclude.workspace = true include.workspace = true [workspace] members = [] [workspace.package] version = "1.2.3" authors = ["Rustaceans"] description = "This is a crate" documentation = "https://www.rust-lang.org/learn" homepage = "https://www.rust-lang.org" repository = "https://github.com/example/example" license = "MIT" keywords = ["cli"] categories = ["development-tools"] publish = true edition = "2018" rust-version = "1.60" exclude = ["foo.txt"] include = ["bar.txt", "**/*.rs", "Cargo.toml"] "#, ) .file("src/main.rs", "fn main() {}") .file("foo.txt", "") // should be ignored when packaging .file("bar.txt", "") // should be included when packaging .build(); p.cargo("publish") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] both package.include and package.exclude are specified; the exclude list will be ignored [PACKAGING] foo v1.2.3 ([ROOT]/foo) [PACKAGED] 6 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v1.2.3 ([ROOT]/foo) [COMPILING] foo v1.2.3 ([ROOT]/foo/target/package/foo-1.2.3) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v1.2.3 ([ROOT]/foo) [UPLOADED] foo v1.2.3 to registry `crates-io` [NOTE] waiting for `foo v1.2.3` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v1.2.3 at registry `crates-io` "#]]) .run(); publish::validate_upload_with_contents( r#" { "authors": ["Rustaceans"], "badges": {}, "categories": ["development-tools"], "deps": [], "description": "This is a crate", "documentation": "https://www.rust-lang.org/learn", "features": {}, "homepage": "https://www.rust-lang.org", "keywords": ["cli"], "license": "MIT", "license_file": null, "links": null, "name": "foo", "readme": null, "readme_file": null, "repository": "https://github.com/example/example", "rust_version": "1.60", "vers": "1.2.3" } "#, "foo-1.2.3.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs", ".cargo_vcs_info.json", "bar.txt", ], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" rust-version = "1.60" name = "foo" version = "1.2.3" authors = ["Rustaceans"] build = false exclude = ["foo.txt"] include = [ "bar.txt", "**/*.rs", "Cargo.toml", ] publish = true autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "This is a crate" homepage = "https://www.rust-lang.org" documentation = "https://www.rust-lang.org/learn" readme = false keywords = ["cli"] categories = ["development-tools"] license = "MIT" repository = "https://github.com/example/example" [[bin]] name = "foo" path = "src/main.rs" "##]], )], ); } #[cargo_test] fn inherit_own_dependencies() { let registry = RegistryBuilder::new().http_api().http_index().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.2.0" edition = "2015" authors = [] [dependencies] dep.workspace = true [build-dependencies] dep-build.workspace = true [dev-dependencies] dep-dev.workspace = true [workspace] members = [] [workspace.dependencies] dep = "0.1" dep-build = "0.8" dep-dev = "0.5.2" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("dep", "0.1.2").publish(); Package::new("dep-build", "0.8.2").publish(); Package::new("dep-dev", "0.5.2").publish(); p.cargo("check") // Unordered because the download order is nondeterministic. .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 3 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] dep v0.1.2 (registry `dummy-registry`) [DOWNLOADED] dep-build v0.8.2 (registry `dummy-registry`) [CHECKING] dep v0.1.2 [CHECKING] bar v0.2.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); p.cargo("check").run(); let lockfile = p.read_lockfile(); assert!(lockfile.contains("dep")); assert!(lockfile.contains("dep-dev")); assert!(lockfile.contains("dep-build")); p.cargo("publish") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] bar v0.2.0 ([ROOT]/foo) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] bar v0.2.0 ([ROOT]/foo) [COMPILING] dep v0.1.2 [COMPILING] bar v0.2.0 ([ROOT]/foo/target/package/bar-0.2.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] bar v0.2.0 ([ROOT]/foo) [UPLOADED] bar v0.2.0 to registry `crates-io` [NOTE] waiting for `bar v0.2.0` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] bar v0.2.0 at registry `crates-io` "#]]) .run(); publish::validate_upload_with_contents( r#" { "authors": [], "badges": {}, "categories": [], "deps": [ { "default_features": true, "features": [], "kind": "normal", "name": "dep", "optional": false, "target": null, "version_req": "^0.1" }, { "default_features": true, "features": [], "kind": "dev", "name": "dep-dev", "optional": false, "target": null, "version_req": "^0.5.2" }, { "default_features": true, "features": [], "kind": "build", "name": "dep-build", "optional": false, "target": null, "version_req": "^0.8" } ], "description": null, "documentation": null, "features": {}, "homepage": null, "keywords": [], "license": null, "license_file": null, "links": null, "name": "bar", "readme": null, "readme_file": null, "repository": null, "rust_version": null, "vers": "0.2.0" } "#, "bar-0.2.0.crate", &["Cargo.toml", "Cargo.toml.orig", "Cargo.lock", "src/main.rs"], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "bar" version = "0.2.0" authors = [] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false readme = false [[bin]] name = "bar" path = "src/main.rs" [dependencies.dep] version = "0.1" [dev-dependencies.dep-dev] version = "0.5.2" [build-dependencies.dep-build] version = "0.8" "##]], )], ); } #[cargo_test] fn inherit_own_detailed_dependencies() { let registry = RegistryBuilder::new().http_api().http_index().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.2.0" edition = "2015" authors = [] [dependencies] dep.workspace = true [workspace] members = [] [workspace.dependencies] dep = { version = "0.1.2", features = ["testing"] } "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("dep", "0.1.2") .feature("testing", &vec![]) .publish(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] dep v0.1.2 (registry `dummy-registry`) [CHECKING] dep v0.1.2 [CHECKING] bar v0.2.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check").run(); let lockfile = p.read_lockfile(); assert!(lockfile.contains("dep")); p.cargo("publish") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] bar v0.2.0 ([ROOT]/foo) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] bar v0.2.0 ([ROOT]/foo) [COMPILING] dep v0.1.2 [COMPILING] bar v0.2.0 ([ROOT]/foo/target/package/bar-0.2.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] bar v0.2.0 ([ROOT]/foo) [UPLOADED] bar v0.2.0 to registry `crates-io` [NOTE] waiting for `bar v0.2.0` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] bar v0.2.0 at registry `crates-io` "#]]) .run(); publish::validate_upload_with_contents( r#" { "authors": [], "badges": {}, "categories": [], "deps": [ { "default_features": true, "features": ["testing"], "kind": "normal", "name": "dep", "optional": false, "target": null, "version_req": "^0.1.2" } ], "description": null, "documentation": null, "features": {}, "homepage": null, "keywords": [], "license": null, "license_file": null, "links": null, "name": "bar", "readme": null, "readme_file": null, "repository": null, "rust_version": null, "vers": "0.2.0" } "#, "bar-0.2.0.crate", &["Cargo.toml", "Cargo.toml.orig", "Cargo.lock", "src/main.rs"], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "bar" version = "0.2.0" authors = [] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false readme = false [[bin]] name = "bar" path = "src/main.rs" [dependencies.dep] version = "0.1.2" features = ["testing"] "##]], )], ); } #[cargo_test] fn inherit_from_own_undefined_field() { registry::init(); let p = project().build(); let _ = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "foo" version = "1.2.5" edition = "2015" authors = ["rustaceans"] description.workspace = true [workspace] members = [] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: error inheriting `description` from workspace root manifest's `workspace.package.description` Caused by: `workspace.package.description` was not defined "#]]) .run(); } #[cargo_test] fn inherited_dependencies_union_features() { Package::new("dep", "0.1.0") .feature("fancy", &["fancy_dep"]) .feature("dancy", &["dancy_dep"]) .add_dep(Dependency::new("fancy_dep", "0.2").optional(true)) .add_dep(Dependency::new("dancy_dep", "0.6").optional(true)) .file("src/lib.rs", "") .publish(); Package::new("fancy_dep", "0.2.4").publish(); Package::new("dancy_dep", "0.6.8").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.2.0" edition = "2015" authors = [] [dependencies] dep = { workspace = true, features = ["dancy"] } [workspace] members = [] [workspace.dependencies] dep = { version = "0.1", features = ["fancy"] } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 3 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] fancy_dep v0.2.4 (registry `dummy-registry`) [DOWNLOADED] dep v0.1.0 (registry `dummy-registry`) [DOWNLOADED] dancy_dep v0.6.8 (registry `dummy-registry`) [CHECKING] fancy_dep v0.2.4 [CHECKING] dancy_dep v0.6.8 [CHECKING] dep v0.1.0 [CHECKING] bar v0.2.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); let lockfile = p.read_lockfile(); assert!(lockfile.contains("dep")); assert!(lockfile.contains("fancy_dep")); assert!(lockfile.contains("dancy_dep")); } #[cargo_test] fn inherit_workspace_fields() { let registry = RegistryBuilder::new().http_api().http_index().build(); let p = project().build(); let _ = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [workspace] members = ["bar"] [workspace.package] version = "1.2.3" authors = ["Rustaceans"] description = "This is a crate" documentation = "https://www.rust-lang.org/learn" readme = "README.md" homepage = "https://www.rust-lang.org" repository = "https://github.com/example/example" license = "MIT" license-file = "LICENSE" keywords = ["cli"] categories = ["development-tools"] publish = true edition = "2018" rust-version = "1.60" exclude = ["foo.txt"] include = ["bar.txt", "**/*.rs", "Cargo.toml", "LICENSE", "README.md"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" workspace = ".." version.workspace = true authors.workspace = true description.workspace = true documentation.workspace = true readme.workspace = true homepage.workspace = true repository.workspace = true license.workspace = true license-file.workspace = true keywords.workspace = true categories.workspace = true publish.workspace = true edition.workspace = true rust-version.workspace = true exclude.workspace = true include.workspace = true "#, ) .file("LICENSE", "license") .file("README.md", "README.md") .file("bar/src/main.rs", "fn main() {}") .file("bar/foo.txt", "") // should be ignored when packaging .file("bar/bar.txt", "") // should be included when packaging .build(); p.cargo("publish") .replace_crates_io(registry.index_url()) .cwd("bar") .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] both package.include and package.exclude are specified; the exclude list will be ignored [PACKAGING] bar v1.2.3 ([ROOT]/foo/bar) [PACKAGED] 8 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] bar v1.2.3 ([ROOT]/foo/bar) [WARNING] only one of `license` or `license-file` is necessary `license` should be used if the package license can be expressed with a standard SPDX expression. `license-file` should be used if the package uses a non-standard license. See https://doc.rust-lang.org/cargo/reference/manifest.html#the-license-and-license-file-fields for more information. [COMPILING] bar v1.2.3 ([ROOT]/foo/target/package/bar-1.2.3) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] bar v1.2.3 ([ROOT]/foo/bar) [UPLOADED] bar v1.2.3 to registry `crates-io` [NOTE] waiting for `bar v1.2.3` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] bar v1.2.3 at registry `crates-io` "#]]) .run(); publish::validate_upload_with_contents( r#" { "authors": ["Rustaceans"], "badges": {}, "categories": ["development-tools"], "deps": [], "description": "This is a crate", "documentation": "https://www.rust-lang.org/learn", "features": {}, "homepage": "https://www.rust-lang.org", "keywords": ["cli"], "license": "MIT", "license_file": "LICENSE", "links": null, "name": "bar", "readme": "README.md", "readme_file": "README.md", "repository": "https://github.com/example/example", "rust_version": "1.60", "vers": "1.2.3" } "#, "bar-1.2.3.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs", "README.md", "LICENSE", ".cargo_vcs_info.json", "bar.txt", ], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" rust-version = "1.60" name = "bar" version = "1.2.3" authors = ["Rustaceans"] build = false exclude = ["foo.txt"] include = [ "bar.txt", "**/*.rs", "Cargo.toml", "LICENSE", "README.md", ] publish = true autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "This is a crate" homepage = "https://www.rust-lang.org" documentation = "https://www.rust-lang.org/learn" readme = "README.md" keywords = ["cli"] categories = ["development-tools"] license = "MIT" license-file = "LICENSE" repository = "https://github.com/example/example" [[bin]] name = "bar" path = "src/main.rs" "##]], )], ); } #[cargo_test] fn inherit_dependencies() { let registry = RegistryBuilder::new().http_api().http_index().build(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] [workspace.dependencies] dep = "0.1" dep-build = "0.8" dep-dev = "0.5.2" "#, ) .file( "bar/Cargo.toml", r#" [package] workspace = ".." name = "bar" version = "0.2.0" edition = "2015" authors = [] [dependencies] dep.workspace = true [build-dependencies] dep-build.workspace = true [dev-dependencies] dep-dev.workspace = true "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); Package::new("dep", "0.1.2").publish(); Package::new("dep-build", "0.8.2").publish(); Package::new("dep-dev", "0.5.2").publish(); p.cargo("check") // Unordered because the download order is nondeterministic. .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 3 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] dep v0.1.2 (registry `dummy-registry`) [DOWNLOADED] dep-build v0.8.2 (registry `dummy-registry`) [CHECKING] dep v0.1.2 [CHECKING] bar v0.2.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); p.cargo("check").run(); let lockfile = p.read_lockfile(); assert!(lockfile.contains("dep")); assert!(lockfile.contains("dep-dev")); assert!(lockfile.contains("dep-build")); p.cargo("publish") .replace_crates_io(registry.index_url()) .cwd("bar") .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] bar v0.2.0 ([ROOT]/foo/bar) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] bar v0.2.0 ([ROOT]/foo/bar) [COMPILING] dep v0.1.2 [COMPILING] bar v0.2.0 ([ROOT]/foo/target/package/bar-0.2.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] bar v0.2.0 ([ROOT]/foo/bar) [UPLOADED] bar v0.2.0 to registry `crates-io` [NOTE] waiting for `bar v0.2.0` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] bar v0.2.0 at registry `crates-io` "#]]) .run(); publish::validate_upload_with_contents( r#" { "authors": [], "badges": {}, "categories": [], "deps": [ { "default_features": true, "features": [], "kind": "normal", "name": "dep", "optional": false, "target": null, "version_req": "^0.1" }, { "default_features": true, "features": [], "kind": "dev", "name": "dep-dev", "optional": false, "target": null, "version_req": "^0.5.2" }, { "default_features": true, "features": [], "kind": "build", "name": "dep-build", "optional": false, "target": null, "version_req": "^0.8" } ], "description": null, "documentation": null, "features": {}, "homepage": null, "keywords": [], "license": null, "license_file": null, "links": null, "name": "bar", "readme": null, "readme_file": null, "repository": null, "rust_version": null, "vers": "0.2.0" } "#, "bar-0.2.0.crate", &["Cargo.toml", "Cargo.toml.orig", "Cargo.lock", "src/main.rs"], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "bar" version = "0.2.0" authors = [] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false readme = false [[bin]] name = "bar" path = "src/main.rs" [dependencies.dep] version = "0.1" [dev-dependencies.dep-dev] version = "0.5.2" [build-dependencies.dep-build] version = "0.8" "##]], )], ); } #[cargo_test] fn inherit_target_dependencies() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] [workspace.dependencies] dep = "0.1" "#, ) .file( "bar/Cargo.toml", r#" [package] workspace = ".." name = "bar" version = "0.2.0" edition = "2015" authors = [] [target.'cfg(unix)'.dependencies] dep.workspace = true [target.'cfg(windows)'.dependencies] dep.workspace = true "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); Package::new("dep", "0.1.2").publish(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] dep v0.1.2 (registry `dummy-registry`) [CHECKING] dep v0.1.2 [CHECKING] bar v0.2.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let lockfile = p.read_lockfile(); assert!(lockfile.contains("dep")); } #[cargo_test] fn inherit_dependency_override_optional() { Package::new("dep", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] [workspace.dependencies] dep = "0.1.0" "#, ) .file( "bar/Cargo.toml", r#" [package] workspace = ".." name = "bar" version = "0.2.0" edition = "2015" authors = [] [dependencies] dep = { workspace = true, optional = true } "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.2.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn inherit_dependency_features() { Package::new("dep", "0.1.0") .feature("fancy", &["fancy_dep"]) .add_dep(Dependency::new("fancy_dep", "0.2").optional(true)) .file("src/lib.rs", "") .publish(); Package::new("fancy_dep", "0.2.4").publish(); Package::new("dancy_dep", "0.6.8").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.2.0" edition = "2015" authors = [] [dependencies] dep = { workspace = true, features = ["fancy"] } [workspace] members = [] [workspace.dependencies] dep = "0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] fancy_dep v0.2.4 (registry `dummy-registry`) [DOWNLOADED] dep v0.1.0 (registry `dummy-registry`) [CHECKING] fancy_dep v0.2.4 [CHECKING] dep v0.1.0 [CHECKING] bar v0.2.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let lockfile = p.read_lockfile(); assert!(lockfile.contains("dep")); assert!(lockfile.contains("fancy_dep")); } #[cargo_test] fn inherit_detailed_dependencies() { let git_project = git::new("detailed", |project| { project .file("Cargo.toml", &basic_lib_manifest("detailed")) .file( "src/detailed.rs", r#" pub fn hello() -> &'static str { "hello world" } "#, ) }); // Make a new branch based on the current HEAD commit let repo = git2::Repository::open(&git_project.root()).unwrap(); let head = repo.head().unwrap().target().unwrap(); let head = repo.find_commit(head).unwrap(); repo.branch("branchy", &head, true).unwrap(); let p = project() .file( "Cargo.toml", &format!( r#" [workspace] members = ["bar"] [workspace.dependencies] detailed = {{ git = '{}', branch = "branchy" }} "#, git_project.url() ), ) .file( "bar/Cargo.toml", r#" [package] workspace = ".." name = "bar" version = "0.2.0" edition = "2015" authors = [] [dependencies] detailed.workspace = true "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/detailed` [LOCKING] 1 package to latest compatible version [CHECKING] detailed v0.5.0 ([ROOTURL]/detailed?branch=branchy#[..]) [CHECKING] bar v0.2.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn inherit_path_dependencies() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] [workspace.dependencies] dep = { path = "dep" } "#, ) .file( "bar/Cargo.toml", r#" [package] workspace = ".." name = "bar" version = "0.2.0" edition = "2015" authors = [] [dependencies] dep.workspace = true "#, ) .file("bar/src/main.rs", "fn main() {}") .file("dep/Cargo.toml", &basic_manifest("dep", "0.9.0")) .file("dep/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] dep v0.9.0 ([ROOT]/foo/dep) [CHECKING] bar v0.2.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let lockfile = p.read_lockfile(); assert!(lockfile.contains("dep")); } #[cargo_test] fn error_workspace_false() { registry::init(); let p = project().build(); let _ = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" workspace = ".." version = "1.2.3" edition = "2015" authors = ["rustaceans"] description = { workspace = false } "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check") .cwd("bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `workspace` cannot be false --> Cargo.toml:8:41 | 8 | description = { workspace = false } | ^^^^^ | "#]]) .run(); } #[cargo_test] fn error_workspace_dependency_looked_for_workspace_itself() { registry::init(); let p = project().build(); let _ = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "bar" version = "1.2.3" edition = "2015" [dependencies] dep.workspace = true [workspace] members = [] [workspace.dependencies] dep.workspace = true "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: dependency (dep) specified without providing a local path, Git repository, version, or workspace dependency to use "#]]) .run(); } #[cargo_test] fn error_malformed_workspace_root() { registry::init(); let p = project().build(); let _ = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [workspace] members = [invalid toml "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" workspace = ".." version = "1.2.3" edition = "2015" authors = ["rustaceans"] "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check") .cwd("bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid array expected `]` --> ../Cargo.toml:3:24 | 3 | members = [invalid toml | ^ | "#]]) .run(); } #[cargo_test] fn error_no_root_workspace() { registry::init(); let p = project().build(); let _ = git::repo(&paths::root().join("foo")) .file( "bar/Cargo.toml", r#" [package] name = "bar" workspace = ".." version = "1.2.3" edition = "2015" authors = ["rustaceans"] description.workspace = true "#, ) .file("src/main.rs", "fn main() {}") .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check") .cwd("bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/bar/Cargo.toml` Caused by: error inheriting `description` from workspace root manifest's `workspace.package.description` Caused by: root of a workspace inferred but wasn't a root: [ROOT]/foo/Cargo.toml "#]]) .run(); } #[cargo_test] fn error_inherit_unspecified_dependency() { let p = project().build(); let _ = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" workspace = ".." version = "1.2.3" edition = "2015" authors = ["rustaceans"] [dependencies] foo.workspace = true "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check") .cwd("bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/bar/Cargo.toml` Caused by: error inheriting `foo` from workspace root manifest's `workspace.dependencies.foo` Caused by: `workspace.dependencies` was not defined "#]]) .run(); } #[cargo_test] fn warn_inherit_def_feat_true_member_def_feat_false() { Package::new("dep", "0.1.0") .feature("default", &["fancy_dep"]) .add_dep(Dependency::new("fancy_dep", "0.2").optional(true)) .file("src/lib.rs", "") .publish(); Package::new("fancy_dep", "0.2.4").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.2.0" edition = "2015" authors = [] [dependencies] dep = { workspace = true, default-features = false } [workspace] members = [] [workspace.dependencies] dep = { version = "0.1.0", default-features = true } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] [ROOT]/foo/Cargo.toml: `default-features` is ignored for dep, since `default-features` was true for `workspace.dependencies.dep`, this could become a hard error in the future [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] fancy_dep v0.2.4 (registry `dummy-registry`) [DOWNLOADED] dep v0.1.0 (registry `dummy-registry`) [CHECKING] fancy_dep v0.2.4 [CHECKING] dep v0.1.0 [CHECKING] bar v0.2.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn warn_inherit_def_feat_true_member_def_feat_false_2024_edition() { Package::new("dep", "0.1.0") .feature("default", &["fancy_dep"]) .add_dep(Dependency::new("fancy_dep", "0.2").optional(true)) .file("src/lib.rs", "") .publish(); Package::new("fancy_dep", "0.2.4").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.2.0" edition = "2024" authors = [] [dependencies] dep = { workspace = true, default-features = false } [workspace] members = [] [workspace.dependencies] dep = { version = "0.1.0", default-features = true } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: error inheriting `dep` from workspace root manifest's `workspace.dependencies.dep` Caused by: `default-features = false` cannot override workspace's `default-features` "#]]) .run(); } #[cargo_test] fn warn_inherit_simple_member_def_feat_false() { Package::new("dep", "0.1.0") .feature("default", &["fancy_dep"]) .add_dep(Dependency::new("fancy_dep", "0.2").optional(true)) .file("src/lib.rs", "") .publish(); Package::new("fancy_dep", "0.2.4").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.2.0" edition = "2015" authors = [] [dependencies] dep = { workspace = true, default-features = false } [workspace] members = [] [workspace.dependencies] dep = "0.1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] [ROOT]/foo/Cargo.toml: `default-features` is ignored for dep, since `default-features` was not specified for `workspace.dependencies.dep`, this could become a hard error in the future [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] fancy_dep v0.2.4 (registry `dummy-registry`) [DOWNLOADED] dep v0.1.0 (registry `dummy-registry`) [CHECKING] fancy_dep v0.2.4 [CHECKING] dep v0.1.0 [CHECKING] bar v0.2.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn warn_inherit_simple_member_def_feat_false_2024_edition() { Package::new("dep", "0.1.0") .feature("default", &["fancy_dep"]) .add_dep(Dependency::new("fancy_dep", "0.2").optional(true)) .file("src/lib.rs", "") .publish(); Package::new("fancy_dep", "0.2.4").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.2.0" edition = "2024" authors = [] [dependencies] dep = { workspace = true, default-features = false } [workspace] members = [] [workspace.dependencies] dep = "0.1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: error inheriting `dep` from workspace root manifest's `workspace.dependencies.dep` Caused by: `default-features = false` cannot override workspace's `default-features` "#]]) .run(); } #[cargo_test] fn inherit_def_feat_false_member_def_feat_true() { Package::new("dep", "0.1.0") .feature("default", &["fancy_dep"]) .add_dep(Dependency::new("fancy_dep", "0.2").optional(true)) .file("src/lib.rs", "") .publish(); Package::new("fancy_dep", "0.2.4").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.2.0" edition = "2015" authors = [] [dependencies] dep = { workspace = true, default-features = true } [workspace] members = [] [workspace.dependencies] dep = { version = "0.1.0", default-features = false } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] fancy_dep v0.2.4 (registry `dummy-registry`) [DOWNLOADED] dep v0.1.0 (registry `dummy-registry`) [CHECKING] fancy_dep v0.2.4 [CHECKING] dep v0.1.0 [CHECKING] bar v0.2.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cannot_inherit_in_patch() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = [] [workspace.dependencies] bar = { path = "bar" } [package] name = "foo" version = "0.2.0" edition = "2015" [patch.crates-io] bar.workspace = true [dependencies] bar = "0.1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: dependency (bar) specified without providing a local path, Git repository, version, or workspace dependency to use "#]]) .run(); } #[cargo_test] fn warn_inherit_unused_manifest_key_dep() { Package::new("dep", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = [] [workspace.dependencies] dep = { version = "0.1", wxz = "wxz" } [package] name = "bar" version = "0.2.0" edition = "2015" authors = [] [dependencies] dep = { workspace = true, wxz = "wxz" } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: workspace.dependencies.dep.wxz [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: dependencies.dep.wxz [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] dep v0.1.0 (registry `dummy-registry`) [CHECKING] dep v0.1.0 [CHECKING] bar v0.2.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn warn_unused_workspace_package_field() { Package::new("dep", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = [] [workspace.package] name = "unused" [package] name = "foo" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: workspace.package.name [CHECKING] foo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn warn_inherit_unused_manifest_key_package() { Package::new("dep", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = [] [workspace.package] version = "1.2.3" authors = ["Rustaceans"] description = "This is a crate" documentation = "https://www.rust-lang.org/learn" homepage = "https://www.rust-lang.org" repository = "https://github.com/example/example" license = "MIT" keywords = ["cli"] categories = ["development-tools"] publish = true edition = "2018" rust-version = "1.60" exclude = ["foo.txt"] include = ["bar.txt", "**/*.rs", "Cargo.toml"] [package] name = "bar" version = { workspace = true, xyz = "abc"} authors = { workspace = true, xyz = "abc"} description = { workspace = true, xyz = "abc"} documentation = { workspace = true, xyz = "abc"} homepage = { workspace = true, xyz = "abc"} repository = { workspace = true, xyz = "abc"} license = { workspace = true, xyz = "abc"} keywords = { workspace = true, xyz = "abc"} categories = { workspace = true, xyz = "abc"} publish = { workspace = true, xyz = "abc"} edition = { workspace = true, xyz = "abc"} rust-version = { workspace = true, xyz = "abc"} exclude = { workspace = true, xyz = "abc"} include = { workspace = true, xyz = "abc"} "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: package.authors.xyz [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: package.categories.xyz [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: package.description.xyz [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: package.documentation.xyz [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: package.edition.xyz [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: package.exclude.xyz [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: package.homepage.xyz [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: package.include.xyz [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: package.keywords.xyz [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: package.license.xyz [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: package.publish.xyz [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: package.repository.xyz [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: package.rust-version.xyz [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: package.version.xyz [CHECKING] bar v1.2.3 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/install.rs000064400000000000000000002432231046102023000162270ustar 00000000000000//! Tests for the `cargo install` command. use std::env; use std::fs::{self, OpenOptions}; use std::io::prelude::*; use std::path::Path; use std::path::PathBuf; use std::thread; use cargo_test_support::compare::assert_e2e; use cargo_test_support::cross_compile; use cargo_test_support::git; use cargo_test_support::prelude::*; use cargo_test_support::registry::{self, Package}; use cargo_test_support::str; use cargo_test_support::{ basic_manifest, cargo_process, project, project_in, symlink_supported, t, }; use cargo_util::{ProcessBuilder, ProcessError}; use cargo_test_support::install::{assert_has_installed_exe, assert_has_not_installed_exe, exe}; use cargo_test_support::paths; fn pkg(name: &str, vers: &str) { Package::new(name, vers) .file("src/lib.rs", "") .file( "src/main.rs", &format!("extern crate {}; fn main() {{}}", name), ) .publish(); } #[cargo_test] fn simple() { pkg("foo", "0.0.1"); cargo_process("install foo").with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.1 (registry `dummy-registry`) [INSTALLING] foo v0.0.1 [COMPILING] foo v0.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]).run(); assert_has_installed_exe(paths::cargo_home(), "foo"); cargo_process("uninstall foo") .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/bin/foo[EXE] "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn install_the_same_version_twice() { pkg("foo", "0.0.1"); cargo_process("install foo foo") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.1 (registry `dummy-registry`) [INSTALLING] foo v0.0.1 [COMPILING] foo v0.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn toolchain() { pkg("foo", "0.0.1"); cargo_process("install +nightly") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid character `+` in package name: `+nightly` Use `cargo +nightly install` if you meant to use the `nightly` toolchain. "#]]) .run(); } #[cargo_test] fn url() { pkg("foo", "0.0.1"); cargo_process("install https://github.com/bar/foo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid package name: `https://github.com/bar/foo` Use `cargo install --git https://github.com/bar/foo` if you meant to install from a git repository. "#]]) .run(); } #[cargo_test] fn simple_with_message_format() { pkg("foo", "0.0.1"); cargo_process("install foo --message-format=json") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.1 (registry `dummy-registry`) [INSTALLING] foo v0.0.1 [COMPILING] foo v0.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`) [WARNING] be sure to add `[..]` to your PATH to be able to run the installed binaries "#]]) .with_stdout_data( str![[r#" [ { "executable": null, "features": [], "filenames": "{...}", "fresh": false, "manifest_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/foo-0.0.1/Cargo.toml", "package_id": "registry+https://github.com/rust-lang/crates.io-index#foo@0.0.1", "profile": "{...}", "reason": "compiler-artifact", "target": { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/foo-0.0.1/src/lib.rs", "test": true } }, { "executable": "[..]", "features": [], "filenames": "{...}", "fresh": false, "manifest_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/foo-0.0.1/Cargo.toml", "package_id": "registry+https://github.com/rust-lang/crates.io-index#foo@0.0.1", "profile": "{...}", "reason": "compiler-artifact", "target": { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "foo", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/foo-0.0.1/src/main.rs", "test": true } }, { "reason": "build-finished", "success": true } ] "#]] .is_json() .against_jsonlines(), ) .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn with_index() { let registry = registry::init(); pkg("foo", "0.0.1"); cargo_process("install foo --index") .arg(registry.index_url().as_str()) .with_stderr_data(str![[r#" [UPDATING] `[ROOT]/registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.1 (registry `[ROOT]/registry`) [INSTALLING] foo v0.0.1 (registry `[ROOT]/registry`) [COMPILING] foo v0.0.1 (registry `[ROOT]/registry`) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.1 (registry `[ROOT]/registry`)` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); cargo_process("uninstall foo") .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/bin/foo[EXE] "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn multiple_pkgs() { pkg("foo", "0.0.1"); pkg("bar", "0.0.2"); cargo_process("install foo bar baz") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.1 (registry `dummy-registry`) [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.2 (registry `dummy-registry`) [ERROR] could not find `baz` in registry `crates-io` with version `*` [INSTALLING] foo v0.0.1 [COMPILING] foo v0.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`) [INSTALLING] bar v0.0.2 [COMPILING] bar v0.0.2 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/bar[EXE] [INSTALLED] package `bar v0.0.2` (executable `bar[EXE]`) [SUMMARY] Successfully installed foo, bar! Failed to install baz (see error(s) above). [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries [ERROR] some crates failed to install "#]]) .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); assert_has_installed_exe(paths::cargo_home(), "bar"); cargo_process("uninstall foo bar") .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/bin/foo[EXE] [REMOVING] [ROOT]/home/.cargo/bin/bar[EXE] [SUMMARY] Successfully uninstalled foo, bar! "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo"); assert_has_not_installed_exe(paths::cargo_home(), "bar"); } fn path() -> Vec { env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect() } #[cargo_test] fn multiple_pkgs_path_set() { // confirm partial failure results in 101 status code and does not have the // '[WARNING] be sure to add `[..]` to your PATH to be able to run the installed binaries' // even if CARGO_HOME/bin is in the PATH pkg("foo", "0.0.1"); pkg("bar", "0.0.2"); // add CARGO_HOME/bin to path let mut path = path(); path.push(paths::cargo_home().join("bin")); let new_path = env::join_paths(path).unwrap(); cargo_process("install foo bar baz") .env("PATH", new_path) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.1 (registry `dummy-registry`) [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.2 (registry `dummy-registry`) [ERROR] could not find `baz` in registry `crates-io` with version `*` [INSTALLING] foo v0.0.1 [COMPILING] foo v0.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`) [INSTALLING] bar v0.0.2 [COMPILING] bar v0.0.2 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/bar[EXE] [INSTALLED] package `bar v0.0.2` (executable `bar[EXE]`) [SUMMARY] Successfully installed foo, bar! Failed to install baz (see error(s) above). [ERROR] some crates failed to install "#]]) .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); assert_has_installed_exe(paths::cargo_home(), "bar"); cargo_process("uninstall foo bar") .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/bin/foo[EXE] [REMOVING] [ROOT]/home/.cargo/bin/bar[EXE] [SUMMARY] Successfully uninstalled foo, bar! "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo"); assert_has_not_installed_exe(paths::cargo_home(), "bar"); } #[cargo_test] fn pick_max_version() { pkg("foo", "0.1.0"); pkg("foo", "0.2.0"); pkg("foo", "0.2.1"); pkg("foo", "0.2.1-pre.1"); pkg("foo", "0.3.0-pre.2"); cargo_process("install foo").with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.2.1 (registry `dummy-registry`) [INSTALLING] foo v0.2.1 [COMPILING] foo v0.2.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.2.1` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]).run(); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn installs_beta_version_by_explicit_name_from_git() { let p = git::repo(&paths::root().join("foo")) .file("Cargo.toml", &basic_manifest("foo", "0.3.0-beta.1")) .file("src/main.rs", "fn main() {}") .build(); cargo_process("install --git") .arg(p.url().to_string()) .arg("foo") .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn missing() { pkg("foo", "0.0.1"); cargo_process("install bar") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] could not find `bar` in registry `crates-io` with version `*` "#]]) .run(); } #[cargo_test] fn missing_current_working_directory() { cargo_process("install .") .with_status(101) .with_stderr_data(str![[r#" [ERROR] To install the binaries for the package in current working directory use `cargo install --path .`. Use `cargo build` if you want to simply build the package. "#]]) .run(); } #[cargo_test] fn bad_version() { pkg("foo", "0.0.1"); cargo_process("install foo --version=0.2.0") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] could not find `foo` in registry `crates-io` with version `=0.2.0` "#]]) .run(); } #[cargo_test] fn bad_paths() { cargo_process("install") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `[ROOT]` is not a crate root; specify a crate to install from crates.io, or use --path or --git to specify an alternate source "#]]) .run(); cargo_process("install --path .") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `[ROOT]` does not contain a Cargo.toml file. --path must point to a directory containing a Cargo.toml file. "#]]) .run(); let toml = paths::root().join("Cargo.toml"); fs::write(toml, "").unwrap(); cargo_process("install --path Cargo.toml") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `[ROOT]/Cargo.toml` is not a directory. --path must point to a directory containing a Cargo.toml file. "#]]) .run(); cargo_process("install --path .") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/Cargo.toml` ... "#]]) .run(); } #[cargo_test] fn install_location_precedence() { pkg("foo", "0.0.1"); let root = paths::root(); let t1 = root.join("t1"); let t2 = root.join("t2"); let t3 = root.join("t3"); let t4 = paths::cargo_home(); fs::create_dir(root.join(".cargo")).unwrap(); fs::write( root.join(".cargo/config.toml"), &format!( "[install] root = '{}' ", t3.display() ), ) .unwrap(); println!("install --root"); cargo_process("install foo --root") .arg(&t1) .env("CARGO_INSTALL_ROOT", &t2) .run(); assert_has_installed_exe(&t1, "foo"); assert_has_not_installed_exe(&t2, "foo"); println!("install CARGO_INSTALL_ROOT"); cargo_process("install foo") .env("CARGO_INSTALL_ROOT", &t2) .run(); assert_has_installed_exe(&t2, "foo"); assert_has_not_installed_exe(&t3, "foo"); println!("install install.root"); cargo_process("install foo").run(); assert_has_installed_exe(&t3, "foo"); assert_has_not_installed_exe(&t4, "foo"); fs::remove_file(root.join(".cargo/config.toml")).unwrap(); println!("install cargo home"); cargo_process("install foo").run(); assert_has_installed_exe(&t4, "foo"); } #[cargo_test] fn install_path() { let p = project().file("src/main.rs", "fn main() {}").build(); cargo_process("install --path").arg(p.root()).run(); assert_has_installed_exe(paths::cargo_home(), "foo"); // path-style installs force a reinstall p.cargo("install --path .").with_stderr_data(str![[r#" [INSTALLING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [REPLACING] [ROOT]/home/.cargo/bin/foo[EXE] [REPLACED] package `foo v0.0.1 ([ROOT]/foo)` with `foo v0.0.1 ([ROOT]/foo)` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]).run(); } #[cargo_test] fn install_target_dir() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("install --target-dir td_test") .with_stderr_data(str![[r#" [WARNING] Using `cargo install` to install the binaries from the package in current working directory is deprecated, use `cargo install --path .` instead. Use `cargo build` if you want to simply build the package. [INSTALLING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.1 ([ROOT]/foo)` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); let mut path = p.root(); path.push("td_test"); assert!(path.exists()); #[cfg(not(windows))] path.push("release/foo"); #[cfg(windows)] path.push("release/foo.exe"); assert!(path.exists()); } #[cargo_test] #[cfg(target_os = "linux")] fn install_path_with_lowercase_cargo_toml() { let toml = paths::root().join("cargo.toml"); fs::write(toml, "").unwrap(); cargo_process("install --path .") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `[ROOT]` does not contain a Cargo.toml file, but found cargo.toml please try to rename it to Cargo.toml. --path must point to a directory containing a Cargo.toml file. "#]] ) .run(); } #[cargo_test] fn install_relative_path_outside_current_ws() { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" authors = [] [workspace] members = ["baz"] "#, ) .file("src/main.rs", "fn main() {}") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.0" authors = [] edition = "2021" [dependencies] foo = "1" "#, ) .file("baz/src/lib.rs", "") .build(); let _bin_project = project_in("bar") .file("src/main.rs", "fn main() {}") .build(); p.cargo("install --path ../bar/foo") .with_stderr_data(str![[r#" [INSTALLING] foo v0.0.1 ([ROOT]/bar/foo) [COMPILING] foo v0.0.1 ([ROOT]/bar/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.1 ([ROOT]/bar/foo)` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); // Validate the workspace error message to display available targets. p.cargo("install --path ../bar/foo --bin") .with_status(101) .with_stderr_data(str![[r#" [ERROR] "--bin" takes one argument. Available binaries: foo "#]]) .run(); } #[cargo_test] fn multiple_packages_containing_binaries() { let p = git::repo(&paths::root().join("foo")) .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/main.rs", "fn main() {}") .file("a/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("a/src/main.rs", "fn main() {}") .build(); cargo_process("install --git") .arg(p.url().to_string()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/foo` [ERROR] multiple packages with binaries found: bar, foo. When installing a git repository, cargo will always search the entire repo for any Cargo.toml. Please specify a package, e.g. `cargo install --git [ROOTURL]/foo bar`. "#]]) .run(); } #[cargo_test] fn multiple_packages_matching_example() { let p = git::repo(&paths::root().join("foo")) .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/lib.rs", "") .file("examples/ex1.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "") .file("bar/examples/ex1.rs", "fn main() {}") .build(); cargo_process("install --example ex1 --git") .arg(p.url().to_string()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/foo` [ERROR] multiple packages with examples found: bar, foo. When installing a git repository, cargo will always search the entire repo for any Cargo.toml. Please specify a package, e.g. `cargo install --git [ROOTURL]/foo bar`. "#]]) .run(); } #[cargo_test] fn multiple_binaries_deep_select_uses_package_name() { let p = git::repo(&paths::root().join("foo")) .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/main.rs", "fn main() {}") .file("bar/baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("bar/baz/src/main.rs", "fn main() {}") .build(); cargo_process("install --git") .arg(p.url().to_string()) .arg("baz") .run(); } #[cargo_test] fn multiple_binaries_in_selected_package_installs_all() { let p = git::repo(&paths::root().join("foo")) .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/bin/bin1.rs", "fn main() {}") .file("bar/src/bin/bin2.rs", "fn main() {}") .build(); cargo_process("install --git") .arg(p.url().to_string()) .arg("bar") .run(); let cargo_home = paths::cargo_home(); assert_has_installed_exe(&cargo_home, "bin1"); assert_has_installed_exe(&cargo_home, "bin2"); } #[cargo_test] fn multiple_binaries_in_selected_package_with_bin_option_installs_only_one() { let p = git::repo(&paths::root().join("foo")) .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/bin/bin1.rs", "fn main() {}") .file("bar/src/bin/bin2.rs", "fn main() {}") .build(); cargo_process("install --bin bin1 --git") .arg(p.url().to_string()) .arg("bar") .run(); let cargo_home = paths::cargo_home(); assert_has_installed_exe(&cargo_home, "bin1"); assert_has_not_installed_exe(&cargo_home, "bin2"); } #[cargo_test] fn multiple_crates_select() { let p = git::repo(&paths::root().join("foo")) .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/main.rs", "fn main() {}") .file("a/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("a/src/main.rs", "fn main() {}") .build(); cargo_process("install --git") .arg(p.url().to_string()) .arg("foo") .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); assert_has_not_installed_exe(paths::cargo_home(), "bar"); cargo_process("install --git") .arg(p.url().to_string()) .arg("bar") .run(); assert_has_installed_exe(paths::cargo_home(), "bar"); } #[cargo_test] fn multiple_crates_git_all() { let p = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [workspace] members = ["bin1", "bin2"] "#, ) .file("bin1/Cargo.toml", &basic_manifest("bin1", "0.1.0")) .file("bin2/Cargo.toml", &basic_manifest("bin2", "0.1.0")) .file( "bin1/src/main.rs", r#"fn main() { println!("Hello, world!"); }"#, ) .file( "bin2/src/main.rs", r#"fn main() { println!("Hello, world!"); }"#, ) .build(); cargo_process(&format!("install --git {} bin1 bin2", p.url().to_string())).run(); } #[cargo_test] fn multiple_crates_auto_binaries() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = [] [dependencies] bar = { path = "a" } "#, ) .file("src/main.rs", "extern crate bar; fn main() {}") .file("a/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("a/src/lib.rs", "") .build(); cargo_process("install --path").arg(p.root()).run(); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn multiple_crates_auto_examples() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = [] [dependencies] bar = { path = "a" } "#, ) .file("src/lib.rs", "extern crate bar;") .file( "examples/foo.rs", " extern crate bar; extern crate foo; fn main() {} ", ) .file("a/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("a/src/lib.rs", "") .build(); cargo_process("install --path") .arg(p.root()) .arg("--example=foo") .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn no_binaries_or_examples() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = [] [dependencies] bar = { path = "a" } "#, ) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("a/src/lib.rs", "") .build(); cargo_process("install --path") .arg(p.root()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] no packages found with binaries or examples "#]]) .run(); } #[cargo_test] fn no_binaries() { let p = project() .file("src/lib.rs", "") .file("examples/foo.rs", "fn main() {}") .build(); cargo_process("install --path") .arg(p.root()) .arg("foo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] there is nothing to install in `foo v0.0.1 ([ROOT]/foo)`, because it has no binaries `cargo install` is only for installing programs, and can't be used with libraries. To use a library crate, add it as a dependency to a Cargo project with `cargo add`. "#]]) .run(); } #[cargo_test] fn examples() { let p = project() .file("src/lib.rs", "") .file("examples/foo.rs", "extern crate foo; fn main() {}") .build(); cargo_process("install --path") .arg(p.root()) .arg("--example=foo") .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn install_force() { let p = project().file("src/main.rs", "fn main() {}").build(); cargo_process("install --path").arg(p.root()).run(); let p = project() .at("foo2") .file("Cargo.toml", &basic_manifest("foo", "0.2.0")) .file("src/main.rs", "fn main() {}") .build(); cargo_process("install --force --path") .arg(p.root()) .with_stderr_data(str![[r#" [INSTALLING] foo v0.2.0 ([ROOT]/foo2) [COMPILING] foo v0.2.0 ([ROOT]/foo2) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [REPLACING] [ROOT]/home/.cargo/bin/foo[EXE] [REPLACED] package `foo v0.0.1 ([ROOT]/foo)` with `foo v0.2.0 ([ROOT]/foo2)` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); cargo_process("install --list") .with_stdout_data(str![[r#" foo v0.2.0 ([ROOT]/foo2): foo[EXE] "#]]) .run(); } #[cargo_test] fn install_force_partial_overlap() { let p = project() .file("src/bin/foo-bin1.rs", "fn main() {}") .file("src/bin/foo-bin2.rs", "fn main() {}") .build(); cargo_process("install --path").arg(p.root()).run(); let p = project() .at("foo2") .file("Cargo.toml", &basic_manifest("foo", "0.2.0")) .file("src/bin/foo-bin2.rs", "fn main() {}") .file("src/bin/foo-bin3.rs", "fn main() {}") .build(); cargo_process("install --force --path") .arg(p.root()) .with_stderr_data(str![[r#" [INSTALLING] foo v0.2.0 ([ROOT]/foo2) [COMPILING] foo v0.2.0 ([ROOT]/foo2) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo-bin3[EXE] [REPLACING] [ROOT]/home/.cargo/bin/foo-bin2[EXE] [REMOVING] executable `[ROOT]/home/.cargo/bin/foo-bin1[EXE]` from previous version foo v0.0.1 ([ROOT]/foo) [INSTALLED] package `foo v0.2.0 ([ROOT]/foo2)` (executable `foo-bin3[EXE]`) [REPLACED] package `foo v0.0.1 ([ROOT]/foo)` with `foo v0.2.0 ([ROOT]/foo2)` (executable `foo-bin2[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); cargo_process("install --list") .with_stdout_data(str![[r#" foo v0.2.0 ([ROOT]/foo2): foo-bin2[EXE] foo-bin3[EXE] "#]]) .run(); } #[cargo_test] fn install_force_bin() { let p = project() .file("src/bin/foo-bin1.rs", "fn main() {}") .file("src/bin/foo-bin2.rs", "fn main() {}") .build(); cargo_process("install --path").arg(p.root()).run(); let p = project() .at("foo2") .file("Cargo.toml", &basic_manifest("foo", "0.2.0")) .file("src/bin/foo-bin1.rs", "fn main() {}") .file("src/bin/foo-bin2.rs", "fn main() {}") .build(); cargo_process("install --force --bin foo-bin2 --path") .arg(p.root()) .with_stderr_data(str![[r#" [INSTALLING] foo v0.2.0 ([ROOT]/foo2) [COMPILING] foo v0.2.0 ([ROOT]/foo2) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [REPLACING] [ROOT]/home/.cargo/bin/foo-bin2[EXE] [REPLACED] package `foo v0.0.1 ([ROOT]/foo)` with `foo v0.2.0 ([ROOT]/foo2)` (executable `foo-bin2[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); cargo_process("install --list") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo): foo-bin1[EXE] foo v0.2.0 ([ROOT]/foo2): foo-bin2[EXE] "#]]) .run(); } #[cargo_test] fn compile_failure() { let p = project().file("src/main.rs", "").build(); cargo_process("install --path") .arg(p.root()) .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] could not compile `foo` (bin "foo") due to 1 previous error [ERROR] failed to compile `foo v0.0.1 ([ROOT]/foo)`, intermediate artifacts can be found at `[ROOT]/foo/target`. To reuse those artifacts with a future compilation, set the environment variable `CARGO_TARGET_DIR` to that path. ... "#]]) .run(); } #[cargo_test] fn git_repo() { let p = git::repo(&paths::root().join("foo")) .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/main.rs", "fn main() {}") .build(); // Use `--locked` to test that we don't even try to write a lock file. cargo_process("install --locked --git") .arg(p.url().to_string()) .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/foo` [WARNING] no Cargo.lock file published in foo v0.1.0 ([ROOTURL]/foo#[..]) [INSTALLING] foo v0.1.0 ([ROOTURL]/foo#[..]) [COMPILING] foo v0.1.0 ([ROOT]/home/.cargo/git/checkouts/foo-[HASH]/[..]) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.1.0 ([ROOTURL]/foo#[..])` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] #[cfg(target_os = "linux")] fn git_repo_with_lowercase_cargo_toml() { let p = git::repo(&paths::root().join("foo")) .file("cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/main.rs", "fn main() {}") .build(); cargo_process("install --git") .arg(p.url().to_string()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] git repository [..] [ERROR] Could not find Cargo.toml in `[..]`, but found cargo.toml please try to rename it to Cargo.toml "#]] ) .run(); } #[cargo_test] fn list() { pkg("foo", "0.0.1"); pkg("bar", "0.2.1"); pkg("bar", "0.2.2"); cargo_process("install --list").with_stdout_data("").run(); cargo_process("install bar --version =0.2.1").run(); cargo_process("install foo").run(); cargo_process("install --list") .with_stdout_data(str![[r#" bar v0.2.1: bar[EXE] foo v0.0.1: foo[EXE] "#]]) .run(); } #[cargo_test] fn list_error() { pkg("foo", "0.0.1"); cargo_process("install foo").run(); cargo_process("install --list") .with_stdout_data(str![[r#" foo v0.0.1: foo[EXE] "#]]) .run(); let mut worldfile_path = paths::cargo_home(); worldfile_path.push(".crates.toml"); let mut worldfile = OpenOptions::new() .write(true) .open(worldfile_path) .expect(".crates.toml should be there"); worldfile.write_all(b"\x00").unwrap(); drop(worldfile); cargo_process("install --list --verbose") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse crate metadata at `[ROOT]/home/.cargo/.crates.toml` Caused by: invalid TOML found for metadata Caused by: TOML parse error at line 1, column 1 | 1 | v1] | ^ invalid key "#]]) .run(); } #[cargo_test] fn uninstall_pkg_does_not_exist() { cargo_process("uninstall foo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package ID specification `foo` did not match any packages "#]]) .run(); } #[cargo_test] fn uninstall_bin_does_not_exist() { pkg("foo", "0.0.1"); cargo_process("install foo").run(); cargo_process("uninstall foo --bin=bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] binary `bar[EXE]` not installed as part of `foo v0.0.1` "#]]) .run(); } #[cargo_test] fn uninstall_piecemeal() { let p = project() .file("src/bin/foo.rs", "fn main() {}") .file("src/bin/bar.rs", "fn main() {}") .build(); cargo_process("install --path").arg(p.root()).run(); assert_has_installed_exe(paths::cargo_home(), "foo"); assert_has_installed_exe(paths::cargo_home(), "bar"); cargo_process("uninstall foo --bin=bar") .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/bin/bar[EXE] "#]]) .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); assert_has_not_installed_exe(paths::cargo_home(), "bar"); cargo_process("uninstall foo --bin=foo") .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/bin/foo[EXE] "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo"); cargo_process("uninstall foo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package ID specification `foo` did not match any packages "#]]) .run(); } #[cargo_test] fn subcommand_works_out_of_the_box() { Package::new("cargo-foo", "1.0.0") .file("src/main.rs", r#"fn main() { println!("bar"); }"#) .publish(); cargo_process("install cargo-foo").run(); cargo_process("foo") .with_stdout_data(str![[r#" bar "#]]) .run(); cargo_process("--list") .with_stdout_data(str![[r#" ... foo ... "#]]) .run(); } #[cargo_test] fn installs_from_cwd_by_default() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("install").with_stderr_data(str![[r#" [WARNING] Using `cargo install` to install the binaries from the package in current working directory is deprecated, use `cargo install --path .` instead. Use `cargo build` if you want to simply build the package. ... "#]]).run(); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn installs_from_cwd_with_2018_warnings() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = [] edition = "2018" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("install") .with_status(101) .with_stderr_data(str![[r#" [ERROR] Using `cargo install` to install the binaries from the package in current working directory is no longer supported, use `cargo install --path .` instead. Use `cargo build` if you want to simply build the package. "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn uninstall_cwd() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("install --path .").with_stderr_data(str![[r#" [INSTALLING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.1 ([ROOT]/foo)` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]).run(); assert_has_installed_exe(paths::cargo_home(), "foo"); p.cargo("uninstall") .with_stdout_data("") .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/bin/foo[EXE] "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn uninstall_cwd_not_installed() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("uninstall") .with_status(101) .with_stdout_data("") .with_stderr_data(str![[r#" [ERROR] package `foo v0.0.1 ([ROOT]/foo)` is not installed "#]]) .run(); } #[cargo_test] fn uninstall_cwd_no_project() { cargo_process("uninstall") .with_status(101) .with_stdout_data("") .with_stderr_data(str![[r#" [ERROR] failed to read `[ROOT]/Cargo.toml` Caused by: [NOT_FOUND] "#]]) .run(); } #[cargo_test] fn do_not_rebuilds_on_local_install() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("build --release").run(); cargo_process("install --path") .arg(p.root()) .with_stderr_data(str![[r#" [INSTALLING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.1 ([ROOT]/foo)` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); assert!(p.build_dir().exists()); assert!(p.release_bin("foo").exists()); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn reports_unsuccessful_subcommand_result() { Package::new("cargo-fail", "1.0.0") .file("src/main.rs", r#"fn main() { panic!("EXPLICIT PANIC!"); }"#) .publish(); cargo_process("install cargo-fail").run(); cargo_process("--list") .with_stdout_data(str![[r#" ... fail ... "#]]) .run(); cargo_process("fail") .with_status(101) .with_stderr_data("...\n[..]EXPLICIT PANIC![..]\n...") .run(); } #[cargo_test] fn git_with_lockfile() { let p = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = [] [dependencies] bar = { path = "bar" } "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "fn main() {}") .file( "Cargo.lock", r#" [[package]] name = "foo" version = "0.1.0" dependencies = [ "bar 0.1.0" ] [[package]] name = "bar" version = "0.1.0" "#, ) .build(); cargo_process("install --git") .arg(p.url().to_string()) .run(); } #[cargo_test] fn q_silences_warnings() { let p = project().file("src/main.rs", "fn main() {}").build(); cargo_process("install -q --path") .arg(p.root()) .with_stderr_data("") .run(); } #[cargo_test] fn readonly_dir() { pkg("foo", "0.0.1"); let root = paths::root(); let dir = &root.join("readonly"); fs::create_dir(root.join("readonly")).unwrap(); let mut perms = fs::metadata(dir).unwrap().permissions(); perms.set_readonly(true); fs::set_permissions(dir, perms).unwrap(); cargo_process("install foo").cwd(dir).run(); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn use_path_workspace() { Package::new("foo", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" authors = [] [workspace] members = ["baz"] "#, ) .file("src/main.rs", "fn main() {}") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.0" authors = [] [dependencies] foo = "1" "#, ) .file("baz/src/lib.rs", "") .build(); p.cargo("build").run(); let lock = p.read_lockfile(); p.cargo("install").run(); let lock2 = p.read_lockfile(); assert_eq!(lock, lock2, "different lockfiles"); } #[cargo_test] fn path_install_workspace_root_despite_default_members() { let p = project() .file( "Cargo.toml", r#" [package] name = "ws-root" version = "0.1.0" authors = [] [workspace] members = ["ws-member"] default-members = ["ws-member"] "#, ) .file("src/main.rs", "fn main() {}") .file( "ws-member/Cargo.toml", r#" [package] name = "ws-member" version = "0.1.0" authors = [] "#, ) .file("ws-member/src/main.rs", "fn main() {}") .build(); p.cargo("install --path") .arg(p.root()) .arg("ws-root") .with_stderr_data(str![[r#" [INSTALLING] ws-root v0.1.0 ([ROOT]/foo) [COMPILING] ws-root v0.1.0 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/ws-root[EXE] [INSTALLED] package `ws-root v0.1.0 ([ROOT]/foo)` (executable `ws-root[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) // Particularly avoid "Installed package `ws-root v0.1.0 ([..]])` (executable `ws-member`)": .with_stderr_does_not_contain("ws-member") .run(); } #[cargo_test] fn git_install_workspace_root_despite_default_members() { let p = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "ws-root" version = "0.1.0" authors = [] [workspace] members = ["ws-member"] default-members = ["ws-member"] "#, ) .file("src/main.rs", "fn main() {}") .file( "ws-member/Cargo.toml", r#" [package] name = "ws-member" version = "0.1.0" authors = [] "#, ) .file("ws-member/src/main.rs", "fn main() {}") .build(); cargo_process("install --git") .arg(p.url().to_string()) .arg("ws-root") .with_stderr_data(str![[r#" ... [INSTALLED] package `ws-root v0.1.0 ([ROOTURL]/foo#[..])` (executable `ws-root[EXE]`) ... "#]]) // Particularly avoid "Installed package `ws-root v0.1.0 ([..]])` (executable `ws-member`)": .with_stderr_does_not_contain("ws-member") .run(); } #[cargo_test] fn dev_dependencies_no_check() { Package::new("foo", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" authors = [] [dev-dependencies] baz = "1.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] no matching package named `baz` found ... "#]]) .run(); p.cargo("install").run(); } #[cargo_test] fn dev_dependencies_lock_file_untouched() { Package::new("foo", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = [] [dev-dependencies] bar = { path = "a" } "#, ) .file("src/main.rs", "fn main() {}") .file("a/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("a/src/lib.rs", "") .build(); p.cargo("build").run(); let lock = p.read_lockfile(); p.cargo("install").run(); let lock2 = p.read_lockfile(); assert!(lock == lock2, "different lockfiles"); } #[cargo_test] fn install_target_native() { pkg("foo", "0.1.0"); cargo_process("install foo --target") .arg(cargo_test_support::rustc_host()) .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn install_target_foreign() { if cross_compile::disabled() { return; } pkg("foo", "0.1.0"); cargo_process("install foo --target") .arg(cross_compile::alternate()) .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn vers_precise() { pkg("foo", "0.1.1"); pkg("foo", "0.1.2"); cargo_process("install foo --vers 0.1.1") .with_stderr_data(str![[r#" ... [DOWNLOADED] foo v0.1.1 (registry `dummy-registry`) ... "#]]) .run(); } #[cargo_test] fn version_precise() { pkg("foo", "0.1.1"); pkg("foo", "0.1.2"); cargo_process("install foo --version 0.1.1") .with_stderr_data(str![[r#" ... [DOWNLOADED] foo v0.1.1 (registry `dummy-registry`) ... "#]]) .run(); } #[cargo_test] fn inline_version_precise() { pkg("foo", "0.1.1"); pkg("foo", "0.1.2"); cargo_process("install foo@0.1.1") .with_stderr_data(str![[r#" ... [DOWNLOADED] foo v0.1.1 (registry `dummy-registry`) ... "#]]) .run(); } #[cargo_test] fn inline_version_multiple() { pkg("foo", "0.1.0"); pkg("foo", "0.1.1"); pkg("foo", "0.1.2"); pkg("bar", "0.2.0"); pkg("bar", "0.2.1"); pkg("bar", "0.2.2"); cargo_process("install foo@0.1.1 bar@0.2.1") .with_stderr_data(str![[r#" ... [DOWNLOADED] foo v0.1.1 (registry `dummy-registry`) ... [DOWNLOADED] bar v0.2.1 (registry `dummy-registry`) ... "#]]) .run(); } #[cargo_test] fn inline_version_without_name() { pkg("foo", "0.1.1"); pkg("foo", "0.1.2"); cargo_process("install @0.1.1") .with_status(1) .with_stderr_data(str![[r#" [ERROR] invalid value '@0.1.1' for '[CRATE[@]]...': missing crate name before '@' For more information, try '--help'. "#]]) .run(); } #[cargo_test] fn inline_and_explicit_version() { pkg("foo", "0.1.1"); pkg("foo", "0.1.2"); cargo_process("install foo@0.1.1 --version 0.1.1") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot specify both `@` and `--version ` "#]]) .run(); } #[cargo_test] fn not_both_vers_and_version() { pkg("foo", "0.1.1"); pkg("foo", "0.1.2"); cargo_process("install foo --version 0.1.1 --vers 0.1.2") .with_status(1) .with_stderr_data(str![[r#" [ERROR] the argument '--version ' cannot be used multiple times Usage: cargo[EXE] install [OPTIONS] [CRATE[@]]... For more information, try '--help'. "#]]) .run(); } #[cargo_test] fn test_install_git_cannot_be_a_base_url() { cargo_process("install --git github.com:rust-lang/rustfmt.git") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid url `github.com:rust-lang/rustfmt.git`: cannot-be-a-base-URLs are not supported "#]]) .run(); } #[cargo_test] fn uninstall_multiple_and_specifying_bin() { cargo_process("uninstall foo bar --bin baz") .with_status(101) .with_stderr_data(str![[r#" [ERROR] A binary can only be associated with a single installed package, specifying multiple specs with --bin is redundant. "#]]) .run(); } #[cargo_test] fn uninstall_with_empty_package_option() { cargo_process("uninstall -p") .with_status(101) .with_stderr_data(str![[r#" [ERROR] "--package " requires a SPEC format value. Run `cargo help pkgid` for more information about SPEC format. "#]]) .run(); } #[cargo_test] fn uninstall_multiple_and_some_pkg_does_not_exist() { pkg("foo", "0.0.1"); cargo_process("install foo").run(); cargo_process("uninstall foo bar") .with_status(101) .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/bin/foo[EXE] [ERROR] package ID specification `bar` did not match any packages [SUMMARY] Successfully uninstalled foo! Failed to uninstall bar (see error(s) above). [ERROR] some packages failed to uninstall "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo"); assert_has_not_installed_exe(paths::cargo_home(), "bar"); } #[cargo_test] fn custom_target_dir_for_git_source() { let p = git::repo(&paths::root().join("foo")) .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/main.rs", "fn main() {}") .build(); cargo_process("install --git") .arg(p.url().to_string()) .run(); assert!(!paths::root().join("target/release").is_dir()); cargo_process("install --force --git") .arg(p.url().to_string()) .env("CARGO_TARGET_DIR", "target") .run(); assert!(paths::root().join("target/release").is_dir()); } #[cargo_test] fn install_respects_lock_file() { // `cargo install` now requires --locked to use a Cargo.lock. Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.1.1") .file("src/lib.rs", "not rust") .publish(); Package::new("foo", "0.1.0") .dep("bar", "0.1") .file("src/lib.rs", "") .file( "src/main.rs", "extern crate foo; extern crate bar; fn main() {}", ) .file( "Cargo.lock", r#" [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "foo" version = "0.1.0" dependencies = [ "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] "#, ) .publish(); cargo_process("install foo") .with_stderr_data(str![[r#" ... [..]not rust[..] ... "#]]) .with_status(101) .run(); cargo_process("install --locked foo").run(); } #[cargo_test] fn install_path_respects_lock_file() { // --path version of install_path_respects_lock_file, --locked is required // to use Cargo.lock. Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.1.1") .file("src/lib.rs", "not rust") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = "0.1" "#, ) .file("src/main.rs", "extern crate bar; fn main() {}") .file( "Cargo.lock", r#" [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "foo" version = "0.1.0" dependencies = [ "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] "#, ) .build(); p.cargo("install --path .") .with_stderr_data(str![[r#" ... [..]not rust[..] ... "#]]) .with_status(101) .run(); p.cargo("install --path . --locked").run(); } #[cargo_test] fn lock_file_path_deps_ok() { Package::new("bar", "0.1.0").publish(); Package::new("foo", "0.1.0") .dep("bar", "0.1") .file("src/lib.rs", "") .file( "src/main.rs", "extern crate foo; extern crate bar; fn main() {}", ) .file( "Cargo.lock", r#" [[package]] name = "bar" version = "0.1.0" [[package]] name = "foo" version = "0.1.0" dependencies = [ "bar 0.1.0", ] "#, ) .publish(); cargo_process("install foo").run(); } #[cargo_test] fn install_empty_argument() { // Bug 5229 cargo_process("install") .arg("") .with_status(1) .with_stderr_data(str![[r#" [ERROR] invalid value '' for '[CRATE[@]]...': crate name is empty For more information, try '--help'. "#]]) .run(); } #[cargo_test] fn git_repo_replace() { let p = git::repo(&paths::root().join("foo")) .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/main.rs", "fn main() {}") .build(); let repo = git2::Repository::open(&p.root()).unwrap(); let old_rev = repo.revparse_single("HEAD").unwrap().id(); cargo_process("install --git") .arg(p.url().to_string()) .run(); git::commit(&repo); let new_rev = repo.revparse_single("HEAD").unwrap().id(); let mut path = paths::home(); path.push(".cargo/.crates.toml"); assert_ne!(old_rev, new_rev); assert!(fs::read_to_string(path.clone()) .unwrap() .contains(&format!("{}", old_rev))); cargo_process("install --force --git") .arg(p.url().to_string()) .run(); assert!(fs::read_to_string(path) .unwrap() .contains(&format!("{}", new_rev))); } #[cargo_test] fn workspace_uses_workspace_target_dir() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = [] [workspace] [dependencies] bar = { path = 'bar' } "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("build --release").cwd("bar").run(); cargo_process("install --path") .arg(p.root().join("bar")) .with_stderr_data(str![[r#" [INSTALLING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/bar[EXE] [INSTALLED] package `bar v0.1.0 ([ROOT]/foo/bar)` (executable `bar[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); } #[cargo_test] fn install_ignores_local_cargo_config() { pkg("bar", "0.0.1"); let p = project() .file( ".cargo/config.toml", r#" [build] target = "non-existing-target" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("install bar").run(); assert_has_installed_exe(paths::cargo_home(), "bar"); } #[cargo_test] fn install_ignores_unstable_table_in_local_cargo_config() { pkg("bar", "0.0.1"); let p = project() .file( ".cargo/config.toml", r#" [unstable] build-std = ["core"] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("install bar") .masquerade_as_nightly_cargo(&["build-std"]) .run(); assert_has_installed_exe(paths::cargo_home(), "bar"); } #[cargo_test] fn install_global_cargo_config() { pkg("bar", "0.0.1"); let config = paths::cargo_home().join("config.toml"); let mut toml = fs::read_to_string(&config).unwrap_or_default(); toml.push_str( r#" [build] target = 'nonexistent' "#, ); fs::write(&config, toml).unwrap(); cargo_process("install bar") .with_status(101) .with_stderr_data( str![[r#" [INSTALLING] bar v0.0.1 Caused by: process didn't exit successfully: `rustc [..]--target nonexistent[..]` ([EXIT_STATUS]: 1) ... "#]] .unordered(), ) .run(); } #[cargo_test] fn install_path_config() { project() .file( ".cargo/config.toml", r#" [build] target = 'nonexistent' "#, ) .file("src/main.rs", "fn main() {}") .build(); cargo_process("install --path foo") .with_status(101) .with_stderr_data(str![[r#" ... process didn't exit successfully: `rustc [..]--target nonexistent[..]` ([EXIT_STATUS]: 1) ... "#]]) .run(); } #[cargo_test] fn install_version_req() { // Try using a few versionreq styles. pkg("foo", "0.0.3"); pkg("foo", "1.0.4"); pkg("foo", "1.0.5"); cargo_process("install foo --version=*") .with_stderr_does_not_contain("[WARNING][..]is not a valid semver[..]") .with_stderr_data(str![[r#" ... [INSTALLING] foo v1.0.5 ... "#]]) .run(); cargo_process("uninstall foo").run(); cargo_process("install foo --version=^1.0") .with_stderr_does_not_contain("[WARNING][..]is not a valid semver[..]") .with_stderr_data(str![[r#" ... [INSTALLING] foo v1.0.5 ... "#]]) .run(); cargo_process("uninstall foo").run(); cargo_process("install foo --version=0.0.*") .with_stderr_does_not_contain("[WARNING][..]is not a valid semver[..]") .with_stderr_data(str![[r#" ... [INSTALLING] foo v0.0.3 ... "#]]) .run(); } #[cargo_test] fn git_install_reads_workspace_manifest() { let p = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [workspace] members = ["bin1"] [profile.release] incremental = 3 "#, ) .file("bin1/Cargo.toml", &basic_manifest("bin1", "0.1.0")) .file( "bin1/src/main.rs", r#"fn main() { println!("Hello, world!"); }"#, ) .build(); cargo_process(&format!("install --git {}", p.url().to_string())) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/foo` [ERROR] invalid type: integer `3`, expected a boolean --> home/.cargo/git/checkouts/foo-[HASH]/[..]/Cargo.toml:6:27 | 6 | incremental = 3 | ^ | [ERROR] invalid type: integer `3`, expected a boolean --> home/.cargo/git/checkouts/foo-[HASH]/[..]/Cargo.toml:6:27 | 6 | incremental = 3 | ^ | "#]]) .run(); } #[cargo_test] fn install_git_with_symlink_home() { // Ensure that `cargo install` with a git repo is OK when CARGO_HOME is a // symlink, and uses an build script. if !symlink_supported() { return; } let p = git::new("foo", |p| { p.file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/main.rs", "fn main() {}") // This triggers discover_git_and_list_files for detecting changed files. .file("build.rs", "fn main() {}") }); #[cfg(unix)] use std::os::unix::fs::symlink; #[cfg(windows)] use std::os::windows::fs::symlink_dir as symlink; let actual = paths::root().join("actual-home"); t!(std::fs::create_dir(&actual)); t!(symlink(&actual, paths::home().join(".cargo"))); cargo_process("install --git") .arg(p.url().to_string()) .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/foo` [INSTALLING] foo v1.0.0 ([ROOTURL]/foo#[..]) [COMPILING] foo v1.0.0 ([ROOT]/home/.cargo/git/checkouts/foo-[HASH]/[..]) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v1.0.0 ([ROOTURL]/foo#[..])` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); } #[cargo_test] fn install_yanked_cargo_package() { Package::new("baz", "0.0.1").yanked(true).publish(); cargo_process("install baz --version 0.0.1") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] cannot install package `baz`, it has been yanked from registry `crates-io` "#]]) .run(); } #[cargo_test] fn install_cargo_package_in_a_patched_workspace() { pkg("foo", "0.1.0"); pkg("fizz", "1.0.0"); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" authors = [] [workspace] members = ["baz"] "#, ) .file("src/main.rs", "fn main() {}") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.0" authors = [] [dependencies] fizz = "1" [patch.crates-io] fizz = { version = "=1.0.0" } "#, ) .file("baz/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] patch for the non root package will be ignored, specify patch at the workspace root: package: [ROOT]/foo/baz/Cargo.toml workspace: [ROOT]/foo/Cargo.toml ... "#]]) .run(); // A crate installation must not emit any message from a workspace under // current working directory. // See https://github.com/rust-lang/cargo/issues/8619 p.cargo("install foo").with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.1.0 (registry `dummy-registry`) [INSTALLING] foo v0.1.0 [COMPILING] foo v0.1.0 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.1.0` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]).run(); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn locked_install_without_published_lockfile() { Package::new("foo", "0.1.0") .file("src/main.rs", "//! Some docs\nfn main() {}") .publish(); cargo_process("install foo --locked") .with_stderr_data(str![[r#" ... [WARNING] no Cargo.lock file published in foo v0.1.0 ... "#]]) .run(); } #[cargo_test] fn install_semver_metadata() { // Check trying to install a package that uses semver metadata. // This uses alt registry because the bug this is exercising doesn't // trigger with a replaced source. registry::alt_init(); Package::new("foo", "1.0.0+abc") .alternative(true) .file("src/main.rs", "fn main() {}") .publish(); cargo_process("install foo --registry alternative --version 1.0.0+abc").run(); cargo_process("install foo --registry alternative") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [IGNORED] package `foo v1.0.0+abc (registry `alternative`)` is already installed, use --force to override [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); // "Updating" is not displayed here due to the --version fast-path. cargo_process("install foo --registry alternative --version 1.0.0+abc") .with_stderr_data(str![[r#" [IGNORED] package `foo v1.0.0+abc (registry `alternative`)` is already installed, use --force to override [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); cargo_process("install foo --registry alternative --version 1.0.0 --force") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [INSTALLING] foo v1.0.0+abc (registry `alternative`) [COMPILING] foo v1.0.0+abc (registry `alternative`) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [REPLACING] [ROOT]/home/.cargo/bin/foo[EXE] [REPLACED] package `foo v1.0.0+abc (registry `alternative`)` with `foo v1.0.0+abc (registry `alternative`)` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); // Check that from a fresh cache will work without metadata, too. paths::home().join(".cargo/registry").rm_rf(); paths::home().join(".cargo/bin").rm_rf(); cargo_process("install foo --registry alternative --version 1.0.0") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [DOWNLOADING] crates ... [DOWNLOADED] foo v1.0.0+abc (registry `alternative`) [INSTALLING] foo v1.0.0+abc (registry `alternative`) [COMPILING] foo v1.0.0+abc (registry `alternative`) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v1.0.0+abc (registry `alternative`)` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); } #[cargo_test] fn no_auto_fix_note() { Package::new("auto_fix", "0.0.1") .file("src/lib.rs", "use std::io;") .file( "src/main.rs", &format!("extern crate {}; use std::io; fn main() {{}}", "auto_fix"), ) .publish(); // This should not contain a suggestion to run `cargo fix` // // This is checked by matching the full output as `with_stderr_does_not_contain` // can be brittle cargo_process("install auto_fix") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] auto_fix v0.0.1 (registry `dummy-registry`) [INSTALLING] auto_fix v0.0.1 [COMPILING] auto_fix v0.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/auto_fix[EXE] [INSTALLED] package `auto_fix v0.0.1` (executable `auto_fix[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); assert_has_installed_exe(paths::cargo_home(), "auto_fix"); cargo_process("uninstall auto_fix") .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/bin/auto_fix[EXE] "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "auto_fix"); } #[cargo_test] fn failed_install_retains_temp_directory() { // Verifies that the temporary directory persists after a build failure. Package::new("foo", "0.0.1") .file("src/main.rs", "x") .publish(); let err = cargo_process("install foo").exec_with_output().unwrap_err(); let err = err.downcast::().unwrap(); let stderr = String::from_utf8(err.stderr.unwrap()).unwrap(); assert_e2e().eq(&stderr, str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.1 (registry `dummy-registry`) [INSTALLING] foo v0.0.1 [COMPILING] foo v0.0.1 [ERROR] expected one of `!` or `::`, found `` --> [ROOT]/home/.cargo/registry/src/-[..]/foo-0.0.1/src/main.rs:1:1 | 1 | x | ^ expected one of `!` or `::` [ERROR] could not compile `foo` (bin "foo") due to 1 previous error [ERROR] failed to compile `foo v0.0.1`, intermediate artifacts can be found at `[..]`. To reuse those artifacts with a future compilation, set the environment variable `CARGO_TARGET_DIR` to that path. "#]]); // Find the path in the output. let stderr = stderr.split_once("found at `").unwrap().1; let end = stderr.find('.').unwrap() - 1; let path = Path::new(&stderr[..end]); assert!(path.exists()); assert!(path.join("release/deps").exists()); } #[cargo_test] fn sparse_install() { // Checks for an issue where uninstalling something corrupted // the SourceIds of sparse registries. // See https://github.com/rust-lang/cargo/issues/11751 let _registry = registry::RegistryBuilder::new().http_index().build(); pkg("foo", "0.0.1"); pkg("bar", "0.0.1"); cargo_process("install foo --registry dummy-registry") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.1 (registry `dummy-registry`) [INSTALLING] foo v0.0.1 (registry `dummy-registry`) [UPDATING] `dummy-registry` index [COMPILING] foo v0.0.1 (registry `dummy-registry`) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.1 (registry `dummy-registry`)` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); let assert_v1 = |expected| { let v1 = fs::read_to_string(paths::home().join(".cargo/.crates.toml")).unwrap(); assert_e2e().eq(&v1, expected); }; assert_v1(str![[r#" [v1] "foo 0.0.1 (sparse+http://127.0.0.1:[..]/index/)" = ["foo[EXE]"] "#]]); cargo_process("install bar").run(); assert_has_installed_exe(paths::cargo_home(), "bar"); assert_v1(str![[r#" [v1] "bar 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = ["bar[EXE]"] "foo 0.0.1 (sparse+http://127.0.0.1:[..]/index/)" = ["foo[EXE]"] "#]]); cargo_process("uninstall bar") .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/bin/bar[EXE] "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "bar"); assert_v1(str![[r#" [v1] "foo 0.0.1 (sparse+http://127.0.0.1:[..]/index/)" = ["foo[EXE]"] "#]]); cargo_process("uninstall foo") .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/bin/foo[EXE] "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo"); assert_v1(str![[r#" [v1] "#]]); } #[cargo_test] fn self_referential() { // Some packages build-dep on prior versions of themselves. Package::new("foo", "0.0.1") .file("src/lib.rs", "fn hello() {}") .file("src/main.rs", "fn main() {}") .file("build.rs", "fn main() {}") .publish(); Package::new("foo", "0.0.2") .file("src/lib.rs", "fn hello() {}") .file("src/main.rs", "fn main() {}") .file("build.rs", "fn main() {}") .build_dep("foo", "0.0.1") .publish(); cargo_process("install foo").with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.2 (registry `dummy-registry`) [INSTALLING] foo v0.0.2 [LOCKING] 1 package to latest compatible version [ADDING] foo v0.0.1 (available: v0.0.2) [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.1 (registry `dummy-registry`) [COMPILING] foo v0.0.1 [COMPILING] foo v0.0.2 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.2` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]).run(); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn ambiguous_registry_vs_local_package() { // Correctly install 'foo' from a local package, even if that package also // depends on a registry dependency named 'foo'. Package::new("foo", "0.0.1") .file("src/lib.rs", "fn hello() {}") .publish(); let p = project() .file("src/main.rs", "fn main() {}") .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = [] edition = "2021" [dependencies] foo = "0.0.1" "#, ) .build(); cargo_process("install --path") .arg(p.root()) .with_stderr_data(str![[r#" [INSTALLING] foo v0.1.0 ([ROOT]/foo) [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.1 (registry `dummy-registry`) [COMPILING] foo v0.0.1 [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.1.0 ([ROOT]/foo)` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn install_with_redundant_default_mode() { pkg("foo", "0.0.1"); cargo_process("install foo --release") .with_stderr_data(str![[r#" [ERROR] unexpected argument '--release' found tip: `--release` is the default for `cargo install`; instead `--debug` is supported Usage: cargo[EXE] install [OPTIONS] [CRATE[@]]... For more information, try '--help'. "#]]) .with_status(1) .run(); } #[cargo_test] fn install_incompat_msrv() { Package::new("foo", "0.1.0") .file("src/main.rs", "fn main() {}") .rust_version("1.30") .publish(); Package::new("foo", "0.2.0") .file("src/main.rs", "fn main() {}") .rust_version("1.9876.0") .publish(); cargo_process("install foo") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] cannot install package `foo 0.2.0`, it requires rustc 1.9876.0 or newer, while the currently active rustc version is [..] `foo 0.1.0` supports rustc 1.30 "#]]) .with_status(101) .run(); } fn assert_tracker_noexistence(key: &str) { let v1_data: toml::Value = toml::from_str(&fs::read_to_string(paths::cargo_home().join(".crates.toml")).unwrap()) .unwrap(); let v2_data: serde_json::Value = serde_json::from_str( &fs::read_to_string(paths::cargo_home().join(".crates2.json")).unwrap(), ) .unwrap(); assert!(v1_data["v1"].get(key).is_none()); assert!(v2_data["installs"][key].is_null()); } #[cargo_test] fn uninstall_running_binary() { use std::io::Write; Package::new("foo", "0.0.1") .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" "#, ) .file( "src/main.rs", r#" use std::net::TcpStream; use std::env::var; use std::io::Read; fn main() { for i in 0..2 { TcpStream::connect(&var("__ADDR__").unwrap()[..]) .unwrap() .read_to_end(&mut Vec::new()) .unwrap(); } } "#, ) .publish(); cargo_process("install foo").with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.1 (registry `dummy-registry`) [INSTALLING] foo v0.0.1 [COMPILING] foo v0.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]).run(); assert_has_installed_exe(paths::cargo_home(), "foo"); let foo_bin = paths::cargo_home().join("bin").join(exe("foo")); let l = std::net::TcpListener::bind("127.0.0.1:0").unwrap(); let addr = l.local_addr().unwrap().to_string(); let t = thread::spawn(move || { ProcessBuilder::new(foo_bin) .env("__ADDR__", addr) .exec() .unwrap(); }); let key = "foo 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)"; #[cfg(windows)] { // Ensure foo is running before the first `cargo uninstall` call l.accept().unwrap().0.write_all(&[1]).unwrap(); cargo_process("uninstall foo") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] failed to remove file `[ROOT]/home/.cargo/bin/foo[EXE]` ... "#]]) .run(); // Ensure foo is stopped before the second `cargo uninstall` call l.accept().unwrap().0.write_all(&[1]).unwrap(); t.join().unwrap(); cargo_process("uninstall foo") .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/bin/foo[EXE] "#]]) .run(); }; #[cfg(not(windows))] { // Ensure foo is running before the first `cargo uninstall` call l.accept().unwrap().0.write_all(&[1]).unwrap(); cargo_process("uninstall foo") .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/bin/foo[EXE] "#]]) .run(); l.accept().unwrap().0.write_all(&[1]).unwrap(); t.join().unwrap(); }; assert_has_not_installed_exe(paths::cargo_home(), "foo"); assert_tracker_noexistence(key); cargo_process("install foo").with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [INSTALLING] foo v0.0.1 [COMPILING] foo v0.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]).run(); } #[cargo_test] fn dry_run() { pkg("foo", "0.0.1"); cargo_process("-Z unstable-options install --dry-run foo") .masquerade_as_nightly_cargo(&["install::dry-run"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.1 (registry `dummy-registry`) [INSTALLING] foo v0.0.1 [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [WARNING] aborting install due to dry run [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn dry_run_incompatible_package() { Package::new("some-package-from-the-distant-future", "0.0.1") .rust_version("1.2345.0") .file("src/main.rs", "fn main() {}") .publish(); cargo_process("-Z unstable-options install --dry-run some-package-from-the-distant-future") .masquerade_as_nightly_cargo(&["install::dry-run"]) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] cannot install package `some-package-from-the-distant-future 0.0.1`, it requires rustc 1.2345.0 or newer, while the currently active rustc version is [..] "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "some-package-from-the-distant-future"); } #[cargo_test] fn dry_run_incompatible_package_dependecy() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = [] [dependencies] some-package-from-the-distant-future = { path = "a" } "#, ) .file("src/main.rs", "fn main() {}") .file( "a/Cargo.toml", r#" [package] name = "some-package-from-the-distant-future" version = "0.1.0" authors = [] rust-version = "1.2345.0" "#, ) .file("a/src/lib.rs", "") .build(); cargo_process("-Z unstable-options install --dry-run --path") .arg(p.root()) .arg("foo") .masquerade_as_nightly_cargo(&["install::dry-run"]) .with_status(101) .with_stderr_data(str![[r#" [INSTALLING] foo v0.1.0 ([ROOT]/foo) [LOCKING] 1 package to latest compatible version [ERROR] failed to compile `foo v0.1.0 ([ROOT]/foo)`, intermediate artifacts can be found at `[ROOT]/foo/target`. To reuse those artifacts with a future compilation, set the environment variable `CARGO_TARGET_DIR` to that path. Caused by: rustc [..] is not supported by the following package: some-package-from-the-distant-future@0.1.0 requires rustc 1.2345.0 "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn dry_run_upgrade() { pkg("foo", "0.0.1"); cargo_process("install foo").run(); assert_has_installed_exe(paths::cargo_home(), "foo"); pkg("foo", "0.0.2"); cargo_process("-Z unstable-options install --dry-run foo") .masquerade_as_nightly_cargo(&["install::dry-run"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.2 (registry `dummy-registry`) [INSTALLING] foo v0.0.2 [REPLACING] [ROOT]/home/.cargo/bin/foo[EXE] [WARNING] aborting install due to dry run [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn dry_run_remove_orphan() { Package::new("bar", "1.0.0") .file("src/bin/client.rs", "fn main() {}") .file("src/bin/server.rs", "fn main() {}") .publish(); cargo_process("install bar") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [INSTALLING] bar v1.0.0 [COMPILING] bar v1.0.0 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/client[EXE] [INSTALLING] [ROOT]/home/.cargo/bin/server[EXE] [INSTALLED] package `bar v1.0.0` (executables `client[EXE]`, `server[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); assert_has_installed_exe(paths::cargo_home(), "client"); assert_has_installed_exe(paths::cargo_home(), "server"); Package::new("bar", "2.0.0") .file("src/bin/client.rs", "fn main() {}") .publish(); cargo_process("-Z unstable-options install --dry-run bar") .masquerade_as_nightly_cargo(&["install::dry-run"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] bar v2.0.0 (registry `dummy-registry`) [INSTALLING] bar v2.0.0 [REPLACING] [ROOT]/home/.cargo/bin/client[EXE] [REMOVING] executable `[ROOT]/home/.cargo/bin/server[EXE]` from previous version bar v1.0.0 [WARNING] aborting install due to dry run [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); assert_has_installed_exe(paths::cargo_home(), "client"); // Ensure server is still installed after the dry run assert_has_installed_exe(paths::cargo_home(), "server"); } cargo-0.86.0/tests/testsuite/install_upgrade.rs000064400000000000000000000740701046102023000177400ustar 00000000000000//! Tests for `cargo install` where it upgrades a package if it is out-of-date. use std::collections::BTreeSet; use std::env; use std::fs; use std::path::PathBuf; use std::sync::atomic::{AtomicUsize, Ordering}; use cargo::core::PackageId; use cargo_test_support::install::exe; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::{self, Package}; use cargo_test_support::{ basic_manifest, cargo_process, cross_compile, execs, git, process, project, str, Execs, }; fn pkg_maybe_yanked(name: &str, vers: &str, yanked: bool) { Package::new(name, vers) .yanked(yanked) .file( "src/main.rs", r#"fn main() { println!("{}", env!("CARGO_PKG_VERSION")) }"#, ) .publish(); } // Helper for publishing a package. fn pkg(name: &str, vers: &str) { pkg_maybe_yanked(name, vers, false) } fn v1_path() -> PathBuf { paths::cargo_home().join(".crates.toml") } fn v2_path() -> PathBuf { paths::cargo_home().join(".crates2.json") } fn load_crates1() -> toml::Value { toml::from_str(&fs::read_to_string(v1_path()).unwrap()).unwrap() } fn load_crates2() -> serde_json::Value { serde_json::from_str(&fs::read_to_string(v2_path()).unwrap()).unwrap() } fn installed_exe(name: &str) -> PathBuf { paths::cargo_home().join("bin").join(exe(name)) } /// Helper for executing binaries installed by cargo. fn installed_process(name: &str) -> Execs { static NEXT_ID: AtomicUsize = AtomicUsize::new(0); thread_local!(static UNIQUE_ID: usize = NEXT_ID.fetch_add(1, Ordering::SeqCst)); // This copies the executable to a unique name so that it may be safely // replaced on Windows. See Project::rename_run for details. let src = installed_exe(name); let dst = installed_exe(&UNIQUE_ID.with(|my_id| format!("{}-{}", name, my_id))); // Note: Cannot use copy. On Linux, file descriptors may be left open to // the executable as other tests in other threads are constantly spawning // new processes (see https://github.com/rust-lang/cargo/pull/5557 for // more). fs::rename(&src, &dst) .unwrap_or_else(|e| panic!("Failed to rename `{:?}` to `{:?}`: {}", src, dst, e)); // Leave behind a fake file so that reinstall duplicate check works. fs::write(src, "").unwrap(); let p = process(dst); execs().with_process_builder(p) } /// Check that the given package name/version has the following bins listed in /// the trackers. Also verifies that both trackers are in sync and valid. /// Pass in an empty `bins` list to assert that the package is *not* installed. fn validate_trackers(name: &str, version: &str, bins: &[&str]) { let v1 = load_crates1(); let v1_table = v1.get("v1").unwrap().as_table().unwrap(); let v2 = load_crates2(); let v2_table = v2["installs"].as_object().unwrap(); assert_eq!(v1_table.len(), v2_table.len()); // Convert `bins` to a BTreeSet. let bins: BTreeSet = bins .iter() .map(|b| format!("{}{}", b, env::consts::EXE_SUFFIX)) .collect(); // Check every entry matches between v1 and v2. for (pkg_id_str, v1_bins) in v1_table { let pkg_id: PackageId = toml::Value::from(pkg_id_str.to_string()) .try_into() .unwrap(); let v1_bins: BTreeSet = v1_bins .as_array() .unwrap() .iter() .map(|b| b.as_str().unwrap().to_string()) .collect(); if pkg_id.name().as_str() == name && pkg_id.version().to_string() == version { if bins.is_empty() { panic!( "Expected {} to not be installed, but found: {:?}", name, v1_bins ); } else { assert_eq!(bins, v1_bins); } } let pkg_id_value = serde_json::to_value(&pkg_id).unwrap(); let pkg_id_str = pkg_id_value.as_str().unwrap(); let v2_info = v2_table .get(pkg_id_str) .expect("v2 missing v1 pkg") .as_object() .unwrap(); let v2_bins = v2_info["bins"].as_array().unwrap(); let v2_bins: BTreeSet = v2_bins .iter() .map(|b| b.as_str().unwrap().to_string()) .collect(); assert_eq!(v1_bins, v2_bins); } } #[cargo_test] fn registry_upgrade() { // Installing and upgrading from a registry. pkg("foo", "1.0.0"); cargo_process("install foo").with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v1.0.0 (registry `dummy-registry`) [INSTALLING] foo v1.0.0 [COMPILING] foo v1.0.0 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v1.0.0` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]).run(); installed_process("foo") .with_stdout_data(str![[r#" 1.0.0 "#]]) .run(); validate_trackers("foo", "1.0.0", &["foo"]); cargo_process("install foo").with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [IGNORED] package `foo v1.0.0` is already installed, use --force to override [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]).run(); pkg("foo", "1.0.1"); cargo_process("install foo").with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v1.0.1 (registry `dummy-registry`) [INSTALLING] foo v1.0.1 [COMPILING] foo v1.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [REPLACING] [ROOT]/home/.cargo/bin/foo[EXE] [REPLACED] package `foo v1.0.0` with `foo v1.0.1` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]).run(); installed_process("foo") .with_stdout_data(str![[r#" 1.0.1 "#]]) .run(); validate_trackers("foo", "1.0.1", &["foo"]); cargo_process("install foo --version=1.0.0") .with_stderr_data(str![[r#" ... [COMPILING] foo v1.0.0 ... "#]]) .run(); installed_process("foo") .with_stdout_data(str![[r#" 1.0.0 "#]]) .run(); validate_trackers("foo", "1.0.0", &["foo"]); cargo_process("install foo --version=^1.0") .with_stderr_data(str![[r#" ... [COMPILING] foo v1.0.1 ... "#]]) .run(); installed_process("foo") .with_stdout_data(str![[r#" 1.0.1 "#]]) .run(); validate_trackers("foo", "1.0.1", &["foo"]); cargo_process("install foo --version=^1.0") .with_stderr_data(str![[r#" ... [IGNORED] package `foo v1.0.1` is already installed, use --force to override ... "#]]) .run(); } #[cargo_test] fn uninstall() { // Basic uninstall test. pkg("foo", "1.0.0"); cargo_process("install foo").run(); cargo_process("uninstall foo").run(); let data = load_crates2(); assert_eq!(data["installs"].as_object().unwrap().len(), 0); let v1_table = load_crates1(); assert_eq!(v1_table.get("v1").unwrap().as_table().unwrap().len(), 0); } #[cargo_test] fn upgrade_force() { pkg("foo", "1.0.0"); cargo_process("install foo").run(); cargo_process("install foo --force") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [INSTALLING] foo v1.0.0 [COMPILING] foo v1.0.0 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [REPLACING] [ROOT]/home/.cargo/bin/foo[EXE] [REPLACED] package `foo v1.0.0` with `foo v1.0.0` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); validate_trackers("foo", "1.0.0", &["foo"]); } #[cargo_test] fn ambiguous_version_no_longer_allowed() { // Non-semver-requirement is not allowed for `--version`. pkg("foo", "1.0.0"); cargo_process("install foo --version=1.0") .with_stderr_data(str![[r#" [ERROR] invalid value '1.0' for '--version ': unexpected end of input while parsing minor version number tip: if you want to specify SemVer range, add an explicit qualifier, like '^1.0' For more information, try '--help'. "#]]) .with_status(1) .run(); } #[cargo_test] fn path_is_always_dirty() { // --path should always reinstall. let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("install --path .").run(); p.cargo("install --path .") .with_stderr_data(str![[r#" ... [REPLACING] [ROOT]/home/.cargo/bin/foo[EXE] ... "#]]) .run(); } #[cargo_test] fn fails_for_conflicts_unknown() { // If an untracked file is in the way, it should fail. pkg("foo", "1.0.0"); let exe = installed_exe("foo"); exe.parent().unwrap().mkdir_p(); fs::write(exe, "").unwrap(); cargo_process("install foo") .with_stderr_data(str![[r#" ... [ERROR] binary `foo[EXE]` already exists in destination ... "#]]) .with_status(101) .run(); } #[cargo_test] fn fails_for_conflicts_known() { // If the same binary exists in another package, it should fail. pkg("foo", "1.0.0"); Package::new("bar", "1.0.0") .file("src/bin/foo.rs", "fn main() {}") .publish(); cargo_process("install foo").run(); cargo_process("install bar") .with_stderr_data(str![[r#" ... [ERROR] binary `foo[EXE]` already exists in destination as part of `foo v1.0.0` ... "#]]) .with_status(101) .run(); } #[cargo_test] fn supports_multiple_binary_names() { // Can individually install with --bin or --example Package::new("foo", "1.0.0") .file("src/main.rs", r#"fn main() { println!("foo"); }"#) .file("src/bin/a.rs", r#"fn main() { println!("a"); }"#) .file("examples/ex1.rs", r#"fn main() { println!("ex1"); }"#) .publish(); cargo_process("install foo --bin foo").run(); installed_process("foo") .with_stdout_data(str![[r#" foo "#]]) .run(); assert!(!installed_exe("a").exists()); assert!(!installed_exe("ex1").exists()); validate_trackers("foo", "1.0.0", &["foo"]); cargo_process("install foo --bin a").run(); installed_process("a") .with_stdout_data(str![[r#" a "#]]) .run(); assert!(!installed_exe("ex1").exists()); validate_trackers("foo", "1.0.0", &["a", "foo"]); cargo_process("install foo --example ex1").run(); installed_process("ex1") .with_stdout_data(str![[r#" ex1 "#]]) .run(); validate_trackers("foo", "1.0.0", &["a", "ex1", "foo"]); cargo_process("uninstall foo --bin foo").run(); assert!(!installed_exe("foo").exists()); assert!(installed_exe("ex1").exists()); validate_trackers("foo", "1.0.0", &["a", "ex1"]); cargo_process("uninstall foo").run(); assert!(!installed_exe("ex1").exists()); assert!(!installed_exe("a").exists()); } #[cargo_test] fn v1_already_installed_fresh() { // Install with v1, then try to install again with v2. pkg("foo", "1.0.0"); cargo_process("install foo").run(); cargo_process("install foo") .with_stderr_data(str![[r#" ... [IGNORED] package `foo v1.0.0` is already installed, use --force to override ... "#]]) .run(); } #[cargo_test] fn v1_already_installed_dirty() { // Install with v1, then install a new version with v2. pkg("foo", "1.0.0"); cargo_process("install foo").run(); pkg("foo", "1.0.1"); cargo_process("install foo") .with_stderr_data(str![[r#" ... [COMPILING] foo v1.0.1 ... [REPLACING] [ROOT]/home/.cargo/bin/foo[EXE] ... "#]]) .run(); validate_trackers("foo", "1.0.1", &["foo"]); } #[cargo_test] fn change_features_rebuilds() { Package::new("foo", "1.0.0") .file( "src/main.rs", r#" fn main() { if cfg!(feature = "f1") { println!("f1"); } if cfg!(feature = "f2") { println!("f2"); } } "#, ) .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" [features] f1 = [] f2 = [] default = ["f1"] "#, ) .publish(); cargo_process("install foo").run(); installed_process("foo") .with_stdout_data(str![[r#" f1 "#]]) .run(); cargo_process("install foo --no-default-features").run(); installed_process("foo").with_stdout_data("").run(); cargo_process("install foo --all-features").run(); installed_process("foo") .with_stdout_data(str![[r#" f1 f2 "#]]) .run(); cargo_process("install foo --no-default-features --features=f1").run(); installed_process("foo") .with_stdout_data(str![[r#" f1 "#]]) .run(); } #[cargo_test] fn change_profile_rebuilds() { pkg("foo", "1.0.0"); cargo_process("install foo").run(); cargo_process("install foo --debug") .with_stderr_data(str![[r#" ... [COMPILING] foo v1.0.0 ... [REPLACING] [ROOT]/home/.cargo/bin/foo[EXE] ... "#]]) .run(); cargo_process("install foo --debug") .with_stderr_data(str![[r#" ... [IGNORED] package `foo v1.0.0` is already installed, use --force to override ... "#]]) .run(); } #[cargo_test] fn change_target_rebuilds() { if cross_compile::disabled() { return; } pkg("foo", "1.0.0"); cargo_process("install foo").run(); let target = cross_compile::alternate(); cargo_process("install foo -v --target") .arg(&target) .with_stderr_data(str![[r#" ... [COMPILING] foo v1.0.0 [RUNNING] `rustc [..]--target [ALT_TARGET][..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [REPLACING] [ROOT]/home/.cargo/bin/foo[EXE] ... "#]]) .run(); } #[cargo_test] fn change_bin_sets_rebuilds() { // Changing which bins in a multi-bin project should reinstall. Package::new("foo", "1.0.0") .file("src/main.rs", "fn main() { }") .file("src/bin/x.rs", "fn main() { }") .file("src/bin/y.rs", "fn main() { }") .publish(); cargo_process("install foo --bin x").run(); assert!(installed_exe("x").exists()); assert!(!installed_exe("y").exists()); assert!(!installed_exe("foo").exists()); validate_trackers("foo", "1.0.0", &["x"]); cargo_process("install foo --bin y") .with_stderr_data(str![[r#" ... [INSTALLED] package `foo v1.0.0` (executable `y[EXE]`) ... "#]]) .run(); assert!(installed_exe("x").exists()); assert!(installed_exe("y").exists()); assert!(!installed_exe("foo").exists()); validate_trackers("foo", "1.0.0", &["x", "y"]); cargo_process("install foo") .with_stderr_data(str![[r#" ... [INSTALLED] package `foo v1.0.0` (executable `foo[EXE]`) [REPLACED] package `foo v1.0.0` with `foo v1.0.0` (executables `x[EXE]`, `y[EXE]`) ... "#]]) .run(); assert!(installed_exe("x").exists()); assert!(installed_exe("y").exists()); assert!(installed_exe("foo").exists()); validate_trackers("foo", "1.0.0", &["foo", "x", "y"]); } #[cargo_test] fn forwards_compatible() { // Unknown fields should be preserved. pkg("foo", "1.0.0"); pkg("bar", "1.0.0"); cargo_process("install foo").run(); let key = "foo 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)"; let v2 = paths::cargo_home().join(".crates2.json"); let mut data = load_crates2(); data["newfield"] = serde_json::Value::Bool(true); data["installs"][key]["moreinfo"] = serde_json::Value::String("shazam".to_string()); fs::write(&v2, serde_json::to_string(&data).unwrap()).unwrap(); cargo_process("install bar").run(); let data: serde_json::Value = serde_json::from_str(&fs::read_to_string(&v2).unwrap()).unwrap(); assert_eq!(data["newfield"].as_bool().unwrap(), true); assert_eq!( data["installs"][key]["moreinfo"].as_str().unwrap(), "shazam" ); } #[cargo_test] fn v2_syncs() { // V2 inherits the installs from V1. pkg("one", "1.0.0"); pkg("two", "1.0.0"); pkg("three", "1.0.0"); let p = project() .file("src/bin/x.rs", "fn main() {}") .file("src/bin/y.rs", "fn main() {}") .build(); cargo_process("install one").run(); validate_trackers("one", "1.0.0", &["one"]); p.cargo("install --path .").run(); validate_trackers("foo", "1.0.0", &["x", "y"]); // v1 add/remove cargo_process("install two").run(); cargo_process("uninstall one").run(); // This should pick up that `two` was added, `one` was removed. cargo_process("install three").run(); validate_trackers("three", "1.0.0", &["three"]); cargo_process("install --list") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo): x[EXE] y[EXE] three v1.0.0: three[EXE] two v1.0.0: two[EXE] "#]]) .run(); cargo_process("install one").run(); installed_process("one") .with_stdout_data(str![[r#" 1.0.0 "#]]) .run(); validate_trackers("one", "1.0.0", &["one"]); cargo_process("install two") .with_stderr_data(str![[r#" ... [IGNORED] package `two v1.0.0` is already installed, use --force to override ... "#]]) .run(); // v1 remove p.cargo("uninstall --bin x").run(); pkg("x", "1.0.0"); pkg("y", "1.0.0"); // This should succeed because `x` was removed in V1. cargo_process("install x").run(); validate_trackers("x", "1.0.0", &["x"]); // This should fail because `y` still exists in a different package. cargo_process("install y") .with_stderr_data(str![[r#" ... [ERROR] binary `y[EXE]` already exists in destination as part of `foo v0.0.1 ([ROOT]/foo)` ... "#]]) .with_status(101) .run(); } #[cargo_test] fn upgrade_git() { let git_project = git::new("foo", |project| project.file("src/main.rs", "fn main() {}")); // install cargo_process("install --git") .arg(git_project.url().to_string()) .run(); // Check install stays fresh. cargo_process("install --git") .arg(git_project.url().to_string()) .with_stderr_data(str![[r#" ... [IGNORED] package `foo v0.0.1 ([ROOTURL]/foo#[..])` is already installed, use --force to override ... "#]]) .run(); // Modify a file. let repo = git2::Repository::open(git_project.root()).unwrap(); git_project.change_file("src/main.rs", r#"fn main() {println!("onomatopoeia");}"#); git::add(&repo); git::commit(&repo); // Install should reinstall. cargo_process("install --git") .arg(git_project.url().to_string()) .with_stderr_data(str![[r#" ... [COMPILING] foo v0.0.1 ([ROOT]/home/.cargo/git/checkouts/foo-[HASH]/[..]) ... [REPLACING] [ROOT]/home/.cargo/bin/foo[EXE] ... "#]]) .run(); installed_process("foo") .with_stdout_data(str![[r#" onomatopoeia "#]]) .run(); // Check install stays fresh. cargo_process("install --git") .arg(git_project.url().to_string()) .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/foo` [IGNORED] package `foo v0.0.1 ([ROOTURL]/foo#[..])` is already installed, use --force to override [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); } #[cargo_test] fn switch_sources() { // Installing what appears to be the same thing, but from different // sources should reinstall. registry::alt_init(); pkg("foo", "1.0.0"); Package::new("foo", "1.0.0") .file("src/main.rs", r#"fn main() { println!("alt"); }"#) .alternative(true) .publish(); let p = project() .at("foo-local") // so it doesn't use the same directory as the git project .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/main.rs", r#"fn main() { println!("local"); }"#) .build(); let git_project = git::new("foo", |project| { project.file("src/main.rs", r#"fn main() { println!("git"); }"#) }); cargo_process("install foo").run(); installed_process("foo") .with_stdout_data(str![[r#" 1.0.0 "#]]) .run(); cargo_process("install foo --registry alternative").run(); installed_process("foo") .with_stdout_data(str![[r#" alt "#]]) .run(); p.cargo("install --path .").run(); installed_process("foo") .with_stdout_data(str![[r#" local "#]]) .run(); cargo_process("install --git") .arg(git_project.url().to_string()) .run(); installed_process("foo") .with_stdout_data(str![[r#" git "#]]) .run(); } #[cargo_test] fn multiple_report() { // Testing the full output that indicates installed/ignored/replaced/summary. pkg("one", "1.0.0"); pkg("two", "1.0.0"); fn three(vers: &str) { Package::new("three", vers) .file("src/main.rs", "fn main() { }") .file("src/bin/x.rs", "fn main() { }") .file("src/bin/y.rs", "fn main() { }") .publish(); } three("1.0.0"); cargo_process("install one two three") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] one v1.0.0 (registry `dummy-registry`) [DOWNLOADING] crates ... [DOWNLOADED] two v1.0.0 (registry `dummy-registry`) [DOWNLOADING] crates ... [DOWNLOADED] three v1.0.0 (registry `dummy-registry`) [INSTALLING] one v1.0.0 [COMPILING] one v1.0.0 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/one[EXE] [INSTALLED] package `one v1.0.0` (executable `one[EXE]`) [INSTALLING] two v1.0.0 [COMPILING] two v1.0.0 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/two[EXE] [INSTALLED] package `two v1.0.0` (executable `two[EXE]`) [INSTALLING] three v1.0.0 [COMPILING] three v1.0.0 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/three[EXE] [INSTALLING] [ROOT]/home/.cargo/bin/x[EXE] [INSTALLING] [ROOT]/home/.cargo/bin/y[EXE] [INSTALLED] package `three v1.0.0` (executables `three[EXE]`, `x[EXE]`, `y[EXE]`) [SUMMARY] Successfully installed one, two, three! [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); pkg("foo", "1.0.1"); pkg("bar", "1.0.1"); three("1.0.1"); cargo_process("install one two three") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [IGNORED] package `one v1.0.0` is already installed, use --force to override [IGNORED] package `two v1.0.0` is already installed, use --force to override [DOWNLOADING] crates ... [DOWNLOADED] three v1.0.1 (registry `dummy-registry`) [INSTALLING] three v1.0.1 [COMPILING] three v1.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [REPLACING] [ROOT]/home/.cargo/bin/three[EXE] [REPLACING] [ROOT]/home/.cargo/bin/x[EXE] [REPLACING] [ROOT]/home/.cargo/bin/y[EXE] [REPLACED] package `three v1.0.0` with `three v1.0.1` (executables `three[EXE]`, `x[EXE]`, `y[EXE]`) [SUMMARY] Successfully installed one, two, three! [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); cargo_process("uninstall three") .with_stderr_data(str![[r#" [REMOVING] [ROOT]/home/.cargo/bin/three[EXE] [REMOVING] [ROOT]/home/.cargo/bin/x[EXE] [REMOVING] [ROOT]/home/.cargo/bin/y[EXE] "#]]) .run(); cargo_process("install three --bin x") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [INSTALLING] three v1.0.1 [COMPILING] three v1.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/x[EXE] [INSTALLED] package `three v1.0.1` (executable `x[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); cargo_process("install three") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [INSTALLING] three v1.0.1 [COMPILING] three v1.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/three[EXE] [INSTALLING] [ROOT]/home/.cargo/bin/y[EXE] [REPLACING] [ROOT]/home/.cargo/bin/x[EXE] [INSTALLED] package `three v1.0.1` (executables `three[EXE]`, `y[EXE]`) [REPLACED] package `three v1.0.1` with `three v1.0.1` (executable `x[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); } #[cargo_test] fn no_track() { pkg("foo", "1.0.0"); cargo_process("install --no-track foo").run(); assert!(!v1_path().exists()); assert!(!v2_path().exists()); cargo_process("install --no-track foo") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] binary `foo[EXE]` already exists in destination `[ROOT]/home/.cargo/bin/foo[EXE]` Add --force to overwrite "#]]) .with_status(101) .run(); } #[cargo_test] fn deletes_orphaned() { // When an executable is removed from a project, upgrading should remove it. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" "#, ) .file("src/main.rs", "fn main() {}") .file("src/bin/other.rs", "fn main() {}") .file("examples/ex1.rs", "fn main() {}") .build(); p.cargo("install --path . --bins --examples").run(); assert!(installed_exe("other").exists()); // Remove a binary, add a new one, and bump the version. fs::remove_file(p.root().join("src/bin/other.rs")).unwrap(); p.change_file("examples/ex2.rs", "fn main() {}"); p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.2.0" "#, ); p.cargo("install --path . --bins --examples") .with_stderr_data(str![[r#" [INSTALLING] foo v0.2.0 ([ROOT]/foo) [COMPILING] foo v0.2.0 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/ex2[EXE] [REPLACING] [ROOT]/home/.cargo/bin/ex1[EXE] [REPLACING] [ROOT]/home/.cargo/bin/foo[EXE] [REMOVING] executable `[ROOT]/home/.cargo/bin/other[EXE]` from previous version foo v0.1.0 ([ROOT]/foo) [INSTALLED] package `foo v0.2.0 ([ROOT]/foo)` (executable `ex2[EXE]`) [REPLACED] package `foo v0.1.0 ([ROOT]/foo)` with `foo v0.2.0 ([ROOT]/foo)` (executables `ex1[EXE]`, `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); assert!(!installed_exe("other").exists()); validate_trackers("foo", "0.2.0", &["foo", "ex1", "ex2"]); // 0.1.0 should not have any entries. validate_trackers("foo", "0.1.0", &[]); } #[cargo_test] fn already_installed_exact_does_not_update() { pkg("foo", "1.0.0"); cargo_process("install foo --version=1.0.0").run(); cargo_process("install foo --version=1.0.0") .with_stderr_data(str![[r#" [IGNORED] package `foo v1.0.0` is already installed, use --force to override [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); cargo_process("install foo --version=>=1.0.0") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [IGNORED] package `foo v1.0.0` is already installed, use --force to override [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); pkg("foo", "1.0.1"); cargo_process("install foo --version=>=1.0.0") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v1.0.1 (registry `dummy-registry`) [INSTALLING] foo v1.0.1 [COMPILING] foo v1.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [REPLACING] [ROOT]/home/.cargo/bin/foo[EXE] [REPLACED] package `foo v1.0.0` with `foo v1.0.1` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); } #[cargo_test] fn already_installed_updates_yank_status_on_upgrade() { pkg("foo", "1.0.0"); pkg_maybe_yanked("foo", "1.0.1", true); cargo_process("install foo --version=1.0.0").run(); cargo_process("install foo --version=1.0.1") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] cannot install package `foo`, it has been yanked from registry `crates-io` "#]]) .run(); pkg_maybe_yanked("foo", "1.0.1", false); pkg("foo", "1.0.1"); cargo_process("install foo --version=1.0.1") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v1.0.1 (registry `dummy-registry`) [INSTALLING] foo v1.0.1 [COMPILING] foo v1.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [REPLACING] [ROOT]/home/.cargo/bin/foo[EXE] [REPLACED] package `foo v1.0.0` with `foo v1.0.1` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); } #[cargo_test] fn partially_already_installed_does_one_update() { pkg("foo", "1.0.0"); cargo_process("install foo --version=1.0.0").run(); pkg("bar", "1.0.0"); pkg("baz", "1.0.0"); cargo_process("install foo bar baz --version=1.0.0") .with_stderr_data(str![[r#" [IGNORED] package `foo v1.0.0` is already installed, use --force to override [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [DOWNLOADING] crates ... [DOWNLOADED] baz v1.0.0 (registry `dummy-registry`) [INSTALLING] bar v1.0.0 [COMPILING] bar v1.0.0 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/bar[EXE] [INSTALLED] package `bar v1.0.0` (executable `bar[EXE]`) [INSTALLING] baz v1.0.0 [COMPILING] baz v1.0.0 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/baz[EXE] [INSTALLED] package `baz v1.0.0` (executable `baz[EXE]`) [SUMMARY] Successfully installed foo, bar, baz! [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); } cargo-0.86.0/tests/testsuite/jobserver.rs000064400000000000000000000242521046102023000165610ustar 00000000000000//! Tests for the jobserver protocol. use std::env; use std::net::TcpListener; use std::process::Command; use std::thread; use cargo_test_support::basic_bin_manifest; use cargo_test_support::cargo_exe; use cargo_test_support::install::assert_has_installed_exe; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::{project, rustc_host, str}; use cargo_util::is_ci; const EXE_CONTENT: &str = r#" use std::env; fn main() { let var = env::var("CARGO_MAKEFLAGS").expect("no jobserver from env"); let arg = var.split(' ') .find(|p| p.starts_with("--jobserver")) .unwrap(); let val = &arg[arg.find('=').unwrap() + 1..]; validate(val); } #[cfg(unix)] fn validate(s: &str) { use std::fs::{self, File}; use std::io::*; use std::os::unix::prelude::*; if let Some((r, w)) = s.split_once(',') { // `--jobserver-auth=R,W` unsafe { let mut read = File::from_raw_fd(r.parse().unwrap()); let mut write = File::from_raw_fd(w.parse().unwrap()); let mut buf = [0]; assert_eq!(read.read(&mut buf).unwrap(), 1); assert_eq!(write.write(&buf).unwrap(), 1); } } else { // `--jobserver-auth=fifo:PATH` is the default since GNU Make 4.4 let (_, path) = s.split_once(':').expect("fifo:PATH"); assert!(fs::metadata(path).unwrap().file_type().is_fifo()); } } #[cfg(windows)] fn validate(_: &str) { // a little too complicated for a test... } "#; fn make_exe() -> &'static str { if cfg!(windows) { "mingw32-make" } else if cfg!(target_os = "aix") { "gmake" } else { "make" } } #[cargo_test] fn jobserver_exists() { let p = project() .file("build.rs", EXE_CONTENT) .file("src/lib.rs", "") .build(); // Explicitly use `-j2` to ensure that there's eventually going to be a // token to read from `validate` above, since running the build script // itself consumes a token. p.cargo("check -j2").run(); } #[cargo_test] fn external_subcommand_inherits_jobserver() { let make = make_exe(); if Command::new(make).arg("--version").output().is_err() { return; } let name = "cargo-jobserver-check"; let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "{name}" version = "0.0.1" "# ), ) .file("src/main.rs", EXE_CONTENT) .file( "Makefile", "\ all: \t+$(CARGO) jobserver-check ", ) .build(); p.cargo("install --path .").run(); assert_has_installed_exe(paths::cargo_home(), name); p.process(make).env("CARGO", cargo_exe()).arg("-j2").run(); } #[cargo_test] fn runner_inherits_jobserver() { let make = make_exe(); if Command::new(make).arg("--version").output().is_err() { return; } let runner = "runner"; project() .at(runner) .file("Cargo.toml", &basic_bin_manifest(runner)) .file( "src/main.rs", r#" pub fn main() { eprintln!("this is a runner"); let args: Vec = std::env::args().collect(); let status = std::process::Command::new(&args[1]).status().unwrap(); assert!(status.success()); } "#, ) .build() .cargo("install --path .") .run(); // Add .cargo/bin to PATH let mut path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect(); path.push(paths::cargo_home().join("bin")); let path = &env::join_paths(path).unwrap(); assert_has_installed_exe(paths::cargo_home(), runner); let host = rustc_host(); let config_value = &format!("target.{host}.runner = \"{runner}\""); let name = "cargo-jobserver-check"; let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "{name}" version = "0.0.1" edition = "2015" "# ), ) .file( "src/lib.rs", r#" #[test] fn test() { _ = std::env::var("CARGO_MAKEFLAGS").expect("no jobserver from env"); } "#, ) .file("src/main.rs", EXE_CONTENT) .file( "Makefile", &format!( "\ run: \t+$(CARGO) run run-runner: \t+$(CARGO) run --config '{config_value}' test: \t+$(CARGO) test --lib test-runner: \t+$(CARGO) test --lib --config '{config_value}' ", ), ) .build(); // jobserver can be inherited from env p.process(make) .env("CARGO", cargo_exe()) .arg("run") .arg("-j2") .run(); p.process(make) .env("PATH", path) .env("CARGO", cargo_exe()) .arg("run-runner") .arg("-j2") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `runner target/debug/cargo-jobserver-check[EXE]` this is a runner "#]]) .run(); p.process(make) .env("CARGO", cargo_exe()) .arg("test") .arg("-j2") .run(); p.process(make) .env("PATH", path) .env("CARGO", cargo_exe()) .arg("test-runner") .arg("-j2") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/cargo_jobserver_check-[HASH][EXE]) this is a runner "#]]) .run(); // but not from `-j` flag p.cargo("run -j2") .with_status(101) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/cargo-jobserver-check[EXE]` ... [..]no jobserver from env[..] ... "#]]) .run(); p.cargo("run -j2") .env("PATH", path) .arg("--config") .arg(config_value) .with_status(101) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `runner target/debug/cargo-jobserver-check[EXE]` this is a runner ... [..]no jobserver from env[..] ... "#]]) .run(); p.cargo("test -j2") .with_status(101) .with_stdout_data("...\n[..]no jobserver from env[..]\n...") .run(); p.cargo("test -j2") .env("PATH", path) .arg("--config") .arg(config_value) .with_status(101) .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/cargo_jobserver_check-[HASH][EXE]) this is a runner ... "#]]) .with_stdout_data("...\n[..]no jobserver from env[..]\n...") .run(); } #[cargo_test] fn makes_jobserver_used() { let make = make_exe(); if !is_ci() && Command::new(make).arg("--version").output().is_err() { return; } let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [dependencies] d1 = { path = "d1" } d2 = { path = "d2" } d3 = { path = "d3" } "#, ) .file("src/lib.rs", "") .file( "d1/Cargo.toml", r#" [package] name = "d1" version = "0.0.1" authors = [] build = "../dbuild.rs" "#, ) .file("d1/src/lib.rs", "") .file( "d2/Cargo.toml", r#" [package] name = "d2" version = "0.0.1" authors = [] build = "../dbuild.rs" "#, ) .file("d2/src/lib.rs", "") .file( "d3/Cargo.toml", r#" [package] name = "d3" version = "0.0.1" authors = [] build = "../dbuild.rs" "#, ) .file("d3/src/lib.rs", "") .file( "dbuild.rs", r#" use std::net::TcpStream; use std::env; use std::io::Read; fn main() { let addr = env::var("ADDR").unwrap(); let mut stream = TcpStream::connect(addr).unwrap(); let mut v = Vec::new(); stream.read_to_end(&mut v).unwrap(); } "#, ) .file( "Makefile", "\ all: \t+$(CARGO) build ", ) .build(); let l = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = l.local_addr().unwrap(); let child = thread::spawn(move || { let a1 = l.accept().unwrap(); let a2 = l.accept().unwrap(); l.set_nonblocking(true).unwrap(); for _ in 0..1000 { assert!(l.accept().is_err()); thread::yield_now(); } drop(a1); l.set_nonblocking(false).unwrap(); let a3 = l.accept().unwrap(); drop((a2, a3)); }); p.process(make) .env("CARGO", cargo_exe()) .env("ADDR", addr.to_string()) .arg("-j2") .run(); child.join().unwrap(); } #[cargo_test] fn jobserver_and_j() { let make = make_exe(); if !is_ci() && Command::new(make).arg("--version").output().is_err() { return; } let p = project() .file("src/lib.rs", "") .file( "Makefile", "\ all: \t+$(CARGO) build -j2 ", ) .build(); p.process(make) .env("CARGO", cargo_exe()) .arg("-j2") .with_stderr_data(str![[r#" [WARNING] a `-j` argument was passed to Cargo but Cargo is also configured with an external jobserver in its environment, ignoring the `-j` parameter [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/lints/error/mod.rs000064400000000000000000000014021046102023000176110ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::{file, project}; #[cargo_test] fn case() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] im-a-teapot = true [lints.cargo] im_a_teapot = "deny" "#, ) .file("src/lib.rs", "") .build(); snapbox::cmd::Command::cargo_ui() .masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"]) .current_dir(p.root()) .arg("check") .arg("-Zcargo-lints") .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/lints/error/stderr.term.svg000064400000000000000000000031571046102023000214670ustar 00000000000000 error: `im_a_teapot` is specified --> Cargo.toml:9:1 | 9 | im-a-teapot = true | ^^^^^^^^^^^^^^^^^^ | = note: `cargo::im_a_teapot` is set to `deny` in `[lints]` cargo-0.86.0/tests/testsuite/lints/inherited/mod.rs000064400000000000000000000015161046102023000204410ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::{file, project}; #[cargo_test] fn case() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo"] [workspace.lints.cargo] im_a_teapot = { level = "warn", priority = 10 } "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lints] workspace = true "#, ) .file("foo/src/lib.rs", "") .build(); snapbox::cmd::Command::cargo_ui() .masquerade_as_nightly_cargo(&["cargo-lints"]) .current_dir(p.root()) .arg("check") .arg("-Zcargo-lints") .assert() .code(101) .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/lints/inherited/stderr.term.svg000064400000000000000000000053701046102023000223100ustar 00000000000000 error: use of unstable lint `im_a_teapot` --> Cargo.toml:6:1 | 6 | im_a_teapot = { level = "warn", priority = 10 } | ^^^^^^^^^^^ this is behind `test-dummy-unstable`, which is not enabled | note: `cargo::im_a_teapot` was inherited --> foo/Cargo.toml:9:1 | 9 | workspace = true | ---------------- | = help: consider adding `cargo-features = ["test-dummy-unstable"]` to the top of the manifest error: encountered 1 errors(s) while verifying lints cargo-0.86.0/tests/testsuite/lints/mod.rs000064400000000000000000000157111046102023000164700ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry::Package; use cargo_test_support::str; mod error; mod inherited; mod unknown_lints; mod warning; #[cargo_test] fn dashes_dont_get_rewritten() { let foo = project() .file( "Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] im-a-teapot = true [lints.cargo] im-a-teapot = "warn" "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check -Zcargo-lints") .masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"]) .with_stderr_data(str![[r#" [WARNING] unknown lint: `im-a-teapot` --> Cargo.toml:12:1 | 12 | im-a-teapot = "warn" | ^^^^^^^^^^^ | = [NOTE] `cargo::unknown_lints` is set to `warn` by default = [HELP] there is a lint with a similar name: `im_a_teapot` [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn forbid_not_overridden() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] im-a-teapot = true [lints.cargo] im_a_teapot = { level = "warn", priority = 10 } test_dummy_unstable = { level = "forbid", priority = -1 } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -Zcargo-lints") .masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] `im_a_teapot` is specified --> Cargo.toml:9:1 | 9 | im-a-teapot = true | ^^^^^^^^^^^^^^^^^^ | = [NOTE] `cargo::im_a_teapot` is set to `forbid` in `[lints]` "#]]) .run(); } #[cargo_test] fn workspace_lints() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [workspace.lints.cargo] im_a_teapot = { level = "warn", priority = 10 } test_dummy_unstable = { level = "forbid", priority = -1 } [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] im-a-teapot = true [lints] workspace = true "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -Zcargo-lints") .masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] `im_a_teapot` is specified --> Cargo.toml:13:1 | 13 | im-a-teapot = true | ^^^^^^^^^^^^^^^^^^ | = [NOTE] `cargo::im_a_teapot` is set to `forbid` in `[lints]` "#]]) .run(); } #[cargo_test] fn dont_always_inherit_workspace_lints() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo"] [workspace.lints.cargo] im_a_teapot = "warn" "#, ) .file( "foo/Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] im-a-teapot = true "#, ) .file("foo/src/lib.rs", "") .build(); p.cargo("check -Zcargo-lints") .masquerade_as_nightly_cargo(&["cargo-lints"]) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cap_lints() { Package::new("baz", "0.1.0").publish(); Package::new("bar", "0.1.0") .file( "Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "bar" version = "0.1.0" edition = "2021" im-a-teapot = true [dependencies] baz = { version = "0.1.0", optional = true } [lints.cargo] im_a_teapot = "warn" "#, ) .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2021" [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -Zcargo-lints") .masquerade_as_nightly_cargo(&["cargo-lints"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [CHECKING] bar v0.1.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn check_feature_gated() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lints.cargo] im_a_teapot = "warn" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -Zcargo-lints") .masquerade_as_nightly_cargo(&["cargo-lints"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] use of unstable lint `im_a_teapot` --> Cargo.toml:9:1 | 9 | im_a_teapot = "warn" | ^^^^^^^^^^^ this is behind `test-dummy-unstable`, which is not enabled | = [HELP] consider adding `cargo-features = ["test-dummy-unstable"]` to the top of the manifest [ERROR] encountered 1 errors(s) while verifying lints "#]]) .run(); } #[cargo_test] fn check_feature_gated_workspace() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo"] [workspace.lints.cargo] im_a_teapot = { level = "warn", priority = 10 } test_dummy_unstable = { level = "forbid", priority = -1 } "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lints] workspace = true "#, ) .file("foo/src/lib.rs", "") .build(); p.cargo("check -Zcargo-lints") .masquerade_as_nightly_cargo(&["cargo-lints"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] use of unstable lint `im_a_teapot` --> Cargo.toml:6:1 | 6 | im_a_teapot = { level = "warn", priority = 10 } | ^^^^^^^^^^^ this is behind `test-dummy-unstable`, which is not enabled | [NOTE] `cargo::im_a_teapot` was inherited --> foo/Cargo.toml:9:1 | 9 | workspace = true | ---------------- | = [HELP] consider adding `cargo-features = ["test-dummy-unstable"]` to the top of the manifest [ERROR] use of unstable lint `test_dummy_unstable` --> Cargo.toml:7:1 | 7 | test_dummy_unstable = { level = "forbid", priority = -1 } | ^^^^^^^^^^^^^^^^^^^ this is behind `test-dummy-unstable`, which is not enabled | [NOTE] `cargo::test_dummy_unstable` was inherited --> foo/Cargo.toml:9:1 | 9 | workspace = true | ---------------- | = [HELP] consider adding `cargo-features = ["test-dummy-unstable"]` to the top of the manifest [ERROR] encountered 2 errors(s) while verifying lints "#]]) .run(); } cargo-0.86.0/tests/testsuite/lints/unknown_lints.rs000064400000000000000000000035741046102023000206250ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; #[cargo_test] fn default() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lints.cargo] this-lint-does-not-exist = "warn" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -Zcargo-lints") .masquerade_as_nightly_cargo(&["cargo-lints"]) .with_stderr_data(str![[r#" [WARNING] unknown lint: `this-lint-does-not-exist` --> Cargo.toml:9:1 | 9 | this-lint-does-not-exist = "warn" | ^^^^^^^^^^^^^^^^^^^^^^^^ | = [NOTE] `cargo::unknown_lints` is set to `warn` by default [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn inherited() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo"] [workspace.lints.cargo] this-lint-does-not-exist = "warn" "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lints] workspace = true "#, ) .file("foo/src/lib.rs", "") .build(); p.cargo("check -Zcargo-lints") .masquerade_as_nightly_cargo(&["cargo-lints"]) .with_stderr_data(str![[r#" [WARNING] unknown lint: `this-lint-does-not-exist` --> Cargo.toml:6:1 | 6 | this-lint-does-not-exist = "warn" | ^^^^^^^^^^^^^^^^^^^^^^^^ | [NOTE] `cargo::this-lint-does-not-exist` was inherited --> foo/Cargo.toml:9:1 | 9 | workspace = true | ---------------- | = [NOTE] `cargo::unknown_lints` is set to `warn` by default [CHECKING] foo v0.0.1 ([ROOT]/foo/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/lints/warning/mod.rs000064400000000000000000000014021046102023000201250ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::{file, project}; #[cargo_test] fn case() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] im-a-teapot = true [lints.cargo] im_a_teapot = "warn" "#, ) .file("src/lib.rs", "") .build(); snapbox::cmd::Command::cargo_ui() .masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"]) .current_dir(p.root()) .arg("check") .arg("-Zcargo-lints") .assert() .success() .stdout_eq(str![""]) .stderr_eq(file!["stderr.term.svg"]); } cargo-0.86.0/tests/testsuite/lints/warning/stderr.term.svg000064400000000000000000000036551046102023000220060ustar 00000000000000 warning: `im_a_teapot` is specified --> Cargo.toml:9:1 | 9 | im-a-teapot = true | ------------------ | = note: `cargo::im_a_teapot` is set to `warn` in `[lints]` Checking foo v0.0.1 ([ROOT]/foo) Finished `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s cargo-0.86.0/tests/testsuite/lints_table.rs000064400000000000000000000435361046102023000170660ustar 00000000000000//! Tests for `[lints]` use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry::Package; use cargo_test_support::str; #[cargo_test] fn dependency_warning_ignored() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar.path = "../bar" "#, ) .file("src/lib.rs", "") .build(); let _bar = project() .at("bar") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [lints.rust] unsafe_code = "forbid" "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.0.1 ([ROOT]/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn malformed_on_stable() { let foo = project() .file( "Cargo.toml", r#" lints = 20 [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid type: integer `20`, expected a lints table --> Cargo.toml:2:25 | 2 | lints = 20 | ^^ | "#]]) .run(); } #[cargo_test] fn fail_on_invalid_tool() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [workspace.lints.super-awesome-linter] unsafe_code = "forbid" "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check").with_stderr_data(str![[r#" [WARNING] [ROOT]/foo/Cargo.toml: unrecognized lint tool `lints.super-awesome-linter`, specifying unrecognized tools may break in the future. supported tools: cargo, clippy, rust, rustdoc [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn invalid_type_in_lint_value() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [workspace.lints.rust] rust-2018-idioms = -1 "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid type: integer `-1`, expected a string or map --> Cargo.toml:8:36 | 8 | rust-2018-idioms = -1 | ^^ | "#]]) .run(); } #[cargo_test] fn warn_on_unused_key() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [workspace.lints.rust] rust-2018-idioms = { level = "allow", unused = true } [lints.rust] rust-2018-idioms = { level = "allow", unused = true } "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") .with_stderr_data(str![[r#" [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: `lints.rust.rust-2018-idioms.unused` [WARNING] [ROOT]/foo/Cargo.toml: unused manifest key: `lints.rust.rust-2018-idioms.unused` [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn fail_on_tool_injection() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [workspace.lints.rust] "clippy::cyclomatic_complexity" = "warn" "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `lints.rust.clippy::cyclomatic_complexity` is not valid lint name; try `lints.clippy.cyclomatic_complexity` "#]]) .run(); } #[cargo_test] fn fail_on_redundant_tool() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [workspace.lints.rust] "rust::unsafe_code" = "forbid" "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `lints.rust.rust::unsafe_code` is not valid lint name; try `lints.rust.unsafe_code` "#]]) .run(); } #[cargo_test] fn fail_on_conflicting_tool() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [workspace.lints.rust] "super-awesome-tool::unsafe_code" = "forbid" "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `lints.rust.super-awesome-tool::unsafe_code` is not a valid lint name "#]]) .run(); } #[cargo_test] fn package_lint_deny() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lints.rust] "unsafe_code" = "deny" "#, ) .file( "src/lib.rs", " pub fn foo(num: i32) -> u32 { unsafe { std::mem::transmute(num) } } ", ) .build(); foo.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [ERROR] usage of an `unsafe` block ... "#]]) .run(); } #[cargo_test] fn workspace_cant_be_false() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lints] workspace = false [workspace.lints.rust] "unsafe_code" = "deny" "#, ) .file( "src/lib.rs", " pub fn foo(num: i32) -> u32 { unsafe { std::mem::transmute(num) } } ", ) .build(); foo.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `workspace` cannot be false --> Cargo.toml:9:29 | 9 | workspace = false | ^^^^^ | "#]]) .run(); } #[cargo_test] fn workspace_lint_deny() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lints] workspace = true [workspace.lints.rust] "unsafe_code" = "deny" "#, ) .file( "src/lib.rs", " pub fn foo(num: i32) -> u32 { unsafe { std::mem::transmute(num) } } ", ) .build(); foo.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [ERROR] usage of an `unsafe` block ... "#]]) .run(); } #[cargo_test] fn workspace_and_package_lints() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lints] workspace = true [lints.rust] "unsafe_code" = "allow" [workspace.lints.rust] "unsafe_code" = "deny" "#, ) .file( "src/lib.rs", " pub fn foo(num: i32) -> u32 { unsafe { std::mem::transmute(num) } } ", ) .build(); foo.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: cannot override `workspace.lints` in `lints`, either remove the overrides or `lints.workspace = true` and manually specify the lints "#]]) .run(); } #[cargo_test] fn attribute_has_precedence() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lints.rust] "unsafe_code" = "deny" "#, ) .file( "src/lib.rs", " #![allow(unsafe_code)] pub fn foo(num: i32) -> u32 { unsafe { std::mem::transmute(num) } } ", ) .build(); foo.cargo("check") .arg("-v") // Show order of rustflags on failure .run(); } #[cargo_test] fn rustflags_has_precedence() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lints.rust] "unsafe_code" = "deny" "#, ) .file( "src/lib.rs", " pub fn foo(num: i32) -> u32 { unsafe { std::mem::transmute(num) } } ", ) .build(); foo.cargo("check") .arg("-v") // Show order of rustflags on failure .env("RUSTFLAGS", "-Aunsafe_code") .run(); } #[cargo_test] fn profile_rustflags_has_precedence() { let foo = project() .file( "Cargo.toml", r#" cargo-features = ["profile-rustflags"] [package] name = "foo" version = "0.0.1" edition = "2015" [lints.rust] "unsafe_code" = "deny" [profile.dev] rustflags = ["-A", "unsafe_code"] "#, ) .file( "src/lib.rs", " pub fn foo(num: i32) -> u32 { unsafe { std::mem::transmute(num) } } ", ) .build(); foo.cargo("check") .arg("-v") // Show order of rustflags on failure .masquerade_as_nightly_cargo(&["profile-rustflags"]) .run(); } #[cargo_test] fn build_rustflags_has_precedence() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [lints.rust] "unsafe_code" = "deny" "#, ) .file( ".cargo/config.toml", r#" [build] rustflags = ["-A", "unsafe_code"] "#, ) .file( "src/lib.rs", " pub fn foo(num: i32) -> u32 { unsafe { std::mem::transmute(num) } } ", ) .build(); foo.cargo("check") .arg("-v") // Show order of rustflags on failure .run(); } #[cargo_test] fn without_priority() { Package::new("reg-dep", "1.0.0").publish(); let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2018" authors = [] [dependencies] reg-dep = "1.0.0" [lints.rust] "rust-2018-idioms" = "deny" "unused-extern-crates" = "allow" "#, ) .file( "src/lib.rs", " extern crate reg_dep; pub fn foo() -> u32 { 2 } ", ) .build(); foo.cargo("check") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] unused extern crate ... "#]]) .run(); } #[cargo_test] fn with_priority() { Package::new("reg-dep", "1.0.0").publish(); let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2018" authors = [] [dependencies] reg-dep = "1.0.0" [lints.rust] "rust-2018-idioms" = { level = "deny", priority = -1 } "unused-extern-crates" = "allow" "#, ) .file( "src/lib.rs", " extern crate reg_dep; pub fn foo() -> u32 { 2 } ", ) .build(); foo.cargo("check").run(); } #[cargo_test] fn rustdoc_lint() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lints.rustdoc] broken_intra_doc_links = "deny" "#, ) .file( "src/lib.rs", " /// [`bar`] doesn't exist pub fn foo() -> u32 { } ", ) .build(); foo.cargo("doc") .with_status(101) .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [ERROR] unresolved link to `bar` ... "#]]) .run(); } #[cargo_test] fn doctest_respects_lints() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lints.rust] confusable-idents = 'allow' "#, ) .file( "src/lib.rs", r#" /// Test /// /// [`Foo`] /// /// ``` /// let s = "rust"; /// let s_s = "rust2"; /// ``` pub fn f() {} pub const Ě: i32 = 1; pub const Δ”: i32 = 2; "#, ) .build(); foo.cargo("check") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); foo.cargo("test --doc") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [DOCTEST] foo "#]]) .run(); } #[cargo_test] fn cargo_lints_nightly_required() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lints.cargo] "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") .with_stderr_data(str![[r#" [WARNING] unused manifest key `lints.cargo` (may be supported in a future version) this Cargo does not support nightly features, but if you switch to nightly channel you can pass `-Zcargo-lints` to enable this feature. [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cargo_lints_no_z_flag() { let foo = project() .file( "Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] im-a-teapot = true [lints.cargo] "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") .masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"]) .with_stderr_data(str![[r#" [WARNING] unused manifest key `lints.cargo` (may be supported in a future version) consider passing `-Zcargo-lints` to enable this feature. [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cargo_lints_success() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] im-a-teapot = true [lints.cargo] im_a_teapot = "warn" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -Zcargo-lints") .masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"]) .with_stderr_data(str![[r#" [WARNING] `im_a_teapot` is specified --> Cargo.toml:9:1 | 9 | im-a-teapot = true | ------------------ | = [NOTE] `cargo::im_a_teapot` is set to `warn` in `[lints]` [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/list_availables.rs000064400000000000000000000474711046102023000177260ustar 00000000000000//! Tests for packages/target filter flags giving suggestions on which //! packages/targets are available. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; use snapbox::IntoData; fn list_availables_test(command: &str, expected: ExpectedSnapshots) { let full_project = project() .file("examples/a.rs", "fn main() { }") .file("examples/b.rs", "fn main() { }") .file("benches/bench1.rs", "") .file("benches/bench2.rs", "") .file("tests/test1.rs", "") .file("tests/test2.rs", "") .file("src/main.rs", "fn main() { }") .file("Cargo.lock", "") // for `cargo pkgid` .build(); if let ExpectedSnapshots { example: ProjectExpected { full: Some(example), .. }, .. } = expected { full_project .cargo(&format!("{} --example", command)) .with_stderr_data(example) .with_status(101) .run(); } if let ExpectedSnapshots { bin: ProjectExpected { full: Some(bin), .. }, .. } = expected { full_project .cargo(&format!("{} --bin", command)) .with_stderr_data(bin) .with_status(101) .run(); } if let ExpectedSnapshots { bench: ProjectExpected { full: Some(bench), .. }, .. } = expected { full_project .cargo(&format!("{} --bench", command)) .with_stderr_data(bench) .with_status(101) .run(); } if let ExpectedSnapshots { test: ProjectExpected { full: Some(test), .. }, .. } = expected { full_project .cargo(&format!("{} --test", command)) .with_stderr_data(test) .with_status(101) .run(); } if let ExpectedSnapshots { package: ProjectExpected { full: Some(package), .. }, .. } = expected { full_project .cargo(&format!("{} -p", command)) .with_stderr_data(package) .with_status(101) .run(); } let empty_project = project().file("src/lib.rs", "").build(); if let ExpectedSnapshots { example: ProjectExpected { empty: Some(example), .. }, .. } = expected { empty_project .cargo(&format!("{} --example", command)) .with_stderr_data(example) .with_status(101) .run(); } if let ExpectedSnapshots { bin: ProjectExpected { empty: Some(bin), .. }, .. } = expected { empty_project .cargo(&format!("{} --bin", command)) .with_stderr_data(bin) .with_status(101) .run(); } if let ExpectedSnapshots { bench: ProjectExpected { empty: Some(bench), .. }, .. } = expected { empty_project .cargo(&format!("{} --bench", command)) .with_stderr_data(bench) .with_status(101) .run(); } if let ExpectedSnapshots { test: ProjectExpected { empty: Some(test), .. }, .. } = expected { empty_project .cargo(&format!("{} --test", command)) .with_stderr_data(test) .with_status(101) .run(); } if let ExpectedSnapshots { target: ProjectExpected { empty: Some(target), .. }, .. } = expected { empty_project .cargo(&format!("{} --target", command)) .with_stderr_data(target) .with_status(101) .run(); } } #[cargo_test] fn build_list_availables() { list_availables_test( "build", SnapshotsBuilder::new() .with_example(str![[r#" [ERROR] "--example" takes one argument. Available examples: a b "#]], str![[r#" [ERROR] "--example" takes one argument. No examples available. "#]]) .with_bin(str![[r#" [ERROR] "--bin" takes one argument. Available binaries: foo "#]], str![[r#" [ERROR] "--bin" takes one argument. No binaries available. "#]]) .with_test(str![[r#" [ERROR] "--test" takes one argument. Available test targets: test1 test2 "#]], str![[r#" [ERROR] "--test" takes one argument. No test targets available. "#]]) .with_bench(str![[r#" [ERROR] "--bench" takes one argument. Available bench targets: bench1 bench2 "#]], str![[r#" [ERROR] "--bench" takes one argument. No bench targets available. "#]]) .with_package(str![[r#" [ERROR] "--package " requires a SPEC format value, which can be any package ID specifier in the dependency graph. Run `cargo help pkgid` for more information about SPEC format. Possible packages/workspace members: foo "#]]) .with_target(str![[r#" [ERROR] "--target" takes a target architecture as an argument. Run `[..]` to see possible targets. "#]]) .build(), ); } #[cargo_test] fn check_list_availables() { list_availables_test( "check", SnapshotsBuilder::new() .with_example(str![[r#" [ERROR] "--example" takes one argument. Available examples: a b "#]], str![[r#" [ERROR] "--example" takes one argument. No examples available. "#]]) .with_bin(str![[r#" [ERROR] "--bin" takes one argument. Available binaries: foo "#]], str![[r#" [ERROR] "--bin" takes one argument. No binaries available. "#]]) .with_test(str![[r#" [ERROR] "--test" takes one argument. Available test targets: test1 test2 "#]], str![[r#" [ERROR] "--test" takes one argument. No test targets available. "#]]) .with_bench(str![[r#" [ERROR] "--bench" takes one argument. Available bench targets: bench1 bench2 "#]], str![[r#" [ERROR] "--bench" takes one argument. No bench targets available. "#]]) .with_package(str![[r#" [ERROR] "--package " requires a SPEC format value, which can be any package ID specifier in the dependency graph. Run `cargo help pkgid` for more information about SPEC format. Possible packages/workspace members: foo "#]]) .with_target(str![[r#" [ERROR] "--target" takes a target architecture as an argument. Run `[..]` to see possible targets. "#]]) .build(), ); } #[cargo_test] fn doc_list_availables() { list_availables_test( "doc", SnapshotsBuilder::new() .with_bin(str![[r#" [ERROR] "--bin" takes one argument. Available binaries: foo "#]], str![[r#" [ERROR] "--bin" takes one argument. No binaries available. "#]]) .with_package(str![[r#" [ERROR] "--package " requires a SPEC format value, which can be any package ID specifier in the dependency graph. Run `cargo help pkgid` for more information about SPEC format. Possible packages/workspace members: foo "#]]) .with_target(str![[r#" [ERROR] "--target" takes a target architecture as an argument. Run `[..]` to see possible targets. "#]]) .build(), ); } #[cargo_test] fn fix_list_availables() { list_availables_test( "fix", SnapshotsBuilder::new() .with_example(str![[r#" [ERROR] "--example" takes one argument. Available examples: a b "#]], str![[r#" [ERROR] "--example" takes one argument. No examples available. "#]]) .with_bin(str![[r#" [ERROR] "--bin" takes one argument. Available binaries: foo "#]], str![[r#" [ERROR] "--bin" takes one argument. No binaries available. "#]]) .with_test(str![[r#" [ERROR] "--test" takes one argument. Available test targets: test1 test2 "#]], str![[r#" [ERROR] "--test" takes one argument. No test targets available. "#]]) .with_bench(str![[r#" [ERROR] "--bench" takes one argument. Available bench targets: bench1 bench2 "#]], str![[r#" [ERROR] "--bench" takes one argument. No bench targets available. "#]]) .with_package(str![[r#" [ERROR] "--package " requires a SPEC format value, which can be any package ID specifier in the dependency graph. Run `cargo help pkgid` for more information about SPEC format. Possible packages/workspace members: foo "#]]) .with_target(str![[r#" [ERROR] "--target" takes a target architecture as an argument. Run `[..]` to see possible targets. "#]]) .build(), ); } #[cargo_test] fn run_list_availables() { list_availables_test( "run", SnapshotsBuilder::new() .with_example(str![[r#" [ERROR] "--example" takes one argument. Available examples: a b "#]], str![[r#" [ERROR] "--example" takes one argument. No examples available. "#]]) .with_bin(str![[r#" [ERROR] "--bin" takes one argument. Available binaries: foo "#]], str![[r#" [ERROR] "--bin" takes one argument. No binaries available. "#]]) .with_package(str![[r#" [ERROR] "--package " requires a SPEC format value, which can be any package ID specifier in the dependency graph. Run `cargo help pkgid` for more information about SPEC format. Possible packages/workspace members: foo "#]]) .with_target(str![[r#" [ERROR] "--target" takes a target architecture as an argument. Run `[..]` to see possible targets. "#]]) .build(), ); } #[cargo_test] fn test_list_availables() { list_availables_test( "test", SnapshotsBuilder::new() .with_example(str![[r#" [ERROR] "--example" takes one argument. Available examples: a b "#]], str![[r#" [ERROR] "--example" takes one argument. No examples available. "#]]) .with_bin(str![[r#" [ERROR] "--bin" takes one argument. Available binaries: foo "#]], str![[r#" [ERROR] "--bin" takes one argument. No binaries available. "#]]) .with_test(str![[r#" [ERROR] "--test" takes one argument. Available test targets: test1 test2 "#]], str![[r#" [ERROR] "--test" takes one argument. No test targets available. "#]]) .with_bench(str![[r#" [ERROR] "--bench" takes one argument. Available bench targets: bench1 bench2 "#]], str![[r#" [ERROR] "--bench" takes one argument. No bench targets available. "#]]) .with_package(str![[r#" [ERROR] "--package " requires a SPEC format value, which can be any package ID specifier in the dependency graph. Run `cargo help pkgid` for more information about SPEC format. Possible packages/workspace members: foo "#]]) .with_target(str![[r#" [ERROR] "--target" takes a target architecture as an argument. Run `[..]` to see possible targets. "#]]) .build(), ); } #[cargo_test] fn bench_list_availables() { list_availables_test( "bench", SnapshotsBuilder::new() .with_example(str![[r#" [ERROR] "--example" takes one argument. Available examples: a b "#]], str![[r#" [ERROR] "--example" takes one argument. No examples available. "#]]) .with_bin(str![[r#" [ERROR] "--bin" takes one argument. Available binaries: foo "#]], str![[r#" [ERROR] "--bin" takes one argument. No binaries available. "#]]) .with_test(str![[r#" [ERROR] "--test" takes one argument. Available test targets: test1 test2 "#]], str![[r#" [ERROR] "--test" takes one argument. No test targets available. "#]]) .with_bench(str![[r#" [ERROR] "--bench" takes one argument. Available bench targets: bench1 bench2 "#]], str![[r#" [ERROR] "--bench" takes one argument. No bench targets available. "#]]) .with_package(str![[r#" [ERROR] "--package " requires a SPEC format value, which can be any package ID specifier in the dependency graph. Run `cargo help pkgid` for more information about SPEC format. Possible packages/workspace members: foo "#]]) .with_target(str![[r#" [ERROR] "--target" takes a target architecture as an argument. Run `[..]` to see possible targets. "#]]) .build(), ); } #[cargo_test] fn install_list_availables() { list_availables_test( "install", SnapshotsBuilder::new() .with_example( str![[r#" [ERROR] "--example" takes one argument. Available examples: a b "#]], str![[r#" [ERROR] "--example" takes one argument. No examples available. "#]], ) .with_bin( str![[r#" [ERROR] "--bin" takes one argument. Available binaries: foo "#]], str![[r#" [ERROR] "--bin" takes one argument. No binaries available. "#]], ) .with_target(str![[r#" [ERROR] "--target" takes a target architecture as an argument. Run `[..]` to see possible targets. "#]]) .build(), ); } #[cargo_test] fn rustdoc_list_availables() { list_availables_test( "rustdoc", SnapshotsBuilder::new() .with_example(str![[r#" [ERROR] "--example" takes one argument. Available examples: a b "#]], str![[r#" [ERROR] "--example" takes one argument. No examples available. "#]]) .with_bin(str![[r#" [ERROR] "--bin" takes one argument. Available binaries: foo "#]], str![[r#" [ERROR] "--bin" takes one argument. No binaries available. "#]]) .with_test(str![[r#" [ERROR] "--test" takes one argument. Available test targets: test1 test2 "#]], str![[r#" [ERROR] "--test" takes one argument. No test targets available. "#]]) .with_bench(str![[r#" [ERROR] "--bench" takes one argument. Available bench targets: bench1 bench2 "#]], str![[r#" [ERROR] "--bench" takes one argument. No bench targets available. "#]]) .with_package(str![[r#" [ERROR] "--package " requires a SPEC format value, which can be any package ID specifier in the dependency graph. Run `cargo help pkgid` for more information about SPEC format. Possible packages/workspace members: foo "#]]) .with_target(str![[r#" [ERROR] "--target" takes a target architecture as an argument. Run `[..]` to see possible targets. "#]]) .build(), ); } #[cargo_test] fn rustc_list_availables() { list_availables_test( "rustc", SnapshotsBuilder::new() .with_example(str![[r#" [ERROR] "--example" takes one argument. Available examples: a b "#]], str![[r#" [ERROR] "--example" takes one argument. No examples available. "#]]) .with_bin(str![[r#" [ERROR] "--bin" takes one argument. Available binaries: foo "#]], str![[r#" [ERROR] "--bin" takes one argument. No binaries available. "#]]) .with_test(str![[r#" [ERROR] "--test" takes one argument. Available test targets: test1 test2 "#]], str![[r#" [ERROR] "--test" takes one argument. No test targets available. "#]]) .with_bench(str![[r#" [ERROR] "--bench" takes one argument. Available bench targets: bench1 bench2 "#]], str![[r#" [ERROR] "--bench" takes one argument. No bench targets available. "#]]) .with_package(str![[r#" [ERROR] "--package " requires a SPEC format value, which can be any package ID specifier in the dependency graph. Run `cargo help pkgid` for more information about SPEC format. Possible packages/workspace members: foo "#]]) .with_target(str![[r#" [ERROR] "--target" takes a target architecture as an argument. Run `[..]` to see possible targets. "#]]) .build(), ); } #[cargo_test] fn pkgid_list_availables() { list_availables_test( "pkgid", SnapshotsBuilder::new() .with_package(str![[r#" [ERROR] "--package " requires a SPEC format value, which can be any package ID specifier in the dependency graph. Run `cargo help pkgid` for more information about SPEC format. Possible packages/workspace members: foo "#]]) .build(), ); } #[cargo_test] fn tree_list_availables() { list_availables_test( "tree", SnapshotsBuilder::new() .with_package(str![[r#" [ERROR] "--package " requires a SPEC format value, which can be any package ID specifier in the dependency graph. Run `cargo help pkgid` for more information about SPEC format. Possible packages/workspace members: foo "#]]) .with_target(str![[r#" [ERROR] "--target" takes a target architecture as an argument. Run `[..]` to see possible targets. "#]]) .build(), ) } #[cargo_test] fn clean_list_availables() { list_availables_test( "clean", SnapshotsBuilder::new() .with_package(str![[r#" [ERROR] "--package " requires a SPEC format value, which can be any package ID specifier in the dependency graph. Run `cargo help pkgid` for more information about SPEC format. Possible packages/workspace members: foo "#]]) .with_target(str![[r#" [ERROR] "--target" takes a target architecture as an argument. Run `[..]` to see possible targets. "#]]) .build(), ); } #[cargo_test] fn update_list_availables() { list_availables_test( "update", SnapshotsBuilder::new() .with_package(str![[r#" [ERROR] "--package " requires a SPEC format value, which can be any package ID specifier in the dependency graph. Run `cargo help pkgid` for more information about SPEC format. Possible packages/workspace members: foo "#]]) .build(), ); } struct ExpectedSnapshots { example: ProjectExpected, bin: ProjectExpected, test: ProjectExpected, bench: ProjectExpected, package: ProjectExpected, target: ProjectExpected, } struct ProjectExpected { full: Option, empty: Option, } struct SnapshotsBuilder { example: ProjectExpected, bin: ProjectExpected, test: ProjectExpected, bench: ProjectExpected, package: ProjectExpected, target: ProjectExpected, } impl SnapshotsBuilder { pub fn new() -> Self { Self { example: ProjectExpected { full: None, empty: None, }, bin: ProjectExpected { full: None, empty: None, }, test: ProjectExpected { full: None, empty: None, }, bench: ProjectExpected { full: None, empty: None, }, package: ProjectExpected { full: None, empty: None, }, target: ProjectExpected { full: None, empty: None, }, } } fn with_example(mut self, full: T, empty: T) -> Self { self.example.full = Some(full); self.example.empty = Some(empty); self } fn with_bin(mut self, full: T, empty: T) -> Self { self.bin.full = Some(full); self.bin.empty = Some(empty); self } fn with_test(mut self, full: T, empty: T) -> Self { self.test.full = Some(full); self.test.empty = Some(empty); self } fn with_bench(mut self, full: T, empty: T) -> Self { self.bench.full = Some(full); self.bench.empty = Some(empty); self } fn with_package(mut self, full: T) -> Self { self.package.full = Some(full); self } fn with_target(mut self, empty: T) -> Self { self.target.empty = Some(empty); self } fn build(self) -> ExpectedSnapshots { ExpectedSnapshots { example: self.example, bin: self.bin, test: self.test, bench: self.bench, package: self.package, target: self.target, } } } cargo-0.86.0/tests/testsuite/local_registry.rs000064400000000000000000000325561046102023000176100ustar 00000000000000//! Tests for local-registry sources. use std::fs; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::{registry_path, Package}; use cargo_test_support::{basic_manifest, project, str, t}; fn setup() { let root = paths::root(); t!(fs::create_dir(&root.join(".cargo"))); t!(fs::write( root.join(".cargo/config.toml"), r#" [source.crates-io] registry = 'https://wut' replace-with = 'my-awesome-local-registry' [source.my-awesome-local-registry] local-registry = 'registry' "# )); } #[cargo_test] fn simple() { setup(); Package::new("bar", "0.0.1") .local(true) .file("src/lib.rs", "pub fn bar() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.0.1" "#, ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); p.cargo("build") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [UNPACKING] bar v0.0.1 (registry `[ROOT]/registry`) [COMPILING] bar v0.0.1 [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("test").run(); } #[cargo_test] fn not_found() { setup(); // Publish a package so that the directory hierarchy is created. // Note, however, that we declare a dependency on baZ. Package::new("bar", "0.0.1").local(true).publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] baz = "0.0.1" "#, ) .file( "src/lib.rs", "extern crate baz; pub fn foo() { baz::bar(); }", ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no matching package named `baz` found location searched: `[ROOT]/registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]]) .run(); } #[cargo_test] fn depend_on_yanked() { setup(); Package::new("bar", "0.0.1").local(true).publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.0.1" "#, ) .file("src/lib.rs", "") .build(); // Run cargo to create lock file. p.cargo("check").run(); registry_path().join("index").join("3").rm_rf(); Package::new("bar", "0.0.1") .local(true) .yanked(true) .publish(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn multiple_versions() { setup(); Package::new("bar", "0.0.1").local(true).publish(); Package::new("bar", "0.1.0") .local(true) .file("src/lib.rs", "pub fn bar() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [UNPACKING] bar v0.1.0 (registry `[ROOT]/registry`) [CHECKING] bar v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); Package::new("bar", "0.2.0") .local(true) .file("src/lib.rs", "pub fn bar() {}") .publish(); p.cargo("update") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [UPDATING] bar v0.1.0 -> v0.2.0 "#]]) .run(); } #[cargo_test] fn multiple_names() { setup(); Package::new("bar", "0.0.1") .local(true) .file("src/lib.rs", "pub fn bar() {}") .publish(); Package::new("baz", "0.1.0") .local(true) .file("src/lib.rs", "pub fn baz() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" baz = "*" "#, ) .file( "src/lib.rs", r#" extern crate bar; extern crate baz; pub fn foo() { bar::bar(); baz::baz(); } "#, ) .build(); p.cargo("check") .with_stderr_data( str![[r#" [LOCKING] 2 packages to latest compatible versions [UNPACKING] bar v0.0.1 (registry `[ROOT]/registry`) [UNPACKING] baz v0.1.0 (registry `[ROOT]/registry`) [CHECKING] bar v0.0.1 [CHECKING] baz v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn interdependent() { setup(); Package::new("bar", "0.0.1") .local(true) .file("src/lib.rs", "pub fn bar() {}") .publish(); Package::new("baz", "0.1.0") .local(true) .dep("bar", "*") .file("src/lib.rs", "extern crate bar; pub fn baz() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" baz = "*" "#, ) .file( "src/lib.rs", r#" extern crate bar; extern crate baz; pub fn foo() { bar::bar(); baz::baz(); } "#, ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [UNPACKING] bar v0.0.1 (registry `[ROOT]/registry`) [UNPACKING] baz v0.1.0 (registry `[ROOT]/registry`) [CHECKING] bar v0.0.1 [CHECKING] baz v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn path_dep_rewritten() { setup(); Package::new("bar", "0.0.1") .local(true) .file("src/lib.rs", "pub fn bar() {}") .publish(); Package::new("baz", "0.1.0") .local(true) .dep("bar", "*") .file( "Cargo.toml", r#" [package] name = "baz" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = { path = "bar", version = "*" } "#, ) .file("src/lib.rs", "extern crate bar; pub fn baz() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn bar() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" baz = "*" "#, ) .file( "src/lib.rs", r#" extern crate bar; extern crate baz; pub fn foo() { bar::bar(); baz::baz(); } "#, ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [UNPACKING] bar v0.0.1 (registry `[ROOT]/registry`) [UNPACKING] baz v0.1.0 (registry `[ROOT]/registry`) [CHECKING] bar v0.0.1 [CHECKING] baz v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn invalid_dir_bad() { setup(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [source.crates-io] registry = 'https://wut' replace-with = 'my-awesome-local-directory' [source.my-awesome-local-directory] local-registry = '/path/to/nowhere' "#, ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to get `bar` as a dependency of package `foo v0.0.1 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update registry `crates-io` Caused by: failed to update replaced source registry `crates-io` Caused by: local registry path is not a directory: [..]path[..]to[..]nowhere "#]]) .run(); } #[cargo_test] fn different_directory_replacing_the_registry_is_bad() { setup(); // Move our test's .cargo/config to a temporary location and publish a // registry package we're going to use first. let config = paths::root().join(".cargo"); let config_tmp = paths::root().join(".cargo-old"); t!(fs::rename(&config, &config_tmp)); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/lib.rs", "") .build(); // Generate a lock file against the crates.io registry Package::new("bar", "0.0.1").publish(); p.cargo("check").run(); // Switch back to our directory source, and now that we're replacing // crates.io make sure that this fails because we're replacing with a // different checksum config.rm_rf(); t!(fs::rename(&config_tmp, &config)); Package::new("bar", "0.0.1") .file("src/lib.rs", "invalid") .local(true) .publish(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] checksum for `bar v0.0.1` changed between lock files this could be indicative of a few possible errors: * the lock file is corrupt * a replacement source in use (e.g., a mirror) returned a different checksum * the source itself may be corrupt in one way or another unable to verify that `bar v0.0.1` is the same as when the lockfile was generated "#]]) .run(); } #[cargo_test] fn crates_io_registry_url_is_optional() { let root = paths::root(); t!(fs::create_dir(&root.join(".cargo"))); t!(fs::write( root.join(".cargo/config.toml"), r#" [source.crates-io] replace-with = 'my-awesome-local-registry' [source.my-awesome-local-registry] local-registry = 'registry' "# )); Package::new("bar", "0.0.1") .local(true) .file("src/lib.rs", "pub fn bar() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.0.1" "#, ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); p.cargo("build") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [UNPACKING] bar v0.0.1 (registry `[ROOT]/registry`) [COMPILING] bar v0.0.1 [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("test").run(); } cargo-0.86.0/tests/testsuite/locate_project.rs000064400000000000000000000044171046102023000175560ustar 00000000000000//! Tests for the `cargo locate-project` command. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; #[cargo_test] fn simple() { let p = project().build(); p.cargo("locate-project") .with_stdout_data( str![[r#" { "root": "[ROOT]/foo/Cargo.toml" } "#]] .is_json(), ) .run(); } #[cargo_test] fn message_format() { let p = project().build(); p.cargo("locate-project --message-format plain") .with_stdout_data(str![[r#" [ROOT]/foo/Cargo.toml "#]]) .run(); p.cargo("locate-project --message-format json") .with_stdout_data( str![[r#" { "root": "[ROOT]/foo/Cargo.toml" } "#]] .is_json(), ) .run(); p.cargo("locate-project --message-format cryptic") .with_stderr_data(str![[r#" [ERROR] invalid message format specifier: `cryptic` "#]]) .with_status(101) .run(); } #[cargo_test] fn workspace() { let p = project() .file( "Cargo.toml", r#" [package] name = "outer" version = "0.0.0" [workspace] members = ["inner"] "#, ) .file("src/main.rs", "fn main() {}") .file( "inner/Cargo.toml", r#" [package] name = "inner" version = "0.0.0" "#, ) .file("inner/src/lib.rs", "") .build(); p.cargo("locate-project") .with_stdout_data( str![[r#" { "root": "[ROOT]/foo/Cargo.toml" } "#]] .is_json(), ) .run(); p.cargo("locate-project") .cwd("inner") .with_stdout_data( str![[r#" { "root": "[ROOT]/foo/inner/Cargo.toml" } "#]] .is_json(), ) .run(); p.cargo("locate-project --workspace") .with_stdout_data( str![[r#" { "root": "[ROOT]/foo/Cargo.toml" } "#]] .is_json(), ) .run(); p.cargo("locate-project --workspace") .cwd("inner") .with_stdout_data( str![[r#" { "root": "[ROOT]/foo/Cargo.toml" } "#]] .is_json(), ) .run(); } cargo-0.86.0/tests/testsuite/lockfile_compat.rs000064400000000000000000000756101046102023000177170ustar 00000000000000//! Tests for supporting older versions of the Cargo.lock file format. use cargo_test_support::compare::assert_e2e; use cargo_test_support::git; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::{basic_lib_manifest, basic_manifest, project}; #[cargo_test] fn oldest_lockfile_still_works() { let cargo_commands = vec!["build", "update"]; for cargo_command in cargo_commands { oldest_lockfile_still_works_with_command(cargo_command); } } fn oldest_lockfile_still_works_with_command(cargo_command: &str) { Package::new("bar", "0.1.0").publish(); let expected_lockfile = str![[r##" # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "[..]" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar", ] "##]]; let old_lockfile = r#" [root] name = "foo" version = "0.0.1" dependencies = [ "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" "#; let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .file("Cargo.lock", old_lockfile) .build(); p.cargo(cargo_command).run(); let lock = p.read_lockfile(); assert_e2e().eq(&lock, expected_lockfile); } #[cargo_test] fn frozen_flag_preserves_old_lockfile() { let cksum = Package::new("bar", "0.1.0").publish(); let old_lockfile = format!( r#"[root] name = "foo" version = "0.0.1" dependencies = [ "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "{}" "#, cksum, ); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .file("Cargo.lock", &old_lockfile) .build(); p.cargo("check --locked").run(); let lock = p.read_lockfile(); assert_e2e().eq(&lock, &old_lockfile); } #[cargo_test] fn totally_wild_checksums_works() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .file( "Cargo.lock", r#" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum baz 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "checksum" "checksum bar 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "checksum" "#, ); let p = p.build(); p.cargo("check").run(); let lock = p.read_lockfile(); assert_e2e().eq( &lock, str![[r##" # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "[..]" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar", ] "##]], ); } #[cargo_test] fn wrong_checksum_is_an_error() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .file( "Cargo.lock", r#" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "checksum" "#, ); let p = p.build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] checksum for `bar v0.1.0` changed between lock files this could be indicative of a few possible errors: * the lock file is corrupt * a replacement source in use (e.g., a mirror) returned a different checksum * the source itself may be corrupt in one way or another unable to verify that `bar v0.1.0` is the same as when the lockfile was generated "#]]) .run(); } // If the checksum is unlisted in the lock file (e.g., ) yet we can // calculate it (e.g., it's a registry dep), then we should in theory just fill // it in. #[cargo_test] fn unlisted_checksum_is_bad_if_we_calculate() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .file( "Cargo.lock", r#" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "" "#, ); let p = p.build(); p.cargo("fetch").with_status(101).with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] checksum for `bar v0.1.0` was not previously calculated, but a checksum could now be calculated this could be indicative of a few possible situations: * the source `registry `crates-io`` did not previously support checksums, but was replaced with one that does * newer Cargo implementations know how to checksum this source, but this older implementation does not * the lock file is corrupt "#]]).run(); } // If the checksum is listed in the lock file yet we cannot calculate it (e.g., // Git dependencies as of today), then make sure we choke. #[cargo_test] fn listed_checksum_bad_if_we_cannot_compute() { let git = git::new("bar", |p| { p.file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = {{ git = '{}' }} "#, git.url() ), ) .file("src/lib.rs", "") .file( "Cargo.lock", &format!( r#" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar 0.1.0 (git+{0})" ] [[package]] name = "bar" version = "0.1.0" source = "git+{0}" [metadata] "checksum bar 0.1.0 (git+{0})" = "checksum" "#, git.url() ), ); let p = p.build(); p.cargo("fetch").with_status(101).with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [ERROR] checksum for `bar v0.1.0 ([ROOTURL]/bar)` could not be calculated, but a checksum is listed in the existing lock file this could be indicative of a few possible situations: * the source `[ROOTURL]/bar` supports checksums, but was replaced with one that doesn't * the lock file is corrupt unable to verify that `bar v0.1.0 ([ROOTURL]/bar)` is the same as when the lockfile was generated "#]]).run(); } #[cargo_test] fn current_lockfile_format() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", ""); let p = p.build(); p.cargo("check").run(); let actual = p.read_lockfile(); let expected = str![[r##" # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "[..]" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar", ] "##]]; assert_e2e().eq(&actual, expected); } #[cargo_test] fn lockfile_without_root() { Package::new("bar", "0.1.0").publish(); let lockfile = r#" # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar", ] "#; let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .file("Cargo.lock", lockfile); let p = p.build(); p.cargo("check").run(); let lock = p.read_lockfile(); assert_e2e().eq( &lock, str![[r##" # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "[..]" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar", ] "##]], ); } #[cargo_test] fn locked_correct_error() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", ""); let p = p.build(); p.cargo("check --locked") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] the lock file [ROOT]/foo/Cargo.lock needs to be updated but --locked was passed to prevent this If you want to try to generate the lock file without accessing the network, remove the --locked flag and use --offline instead. "#]]) .run(); } #[cargo_test] fn v2_format_preserved() { let cksum = Package::new("bar", "0.1.0").publish(); let lockfile = format!( r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "{}" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar", ] "#, cksum ); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .file("Cargo.lock", &lockfile) .build(); p.cargo("fetch").run(); let lock = p.read_lockfile(); assert_e2e().eq(&lock, &lockfile); } #[cargo_test] fn v2_path_and_crates_io() { let cksum010 = Package::new("a", "0.1.0").publish(); let cksum020 = Package::new("a", "0.2.0").publish(); let lockfile = format!( r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "a" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "{}" [[package]] name = "a" version = "0.2.0" [[package]] name = "a" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "{}" [[package]] name = "foo" version = "0.0.1" dependencies = [ "a 0.1.0", "a 0.2.0", "a 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] "#, cksum010, cksum020, ); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = 'a' } b = { version = "0.1", package = 'a' } c = { version = "0.2", package = 'a' } "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.2.0" edition = "2015" "#, ) .file("a/src/lib.rs", "") .file("Cargo.lock", &lockfile) .build(); p.cargo("fetch").run(); p.cargo("fetch").run(); let lock = p.read_lockfile(); assert_e2e().eq(&lock, &lockfile); } #[cargo_test] fn v3_and_git() { let (git_project, repo) = git::new_repo("dep1", |project| { project .file("Cargo.toml", &basic_lib_manifest("dep1")) .file("src/lib.rs", "") }); let head_id = repo.head().unwrap().target().unwrap(); let lockfile = format!( r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "dep1" version = "0.5.0" source = "git+[ROOTURL]/dep1?branch=master#{}" [[package]] name = "foo" version = "0.0.1" dependencies = [ "dep1", ] "#, head_id, ); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" rust-version = "1.81" # ensure it stays in lockfile v3 [dependencies] dep1 = {{ git = '{}', branch = 'master' }} "#, git_project.url(), ), ) .file("src/lib.rs", "") .file("Cargo.lock", "version = 3") .build(); p.cargo("fetch").run(); let lock = p.read_lockfile(); assert_e2e().eq(&lock, &lockfile); } #[cargo_test] fn lock_from_the_future() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("src/lib.rs", "") .file("Cargo.lock", "version = 10000000") .build(); p.cargo("fetch").with_stderr_data(str![[r#" [ERROR] failed to parse lock file at: [ROOT]/foo/Cargo.lock Caused by: lock file version `10000000` was found, but this version of Cargo does not understand this lock file, perhaps Cargo needs to be updated? "#]]).with_status(101).run(); } #[cargo_test] fn preserve_old_format_if_no_update_needed() { let cksum = Package::new("bar", "0.1.0").publish(); let lockfile = format!( r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] "checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "{}" "#, cksum ); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .file("Cargo.lock", &lockfile) .build(); p.cargo("check --locked").run(); } #[cargo_test] fn same_name_version_different_sources() { let cksum = Package::new("foo", "0.1.0").publish(); let (git_project, repo) = git::new_repo("dep1", |project| { project .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file("src/lib.rs", "") }); let head_id = repo.head().unwrap().target().unwrap(); // Lockfile was generated with Rust 1.51 let lockfile = format!( r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "foo" version = "0.1.0" dependencies = [ "foo 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "foo 0.1.0 (git+{url})", ] [[package]] name = "foo" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "{cksum}" [[package]] name = "foo" version = "0.1.0" source = "git+{url}#{sha}" "#, sha = head_id, url = git_project.url(), cksum = cksum ); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] foo = "0.1.0" foo2 = {{ git = '{}', package = 'foo' }} "#, git_project.url(), ), ) .file("src/lib.rs", "") .file("Cargo.lock", &lockfile) .build(); p.cargo("check").run(); assert_eq!(p.read_file("Cargo.lock"), lockfile); } #[cargo_test] fn bad_data_in_lockfile_error_meg() { Package::new("bar", "0.0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" [dependencies] bar = "*" "#, ) .file("src/main.rs", "fn main() {}") .file( "Cargo.lock", r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e1b9346248cf3391ead604c4407258d327c28e37209f6d56127598165165dda" [[package]] name = "test" version = "0.0.0" dependencies = [ "bar", ]"#, ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `bar = "*"` (locked to 0.1.0) candidate versions found which didn't match: 0.0.1 location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `test v0.0.0 ([ROOT]/foo)` perhaps a crate was updated and forgotten to be re-vendored? "#]]) .run(); } #[cargo_test] fn next_version_is_always_unstable() { let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" "#, ), ) .file("src/lib.rs", "") .file("Cargo.lock", "version = 5") .build(); p.cargo("fetch").with_status(101).with_stderr_data(str![[r#" [ERROR] failed to parse lock file at: [ROOT]/foo/Cargo.lock Caused by: lock file version `5` 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_data(str![[r#" [ERROR] failed to parse lock file at: [ROOT]/foo/Cargo.lock Caused by: lock file version `5` requires `-Znext-lockfile-bump` "#]]) .run(); } fn create_branch(repo: &git2::Repository, branch: &str, head_id: git2::Oid) { repo.branch(branch, &repo.find_commit(head_id).unwrap(), true) .unwrap(); } fn create_tag(repo: &git2::Repository, tag: &str, head_id: git2::Oid) { repo.tag( tag, &repo.find_object(head_id, None).unwrap(), &repo.signature().unwrap(), "make a new tag", false, ) .unwrap(); } fn v3_and_git_url_encoded(ref_kind: &str, f: impl FnOnce(&git2::Repository, &str, git2::Oid)) { let (git_project, repo) = git::new_repo("dep1", |project| { project .file("Cargo.toml", &basic_lib_manifest("dep1")) .file("src/lib.rs", "") }); let url = git_project.url(); let head_id = repo.head().unwrap().target().unwrap(); // Ref name with special characters let git_ref = "a-_+#$)"; let encoded_ref = "a-_%2B%23%24%29"; f(&repo, git_ref, head_id); let lockfile = format!( r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "dep1" version = "0.5.0" source = "git+[ROOTURL]/dep1?{ref_kind}={git_ref}#{head_id}" [[package]] name = "foo" version = "0.0.1" dependencies = [ "dep1", ] "#, ); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" rust-version = "1.81" # ensure it stays in lockfile v3 [dependencies] dep1 = {{ git = '{url}', {ref_kind} = '{git_ref}' }} "#, ), ) .file("src/lib.rs", "") .file("Cargo.lock", "version = 3") .build(); p.cargo("check") .with_stderr_data(format!( "\ [UPDATING] git repository `[ROOTURL]/dep1` [LOCKING] 1 package to latest compatible version [ADDING] dep1 v0.5.0 ([ROOTURL]/dep1?{ref_kind}={encoded_ref}#[..]) [CHECKING] dep1 v0.5.0 ([ROOTURL]/dep1?{ref_kind}={encoded_ref}#[..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s " )) .run(); let lock = p.read_lockfile(); assert_e2e().eq(&lock, &lockfile); // v3 doesn't URL-encode URL parameters, but `url` crate does decode as it // was URL-encoded. Therefore Cargo thinks they are from different source // and clones the repository again. p.cargo("check") .with_stderr_data(format!( "\ [UPDATING] git repository `[ROOTURL]/dep1` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s " )) .run(); } #[cargo_test] fn v3_and_git_url_encoded_branch() { v3_and_git_url_encoded("branch", create_branch); } #[cargo_test] fn v3_and_git_url_encoded_tag() { v3_and_git_url_encoded("tag", create_tag); } #[cargo_test] fn v3_and_git_url_encoded_rev() { v3_and_git_url_encoded("rev", create_tag); } fn v4_and_git_url_encoded(ref_kind: &str, f: impl FnOnce(&git2::Repository, &str, git2::Oid)) { let (git_project, repo) = git::new_repo("dep1", |project| { project .file("Cargo.toml", &basic_lib_manifest("dep1")) .file("src/lib.rs", "") }); let url = git_project.url(); let head_id = repo.head().unwrap().target().unwrap(); // Ref name with special characters let git_ref = "a-_+#$)"; let encoded_ref = "a-_%2B%23%24%29"; f(&repo, git_ref, head_id); let lockfile = format!( r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "dep1" version = "0.5.0" source = "git+[ROOTURL]/dep1?{ref_kind}={encoded_ref}#{head_id}" [[package]] name = "foo" version = "0.0.1" dependencies = [ "dep1", ] "#, ); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] dep1 = {{ git = '{url}', {ref_kind} = '{git_ref}' }} "#, ), ) .file("src/lib.rs", "") .file("Cargo.lock", "version = 4") .build(); p.cargo("check") .with_stderr_data(format!( "\ [UPDATING] git repository `[ROOTURL]/dep1` [LOCKING] 1 package to latest compatible version [ADDING] dep1 v0.5.0 ([ROOTURL]/dep1?{ref_kind}={encoded_ref}#[..]) [CHECKING] dep1 v0.5.0 ([ROOTURL]/dep1?{ref_kind}={encoded_ref}#[..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s " )) .run(); let lock = p.read_lockfile(); assert_e2e().eq(&lock, &lockfile); // Unlike v3_and_git_url_encoded, v4 encodes URL parameters so no git // repository re-clone happen. p.cargo("check") .with_stderr_data( "\ [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s ", ) .run(); } #[cargo_test] fn v4_and_git_url_encoded_branch() { v4_and_git_url_encoded("branch", create_branch); } #[cargo_test] fn v4_and_git_url_encoded_tag() { v4_and_git_url_encoded("tag", create_tag); } #[cargo_test] fn v4_and_git_url_encoded_rev() { v4_and_git_url_encoded("rev", create_tag) } #[cargo_test] fn with_msrv() { let cksum = Package::new("bar", "0.1.0").publish(); let v3_lockfile = format!( r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "{cksum}" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar", ] "# ); let v2_lockfile = format!( r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "{cksum}" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar", ] "# ); let v1_lockfile = format!( r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "foo" version = "0.0.1" dependencies = [ "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] "checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "{cksum}" "# ); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .build(); let cases = [ // v1 is the default ("1.37", None, 1), ("1.37", Some(1), 1), ("1.37", Some(2), 2), ("1.37", Some(3), 3), ("1.37", Some(4), 4), // v2 introduced ("1.38", None, 1), // last version of v1 as the default ("1.40", None, 1), // v2 is the default ("1.41", None, 2), ("1.41", Some(1), 1), ("1.41", Some(2), 2), ("1.41", Some(3), 3), ("1.41", Some(4), 4), // v3 introduced ("1.47", None, 2), // last version of v2 as the default ("1.48", None, 2), // v3 is the default ("1.53", None, 3), ("1.53", Some(1), 1), ("1.53", Some(2), 2), ("1.53", Some(3), 3), ("1.53", Some(4), 4), // v4 introduced ("1.78", None, 3), // last version of v3 as the default ("1.82", None, 3), // v4 is the default ("1.83", None, 4), ("1.83", Some(1), 1), ("1.83", Some(2), 2), ("1.83", Some(3), 3), ("1.83", Some(4), 4), ]; for (msrv, existing_lockfile, expected_version) in cases { // Clean previous lockfile. _ = std::fs::remove_file(p.root().join("Cargo.lock")); p.change_file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" rust-version = "{msrv}" [dependencies] bar = "0.1.0" "#, ), ); if let Some(existing_lockfile) = existing_lockfile { let existing_lockfile = match existing_lockfile { 1 => v1_lockfile.as_str().into(), 2 => v2_lockfile.as_str().into(), 3 => v3_lockfile.as_str().into(), v => std::borrow::Cow::from(format!("version = {v}")), }; p.change_file("Cargo.lock", &existing_lockfile); } p.cargo("fetch").run(); let lock = p.read_lockfile(); let toml = lock.parse::().unwrap(); // get `version = ` from Cargo.lock let version_field = toml.get("version").and_then(|v| v.as_integer()); let actual_version = if let Some(ver) = version_field { ver } else if lock.find("\nchecksum = ").is_some() { 2 } else { 1 }; assert_eq!( expected_version, actual_version, "msrv: {msrv}, existing lockfile: {existing_lockfile:?}" ); } } cargo-0.86.0/tests/testsuite/lockfile_path.rs000064400000000000000000000343711046102023000173670ustar 00000000000000//! Tests for `lockfile-path` flag use std::fs; use snapbox::str; use cargo_test_support::compare::assert_e2e; use cargo_test_support::install::assert_has_installed_exe; use cargo_test_support::registry::{Package, RegistryBuilder}; use cargo_test_support::{ basic_bin_manifest, cargo_process, cargo_test, paths, project, symlink_supported, ProjectBuilder, }; /////////////////////////////// //// Unstable feature tests start /////////////////////////////// #[cargo_test] fn must_have_unstable_options() { let lockfile_path = "mylockfile/is/burried/Cargo.lock"; let p = make_project().build(); p.cargo("generate-lockfile") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("--lockfile-path") .arg(lockfile_path) .with_stderr_data(str![[ r#"[ERROR] the `--lockfile-path` flag is unstable, pass `-Z unstable-options` to enable it See https://github.com/rust-lang/cargo/issues/14421 for more information about the `--lockfile-path` flag. "#]]) .with_status(101) .run(); } #[cargo_test] fn must_be_nightly() { let lockfile_path = "mylockfile/is/burried/Cargo.lock"; let p = make_project().build(); p.cargo("generate-lockfile") .arg("-Zunstable-options") .arg("--lockfile-path") .arg(lockfile_path) .with_stderr_data(str![[ r#"[ERROR] the `-Z` flag is only accepted on the nightly channel of Cargo, but this is the `stable` channel See https://doc.rust-lang.org/book/appendix-07-nightly-rust.html for more information about Rust release channels. "#]]) .with_status(101) .run(); } /////////////////////////////// //// Unstable feature tests end /////////////////////////////// #[cargo_test] fn basic_lockfile_created() { let lockfile_path = "mylockfile/is/burried/Cargo.lock"; let p = make_project().build(); p.cargo("generate-lockfile") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("--lockfile-path") .arg(lockfile_path) .run(); assert!(!p.root().join("Cargo.lock").exists()); assert!(p.root().join(lockfile_path).is_file()); } #[cargo_test] fn basic_lockfile_read() { let lockfile_path = "mylockfile/Cargo.lock"; let p = make_project().file(lockfile_path, VALID_LOCKFILE).build(); p.cargo("generate-lockfile") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("--lockfile-path") .arg(lockfile_path) .run(); assert!(!p.root().join("Cargo.lock").exists()); assert!(p.root().join(lockfile_path).is_file()); } #[cargo_test] fn basic_lockfile_override() { let lockfile_path = "mylockfile/Cargo.lock"; let p = make_project() .file("Cargo.lock", "This is an invalid lock file!") .build(); p.cargo("generate-lockfile") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("--lockfile-path") .arg(lockfile_path) .run(); assert!(p.root().join(lockfile_path).is_file()); } ////////////////////// ///// Symlink tests ////////////////////// #[cargo_test] fn symlink_in_path() { if !symlink_supported() { return; } let dst = "dst"; let src = "somedir/link"; let lockfile_path = format!("{src}/Cargo.lock"); let p = make_project().symlink_dir(dst, src).build(); fs::create_dir(p.root().join("dst")).unwrap(); assert!(p.root().join(src).is_dir()); p.cargo("generate-lockfile") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("--lockfile-path") .arg(lockfile_path.as_str()) .run(); assert!(p.root().join(lockfile_path).is_file()); assert!(p.root().join(dst).join("Cargo.lock").is_file()); } #[cargo_test] fn symlink_lockfile() { if !symlink_supported() { return; } let lockfile_path = "dst/Cargo.lock"; let src = "somedir/link"; let lock_body = VALID_LOCKFILE; let p = make_project() .file(lockfile_path, lock_body) .symlink(lockfile_path, src) .build(); assert!(p.root().join(src).is_file()); p.cargo("generate-lockfile") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("--lockfile-path") .arg(lockfile_path) .run(); assert!(!p.root().join("Cargo.lock").exists()); } #[cargo_test] fn broken_symlink() { if !symlink_supported() { return; } let invalid_dst = "invalid_path"; let src = "somedir/link"; let lockfile_path = format!("{src}/Cargo.lock"); let p = make_project().symlink_dir(invalid_dst, src).build(); assert!(!p.root().join(src).is_dir()); p.cargo("generate-lockfile") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("--lockfile-path") .arg(lockfile_path) .with_status(101) .with_stderr_data(str![[ r#"[ERROR] failed to create directory `[ROOT]/foo/somedir/link` ... "# ]]) .run(); } #[cargo_test] fn loop_symlink() { if !symlink_supported() { return; } let loop_link = "loop"; let src = "somedir/link"; let lockfile_path = format!("{src}/Cargo.lock"); let p = make_project() .symlink_dir(loop_link, src) .symlink_dir(src, loop_link) .build(); assert!(!p.root().join(src).is_dir()); p.cargo("generate-lockfile") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("--lockfile-path") .arg(lockfile_path) .with_status(101) .with_stderr_data(str![[ r#"[ERROR] failed to create directory `[ROOT]/foo/somedir/link` ... "# ]]) .run(); } ///////////////////////// //// Commands tests ///////////////////////// #[cargo_test] fn add_lockfile_override() { let lockfile_path = "mylockfile/Cargo.lock"; project() .at("bar") .file("Cargo.toml", LIB_TOML) .file("src/main.rs", "fn main() {}") .build(); let p = make_project() .file("Cargo.lock", "This is an invalid lock file!") .build(); p.cargo("add") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("--lockfile-path") .arg(lockfile_path) .arg("--path") .arg("../bar") .run(); assert!(p.root().join(lockfile_path).is_file()); } #[cargo_test] fn clean_lockfile_override() { let lockfile_path = "mylockfile/Cargo.lock"; let p = make_project() .file("Cargo.lock", "This is an invalid lock file!") .build(); p.cargo("clean") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("--lockfile-path") .arg(lockfile_path) .arg("--package") .arg("test_foo") .run(); assert!(p.root().join(lockfile_path).is_file()); } #[cargo_test] fn fix_lockfile_override() { let lockfile_path = "mylockfile/Cargo.lock"; let p = make_project() .file("Cargo.lock", "This is an invalid lock file!") .build(); p.cargo("fix") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("--lockfile-path") .arg(lockfile_path) .arg("--package") .arg("test_foo") .arg("--allow-no-vcs") .run(); assert!(p.root().join(lockfile_path).is_file()); } #[cargo_test] fn publish_lockfile_read() { let lockfile_path = "mylockfile/Cargo.lock"; let p = make_project().file(lockfile_path, VALID_LOCKFILE).build(); let registry = RegistryBuilder::new().http_api().http_index().build(); p.cargo("publish") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("--lockfile-path") .arg(lockfile_path) .replace_crates_io(registry.index_url()) .run(); assert!(!p.root().join("Cargo.lock").exists()); assert!(p.root().join(lockfile_path).is_file()); } #[cargo_test] fn remove_lockfile_override() { let lockfile_path = "mylockfile/Cargo.lock"; let manifest = r#" [package] name = "foo" version = "0.5.0" authors = ["wycats@example.com"] edition = "2015" [[bin]] name = "foo" [dependencies] test_bar = { version = "0.1.0", path = "../bar" } "#; project() .at("bar") .file("Cargo.toml", LIB_TOML) .file("src/main.rs", "fn main() {}") .build(); let p = project() .file("Cargo.toml", &manifest) .file("src/main.rs", "fn main() {}") .file("Cargo.lock", "This is an invalid lock file!") .build(); p.cargo("remove") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("--lockfile-path") .arg(lockfile_path) .arg("test_bar") .run(); assert!(p.root().join(lockfile_path).is_file()); } #[cargo_test] fn assert_respect_pinned_version_from_lockfile_path() { let lockfile_path = "mylockfile/Cargo.lock"; let p = project() .file( "Cargo.toml", r#"# [package] name = "test_foo" version = "0.5.0" authors = ["wycats@example.com"] edition = "2015" [[bin]] name = "test_foo" [dependencies] bar = "0.1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.1.0").publish(); p.cargo("generate-lockfile") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("--lockfile-path") .arg(lockfile_path) .run(); assert!(!p.root().join("Cargo.lock").exists()); assert!(p.root().join(lockfile_path).is_file()); let lockfile_original = fs::read_to_string(p.root().join(lockfile_path)).unwrap(); Package::new("bar", "0.1.1").publish(); p.cargo("package") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("--lockfile-path") .arg(lockfile_path) .run(); assert!(p .root() .join("target/package/test_foo-0.5.0/Cargo.lock") .is_file()); let path = p.root().join("target/package/test_foo-0.5.0/Cargo.lock"); let contents = fs::read_to_string(path).unwrap(); assert_e2e().eq(contents, lockfile_original); } #[cargo_test] fn install_respects_lock_file_path() { // `cargo install` will imply --locked when lockfile path is provided Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.1.1") .file("src/lib.rs", "not rust") .publish(); // Publish with lockfile containing bad version of `bar` (0.1.1) Package::new("foo", "0.1.0") .dep("bar", "0.1") .file("src/lib.rs", "") .file( "src/main.rs", "extern crate foo; extern crate bar; fn main() {}", ) .file( "Cargo.lock", r#" [[package]] name = "bar" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "foo" version = "0.1.0" dependencies = [ "bar 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] "#, ) .publish(); cargo_process("install foo --locked") .with_stderr_data(str![[r#" ... [..]not rust[..] ... "#]]) .with_status(101) .run(); // Create lockfile with the good `bar` version (0.1.0) and use it for install project() .file( "Cargo.lock", r#" [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "foo" version = "0.1.0" dependencies = [ "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] "#, ) .build(); cargo_process("install foo -Zunstable-options --lockfile-path foo/Cargo.lock") .masquerade_as_nightly_cargo(&["lockfile-path"]) .run(); assert!(paths::root().join("foo/Cargo.lock").is_file()); assert_has_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn install_lock_file_path_must_present() { // `cargo install` will imply --locked when lockfile path is provided Package::new("bar", "0.1.0").publish(); Package::new("foo", "0.1.0") .dep("bar", "0.1") .file("src/lib.rs", "") .file( "src/main.rs", "extern crate foo; extern crate bar; fn main() {}", ) .publish(); cargo_process("install foo -Zunstable-options --lockfile-path lockfile_dir/Cargo.lock") .masquerade_as_nightly_cargo(&["lockfile-path"]) .with_stderr_data(str![[r#" ... [ERROR] no Cargo.lock file found in the requested path [ROOT]/lockfile_dir/Cargo.lock ... "#]]) .with_status(101) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] fn run_embed() { let lockfile_path = "mylockfile/Cargo.lock"; let invalid_lockfile = "Cargo.lock"; let p = project() .file("src/main.rs", "fn main() {}") .file("Cargo.lock", "This is an invalid lock file!") .build(); p.cargo("run") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("-Zscript") .arg("--lockfile-path") .arg(lockfile_path) .arg("--manifest-path") .arg("src/main.rs") .run(); assert!(p.root().join(lockfile_path).is_file()); p.cargo("run") .masquerade_as_nightly_cargo(&["lockfile-path"]) .arg("-Zunstable-options") .arg("-Zscript") .arg("--lockfile-path") .arg(invalid_lockfile) .arg("--manifest-path") .arg("src/main.rs") .with_status(101) .with_stderr_data(str![[ r#"[WARNING] `package.edition` is unspecified, defaulting to `2024` [ERROR] failed to parse lock file at: [ROOT]/foo/Cargo.lock ... "# ]]) .run(); } const VALID_LOCKFILE: &str = r#"# Test lockfile version = 4 [[package]] name = "test_foo" version = "0.5.0" "#; const LIB_TOML: &str = r#" [package] name = "test_bar" version = "0.1.0" edition = "2021" "#; fn make_project() -> ProjectBuilder { project() .file("Cargo.toml", &basic_bin_manifest("test_foo")) .file("src/main.rs", "fn main() {}") } cargo-0.86.0/tests/testsuite/login.rs000064400000000000000000000266131046102023000156730ustar 00000000000000//! Tests for the `cargo login` command. use std::fs; use std::path::PathBuf; use cargo_test_support::cargo_process; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::{self, RegistryBuilder}; use cargo_test_support::str; use cargo_test_support::t; const TOKEN: &str = "test-token"; const TOKEN2: &str = "test-token2"; const ORIGINAL_TOKEN: &str = "api-token"; fn credentials_toml() -> PathBuf { paths::home().join(".cargo/credentials.toml") } fn setup_new_credentials() { setup_new_credentials_at(credentials_toml()); } fn setup_new_credentials_at(config: PathBuf) { t!(fs::create_dir_all(config.parent().unwrap())); t!(fs::write( &config, format!(r#"token = "{token}""#, token = ORIGINAL_TOKEN) )); } /// Asserts whether or not the token is set to the given value for the given registry. pub fn check_token(expected_token: Option<&str>, registry: Option<&str>) { let credentials = credentials_toml(); assert!(credentials.is_file()); let contents = fs::read_to_string(&credentials).unwrap(); let toml: toml::Table = contents.parse().unwrap(); let actual_token = match registry { // A registry has been provided, so check that the token exists in a // table for the registry. Some(registry) => toml .get("registries") .and_then(|registries_table| registries_table.get(registry)) .and_then(|registry_table| match registry_table.get("token") { Some(&toml::Value::String(ref token)) => Some(token.as_str().to_string()), _ => None, }), // There is no registry provided, so check the global token instead. None => toml .get("registry") .and_then(|registry_table| registry_table.get("token")) .and_then(|v| match v { toml::Value::String(ref token) => Some(token.as_str().to_string()), _ => None, }), }; match (actual_token, expected_token) { (None, None) => {} (Some(actual), Some(expected)) => assert_eq!(actual, expected), (None, Some(expected)) => { panic!("expected `{registry:?}` to be `{expected}`, but was not set") } (Some(actual), None) => { panic!("expected `{registry:?}` to be unset, but was set to `{actual}`") } } } #[cargo_test] fn registry_credentials() { let _alternative = RegistryBuilder::new().alternative().build(); let _alternative2 = RegistryBuilder::new() .alternative_named("alternative2") .build(); setup_new_credentials(); let reg = "alternative"; cargo_process("login --registry").arg(reg).arg(TOKEN).run(); // Ensure that we have not updated the default token check_token(Some(ORIGINAL_TOKEN), None); // Also ensure that we get the new token for the registry check_token(Some(TOKEN), Some(reg)); let reg2 = "alternative2"; cargo_process("login --registry") .arg(reg2) .arg(TOKEN2) .run(); // Ensure not overwriting 1st alternate registry token with // 2nd alternate registry token (see rust-lang/cargo#7701). check_token(Some(ORIGINAL_TOKEN), None); check_token(Some(TOKEN), Some(reg)); check_token(Some(TOKEN2), Some(reg2)); } #[cargo_test] fn empty_login_token() { let registry = RegistryBuilder::new() .no_configure_registry() .no_configure_token() .build(); setup_new_credentials(); cargo_process("login") .replace_crates_io(registry.index_url()) .with_stdin("\t\n") .with_stderr_data(str![[r#" [UPDATING] crates.io index please paste the token found on [ROOTURL]/api/me below [ERROR] credential provider `cargo:token` failed action `login` Caused by: please provide a non-empty token "#]]) .with_status(101) .run(); cargo_process("login") .replace_crates_io(registry.index_url()) .arg("") .with_stderr_data(str![[r#" [ERROR] credential provider `cargo:token` failed action `login` Caused by: please provide a non-empty token "#]]) .with_status(101) .run(); } #[cargo_test] fn invalid_login_token() { let registry = RegistryBuilder::new() .no_configure_registry() .no_configure_token() .build(); setup_new_credentials(); let check = |stdin: &str, stderr: &str, status: i32| { cargo_process("login") .replace_crates_io(registry.index_url()) .with_stdin(stdin) .with_stderr_data(stderr) .with_status(status) .run(); }; let invalid = |stdin: &str| { check( stdin, "[ERROR] credential provider `cargo:token` failed action `login` Caused by: token contains invalid characters. Only printable ISO-8859-1 characters are allowed as it is sent in a HTTPS header. ", 101, ) }; let valid = |stdin: &str| { check( stdin, "\ [LOGIN] token for `crates-io` saved ", 0, ) }; // Update config.json so that the rest of the tests don't need to care // whether or not `Updating` is printed. check( "test", "\ [UPDATING] crates.io index [LOGIN] token for `crates-io` saved ", 0, ); invalid("πŸ˜„"); invalid("\u{0016}"); invalid("\u{0000}"); invalid("δ½ ε₯½"); valid("foo\tbar"); valid("foo bar"); valid( r##"!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"##, ); } #[cargo_test] fn bad_asymmetric_token_args() { let registry = RegistryBuilder::new() .credential_provider(&["cargo:paseto"]) .no_configure_token() .build(); // These cases are kept brief as the implementation is covered by clap, so this is only smoke testing that we have clap configured correctly. cargo_process("login -Zasymmetric-token -- --key-subject") .masquerade_as_nightly_cargo(&["asymmetric-token"]) .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] credential provider `cargo:paseto --key-subject` failed action `login` Caused by: [ERROR] a value is required for '--key-subject ' but none was supplied For more information, try '--help'. "#]]) .with_status(101) .run(); } #[cargo_test] fn login_with_no_cargo_dir() { // Create a config in the root directory because `login` requires the // index to be updated, and we don't want to hit crates.io. let registry = registry::init(); fs::rename(paths::home().join(".cargo"), paths::root().join(".cargo")).unwrap(); paths::home().rm_rf(); cargo_process("login foo -v") .replace_crates_io(registry.index_url()) .run(); let credentials = fs::read_to_string(credentials_toml()).unwrap(); assert_eq!(credentials, "[registry]\ntoken = \"foo\"\n"); } #[cargo_test] fn login_with_asymmetric_token_and_subject_on_stdin() { let registry = RegistryBuilder::new() .credential_provider(&["cargo:paseto"]) .no_configure_token() .build(); let credentials = credentials_toml(); cargo_process("login -v -Z asymmetric-token -- --key-subject=foo") .masquerade_as_nightly_cargo(&["asymmetric-token"]) .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [CREDENTIAL] cargo:paseto --key-subject=foo login crates-io k3.public.AmDwjlyf8jAV3gm5Z7Kz9xAOcsKslt_Vwp5v-emjFzBHLCtcANzTaVEghTNEMj9PkQ "#]]) .with_stdin("k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36") .run(); let credentials = fs::read_to_string(&credentials).unwrap(); assert!(credentials.starts_with("[registry]\n")); assert!(credentials.contains("secret-key-subject = \"foo\"\n")); assert!(credentials.contains("secret-key = \"k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36\"\n")); } #[cargo_test] fn login_with_differently_sized_token() { // Verify that the configuration file gets properly truncated. let registry = registry::init(); let credentials = credentials_toml(); fs::remove_file(&credentials).unwrap(); cargo_process("login lmaolmaolmao -v") .replace_crates_io(registry.index_url()) .run(); cargo_process("login lmao -v") .replace_crates_io(registry.index_url()) .run(); cargo_process("login lmaolmaolmao -v") .replace_crates_io(registry.index_url()) .run(); let credentials = fs::read_to_string(&credentials).unwrap(); assert_eq!(credentials, "[registry]\ntoken = \"lmaolmaolmao\"\n"); } #[cargo_test] fn login_with_token_on_stdin() { let registry = registry::init(); let credentials = credentials_toml(); fs::remove_file(&credentials).unwrap(); cargo_process("login lmao -v") .replace_crates_io(registry.index_url()) .run(); cargo_process("login") .replace_crates_io(registry.index_url()) .with_stdin("some token") .run(); let credentials = fs::read_to_string(&credentials).unwrap(); assert_eq!(credentials, "[registry]\ntoken = \"some token\"\n"); } #[cargo_test] fn login_with_asymmetric_token_on_stdin() { let _registry = RegistryBuilder::new() .credential_provider(&["cargo:paseto"]) .alternative() .no_configure_token() .build(); let credentials = credentials_toml(); cargo_process("login -v -Z asymmetric-token --registry alternative") .masquerade_as_nightly_cargo(&["asymmetric-token"]) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [CREDENTIAL] cargo:paseto login alternative k3.public.AmDwjlyf8jAV3gm5Z7Kz9xAOcsKslt_Vwp5v-emjFzBHLCtcANzTaVEghTNEMj9PkQ "#]]) .with_stdin("k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36") .run(); let credentials = fs::read_to_string(&credentials).unwrap(); assert_eq!(credentials, "[registries.alternative]\nsecret-key = \"k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36\"\n"); } #[cargo_test] fn login_with_generate_asymmetric_token() { let _registry = RegistryBuilder::new() .credential_provider(&["cargo:paseto"]) .alternative() .no_configure_token() .build(); let credentials = credentials_toml(); cargo_process("login -Z asymmetric-token --registry alternative") .masquerade_as_nightly_cargo(&["asymmetric-token"]) .with_stderr_data(str![[r#" [UPDATING] `alternative` index k3.public.[..] "#]]) .run(); let credentials = fs::read_to_string(&credentials).unwrap(); assert!(credentials.contains("secret-key = \"k3.secret.")); } #[cargo_test] fn default_registry_configured() { // When registry.default is set, login should use that one when // --registry is not used. let _alternative = RegistryBuilder::new().alternative().build(); let cargo_home = paths::home().join(".cargo"); cargo_util::paths::append( &cargo_home.join("config.toml"), br#" [registry] default = "alternative" "#, ) .unwrap(); cargo_process("login") .arg("a-new-token") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOGIN] token for `alternative` saved "#]]) .run(); check_token(None, None); check_token(Some("a-new-token"), Some("alternative")); } cargo-0.86.0/tests/testsuite/logout.rs000064400000000000000000000072441046102023000160730ustar 00000000000000//! Tests for the `cargo logout` command. use super::login::check_token; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::TestRegistry; use cargo_test_support::{cargo_process, registry, str}; fn simple_logout_test(registry: &TestRegistry, reg: Option<&str>, flag: &str, note: &str) { let msg = reg.unwrap_or("crates-io"); check_token(Some(registry.token()), reg); let mut cargo = cargo_process(&format!("logout {}", flag)); if reg.is_none() { cargo.replace_crates_io(registry.index_url()); } cargo .with_stderr_data(&format!( "\ [LOGOUT] token for `{msg}` has been removed from local storage [NOTE] This does not revoke the token on the registry server. If you need to revoke the token, visit {note} and follow the instructions there. " )) .run(); check_token(None, reg); let mut cargo = cargo_process(&format!("logout {}", flag)); if reg.is_none() { cargo.replace_crates_io(registry.index_url()); } cargo .with_stderr_data(&format!( "\ [LOGOUT] not currently logged in to `{msg}` " )) .run(); check_token(None, reg); } #[cargo_test] fn default_registry_unconfigured() { let registry = registry::init(); simple_logout_test(®istry, None, "", ""); } #[cargo_test] fn other_registry() { let registry = registry::alt_init(); simple_logout_test( ®istry, Some("alternative"), "--registry alternative", "the `alternative` website", ); // It should not touch crates.io. check_token(Some("sekrit"), None); } #[cargo_test] fn default_registry_configured() { // When registry.default is set, logout should use that one when // --registry is not used. let cargo_home = paths::home().join(".cargo"); cargo_home.mkdir_p(); cargo_util::paths::write( &cargo_home.join("config.toml"), r#" [registry] default = "dummy-registry" [registries.dummy-registry] index = "https://127.0.0.1/index" "#, ) .unwrap(); cargo_util::paths::write( &cargo_home.join("credentials.toml"), r#" [registry] token = "crates-io-token" [registries.dummy-registry] token = "dummy-token" "#, ) .unwrap(); check_token(Some("dummy-token"), Some("dummy-registry")); check_token(Some("crates-io-token"), None); cargo_process("logout").with_stderr_data(str![[r#" [LOGOUT] token for `dummy-registry` has been removed from local storage [NOTE] This does not revoke the token on the registry server. If you need to revoke the token, visit the `dummy-registry` website and follow the instructions there. "#]]).run(); check_token(None, Some("dummy-registry")); check_token(Some("crates-io-token"), None); cargo_process("logout") .with_stderr_data(str![[r#" [LOGOUT] not currently logged in to `dummy-registry` "#]]) .run(); } #[cargo_test] fn logout_asymmetric() { let _registry = registry::RegistryBuilder::new() .token(cargo_test_support::registry::Token::rfc_key()) .build(); cargo_process("logout --registry crates-io -Zasymmetric-token") .masquerade_as_nightly_cargo(&["asymmetric-token"]) .with_stderr_data(str![[r#" [LOGOUT] secret-key for `crates-io` has been removed from local storage "#]]) .run(); cargo_process("logout --registry crates-io -Zasymmetric-token") .masquerade_as_nightly_cargo(&["asymmetric-token"]) .with_stderr_data(str![[r#" [LOGOUT] not currently logged in to `crates-io` "#]]) .run(); } cargo-0.86.0/tests/testsuite/lto.rs000064400000000000000000000703301046102023000153540ustar 00000000000000use cargo::core::compiler::Lto; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::RawOutput; use cargo_test_support::{basic_manifest, project, str, Project}; #[cargo_test] fn with_deps() { Package::new("bar", "0.0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" [dependencies] bar = "*" [profile.release] lto = true "#, ) .file("src/main.rs", "extern crate bar; fn main() {}") .build(); p.cargo("build -v --release") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [COMPILING] bar v0.0.1 [RUNNING] `rustc --crate-name bar [..]-C linker-plugin-lto [..]` [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name test [..]-C lto [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn shared_deps() { Package::new("bar", "0.0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" [dependencies] bar = "*" [build-dependencies] bar = "*" [profile.release] lto = true "#, ) .file("build.rs", "extern crate bar; fn main() {}") .file("src/main.rs", "extern crate bar; fn main() {}") .build(); p.cargo("build -v --release") .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [COMPILING] bar v0.0.1 [RUNNING] `rustc --crate-name bar [..]-C linker-plugin-lto [..]` [RUNNING] `rustc --crate-name bar [..]-C embed-bitcode=no [..]` [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build [..]` [RUNNING] `[ROOT]/foo/target/release/build/test-[HASH]/build-script-build` [RUNNING] `rustc --crate-name test [..]-C lto [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn build_dep_not_ltod() { Package::new("bar", "0.0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" [build-dependencies] bar = "*" [profile.release] lto = true "#, ) .file("build.rs", "extern crate bar; fn main() {}") .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v --release") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [COMPILING] bar v0.0.1 [RUNNING] `rustc --crate-name bar [..]-C embed-bitcode=no [..]` [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build [..]` [RUNNING] `[ROOT]/foo/target/release/build/test-[HASH]/build-script-build` [RUNNING] `rustc --crate-name test [..]-C lto [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn complicated() { Package::new("dep-shared", "0.0.1") .file("src/lib.rs", "pub fn foo() {}") .publish(); Package::new("dep-normal2", "0.0.1") .file("src/lib.rs", "pub fn foo() {}") .publish(); Package::new("dep-normal", "0.0.1") .dep("dep-shared", "*") .dep("dep-normal2", "*") .file( "src/lib.rs", " pub fn foo() { dep_shared::foo(); dep_normal2::foo(); } ", ) .publish(); Package::new("dep-build2", "0.0.1") .file("src/lib.rs", "pub fn foo() {}") .publish(); Package::new("dep-build", "0.0.1") .dep("dep-shared", "*") .dep("dep-build2", "*") .file( "src/lib.rs", " pub fn foo() { dep_shared::foo(); dep_build2::foo(); } ", ) .publish(); Package::new("dep-proc-macro2", "0.0.1") .file("src/lib.rs", "pub fn foo() {}") .publish(); Package::new("dep-proc-macro", "0.0.1") .proc_macro(true) .dep("dep-shared", "*") .dep("dep-proc-macro2", "*") .file( "src/lib.rs", " extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro_attribute] pub fn foo(_: TokenStream, a: TokenStream) -> TokenStream { dep_shared::foo(); dep_proc_macro2::foo(); a } ", ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" [lib] crate-type = ['cdylib', 'staticlib'] [dependencies] dep-normal = "*" dep-proc-macro = "*" [build-dependencies] dep-build = "*" [profile.release] lto = true # force build deps to share an opt-level with the rest of the # graph so they only get built once. [profile.release.build-override] opt-level = 3 "#, ) .file("build.rs", "fn main() { dep_build::foo() }") .file( "src/bin/foo-bin.rs", "#[dep_proc_macro::foo] fn main() { dep_normal::foo() }", ) .file( "src/lib.rs", "#[dep_proc_macro::foo] pub fn foo() { dep_normal::foo() }", ) .build(); p.cargo("build -v --release") // normal deps and their transitive dependencies do not need object // code, so they should have linker-plugin-lto specified .with_stderr_contains( "[..]`rustc[..]--crate-name dep_normal2 [..]-C linker-plugin-lto[..]`", ) .with_stderr_contains("[..]`rustc[..]--crate-name dep_normal [..]-C linker-plugin-lto[..]`") // build dependencies and their transitive deps don't need any bitcode, // so embedding should be turned off .with_stderr_contains("[..]`rustc[..]--crate-name dep_build2 [..]-C embed-bitcode=no[..]`") .with_stderr_contains("[..]`rustc[..]--crate-name dep_build [..]-C embed-bitcode=no[..]`") .with_stderr_contains( "[..]`rustc[..]--crate-name build_script_build [..]-C embed-bitcode=no[..]`", ) // proc macro deps are the same as build deps here .with_stderr_contains( "[..]`rustc[..]--crate-name dep_proc_macro2 [..]-C embed-bitcode=no[..]`", ) .with_stderr_contains( "[..]`rustc[..]--crate-name dep_proc_macro [..]-C embed-bitcode=no[..]`", ) .with_stderr_contains( "[..]`rustc[..]--crate-name foo_bin [..]--crate-type bin[..]-C lto[..]`", ) .with_stderr_contains( "[..]`rustc[..]--crate-name test [..]--crate-type cdylib[..]-C lto[..]`", ) .with_stderr_contains("[..]`rustc[..]--crate-name dep_shared [..]`") .with_stderr_does_not_contain("[..]--crate-name dep_shared[..]-C lto[..]") .with_stderr_does_not_contain("[..]--crate-name dep_shared[..]-C linker-plugin-lto[..]") .with_stderr_does_not_contain("[..]--crate-name dep_shared[..]-C embed-bitcode[..]") .run(); } #[cargo_test] fn off_in_manifest_works() { Package::new("bar", "0.0.1") .file("src/lib.rs", "pub fn foo() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" [dependencies] bar = "*" [profile.release] lto = "off" "#, ) .file("src/lib.rs", "pub fn foo() {}") .file( "src/main.rs", "fn main() { test::foo(); bar::foo(); }", ) .build(); p.cargo("build -v --release") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [COMPILING] bar v0.0.1 [RUNNING] `rustc --crate-name bar [..]--crate-type lib [..]-C lto=off [..]-C embed-bitcode=no [..]` [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name test [..]--crate-type lib [..]-C lto=off [..]-C embed-bitcode=no [..]` [RUNNING] `rustc --crate-name test --edition=2015 src/main.rs [..]--crate-type bin [..]-C lto=off [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn between_builds() { let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" [profile.release] lto = true "#, ) .file("src/lib.rs", "pub fn foo() {}") .file("src/main.rs", "fn main() { test::foo() }") .build(); p.cargo("build -v --release --lib") .with_stderr_data(str![[r#" [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc [..]--crate-type lib [..]-C linker-plugin-lto [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build -v --release") .with_stderr_data(str![[r#" [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc [..]--crate-type bin [..]-C lto [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn test_all() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" [profile.release] lto = true "#, ) .file("src/main.rs", "fn main() {}") .file("tests/a.rs", "") .file("tests/b.rs", "") .build(); p.cargo("test --release -v") .with_stderr_data( str![[r#" [COMPILING] foo v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name a [..]-C lto [..]` [RUNNING] `rustc --crate-name b [..]-C lto [..]` [RUNNING] `rustc --crate-name foo [..]-C lto [..]--test [..]` [RUNNING] `rustc --crate-name foo [..]--crate-type bin [..]-C lto [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/release/deps/foo-[HASH][EXE]` [RUNNING] `[ROOT]/foo/target/release/deps/a-[HASH][EXE]` [RUNNING] `[ROOT]/foo/target/release/deps/b-[HASH][EXE]` "#]] .unordered(), ) .run(); } #[cargo_test] fn test_all_and_bench() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" [profile.release] lto = true [profile.bench] lto = true "#, ) .file("src/main.rs", "fn main() {}") .file("tests/a.rs", "") .file("tests/b.rs", "") .build(); p.cargo("test --release -v") .with_stderr_data( str![[r#" [COMPILING] foo v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name a [..]-C lto [..]` [RUNNING] `rustc --crate-name b [..]-C lto [..]` [RUNNING] `rustc --crate-name foo [..]-C lto [..]--test [..]` [RUNNING] `rustc --crate-name foo [..]--crate-type bin [..]-C lto [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/release/deps/foo-[HASH][EXE]` [RUNNING] `[ROOT]/foo/target/release/deps/a-[HASH][EXE]` [RUNNING] `[ROOT]/foo/target/release/deps/b-[HASH][EXE]` "#]] .unordered(), ) .run(); } /// Basic setup: /// /// foo v0.0.0 /// β”œβ”€β”€ bar v0.0.0 /// β”‚ β”œβ”€β”€ registry v0.0.1 /// β”‚ └── registry-shared v0.0.1 /// └── registry-shared v0.0.1 /// /// Where `bar` will have the given crate types. fn project_with_dep(crate_types: &str) -> Project { Package::new("registry", "0.0.1") .file("src/lib.rs", r#"pub fn foo() { println!("registry"); }"#) .publish(); Package::new("registry-shared", "0.0.1") .file("src/lib.rs", r#"pub fn foo() { println!("shared"); }"#) .publish(); project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" [workspace] [dependencies] bar = { path = 'bar' } registry-shared = "*" [profile.release] lto = true "#, ) .file( "src/main.rs", " fn main() { bar::foo(); registry_shared::foo(); } ", ) .file( "bar/Cargo.toml", &format!( r#" [package] name = "bar" version = "0.0.0" edition = "2015" [dependencies] registry = "*" registry-shared = "*" [lib] crate-type = [{}] "#, crate_types ), ) .file( "bar/src/lib.rs", r#" pub fn foo() { println!("bar"); registry::foo(); registry_shared::foo(); } "#, ) .file("tests/a.rs", "") .file("bar/tests/b.rs", "") .build() } /// Helper for checking which LTO behavior is used for a specific crate. /// /// `krate_info` is extra compiler flags used to distinguish this if the same /// crate name is being built multiple times. fn verify_lto(output: &RawOutput, krate: &str, krate_info: &str, expected_lto: Lto) { let stderr = std::str::from_utf8(&output.stderr).unwrap(); let mut matches = stderr.lines().filter(|line| { line.contains("Running") && line.contains(&format!("--crate-name {} ", krate)) && line.contains(krate_info) }); let line = matches.next().unwrap_or_else(|| { panic!( "expected to find crate `{}` info: `{}`, not found in output:\n{}", krate, krate_info, stderr ); }); if let Some(line2) = matches.next() { panic!( "found multiple lines matching crate `{}` info: `{}`:\nline1:{}\nline2:{}\noutput:\n{}", krate, krate_info, line, line2, stderr ); } let actual_lto = if let Some((_, line)) = line.split_once("-C lto=") { let mode = line.splitn(2, ' ').next().unwrap(); if mode == "off" { Lto::Off } else { Lto::Run(Some(mode.into())) } } else if line.contains("-C lto") { Lto::Run(None) } else if line.contains("-C linker-plugin-lto") { Lto::OnlyBitcode } else if line.contains("-C embed-bitcode=no") { Lto::OnlyObject } else { Lto::ObjectAndBitcode }; assert_eq!( actual_lto, expected_lto, "did not find expected LTO in line: {}", line ); } #[cargo_test] fn cdylib_and_rlib() { let p = project_with_dep("'cdylib', 'rlib'"); let output = p.cargo("build --release -v").run(); // `registry` is ObjectAndBitcode because it needs Object for the // rlib, and Bitcode for the cdylib (which doesn't support LTO). verify_lto( &output, "registry", "--crate-type lib", Lto::ObjectAndBitcode, ); // Same as `registry` verify_lto( &output, "registry_shared", "--crate-type lib", Lto::ObjectAndBitcode, ); // Same as `registry` verify_lto( &output, "bar", "--crate-type cdylib --crate-type rlib", Lto::ObjectAndBitcode, ); verify_lto(&output, "foo", "--crate-type bin", Lto::Run(None)); p.cargo("test --release -v") .with_stderr_data( str![[r#" [FRESH] registry v0.0.1 [FRESH] registry-shared v0.0.1 [FRESH] bar v0.0.0 ([ROOT]/foo/bar) [COMPILING] foo v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]-C lto [..]--test [..]` [RUNNING] `rustc --crate-name a [..]-C lto [..]--test [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/release/deps/foo-[HASH][EXE]` [RUNNING] `[ROOT]/foo/target/release/deps/a-[HASH][EXE]` "#]] .unordered(), ) .run(); p.cargo("build --release -v --manifest-path bar/Cargo.toml") .with_stderr_data( str![[r#" [FRESH] registry-shared v0.0.1 [FRESH] registry v0.0.1 [FRESH] bar v0.0.0 ([ROOT]/foo/bar) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); p.cargo("test --release -v --manifest-path bar/Cargo.toml") .with_stderr_data(str![[r#" [FRESH] registry-shared v0.0.1 [FRESH] registry v0.0.1 [COMPILING] bar v0.0.0 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar [..]-C lto [..]--test [..]` [RUNNING] `rustc --crate-name b [..]-C lto [..]--test [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/release/deps/bar-[HASH][EXE]` [RUNNING] `[ROOT]/foo/target/release/deps/b-[HASH][EXE]` [DOCTEST] bar [RUNNING] `rustdoc --edition=2015 --crate-type cdylib --crate-type rlib --color auto --crate-name bar --test [..]-C lto [..] "#]].unordered()) .run(); } #[cargo_test] fn dylib() { let p = project_with_dep("'dylib'"); let output = p.cargo("build --release -v").run(); // `registry` is OnlyObject because rustc doesn't support LTO with dylibs. verify_lto(&output, "registry", "--crate-type lib", Lto::OnlyObject); // `registry_shared` is both because it is needed by both bar (Object) and // foo (Bitcode for LTO). verify_lto( &output, "registry_shared", "--crate-type lib", Lto::ObjectAndBitcode, ); // `bar` is OnlyObject because rustc doesn't support LTO with dylibs. verify_lto(&output, "bar", "--crate-type dylib", Lto::OnlyObject); // `foo` is LTO because it is a binary, and the profile specifies `lto=true`. verify_lto(&output, "foo", "--crate-type bin", Lto::Run(None)); // `cargo test` should not rebuild dependencies. It builds the test // executables with `lto=true` because the tests are built with the // `--release` flag. p.cargo("test --release -v") .with_stderr_data( str![[r#" [FRESH] registry v0.0.1 [FRESH] registry-shared v0.0.1 [FRESH] bar v0.0.0 ([ROOT]/foo/bar) [COMPILING] foo v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]-C lto [..]--test [..]` [RUNNING] `rustc --crate-name a [..]-C lto [..]--test [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/release/deps/foo-[HASH][EXE]` [RUNNING] `[ROOT]/foo/target/release/deps/a-[HASH][EXE]` "#]] .unordered(), ) .run(); // Building just `bar` causes `registry-shared` to get rebuilt because it // switches to OnlyObject because it is now only being used with a dylib // which does not support LTO. // // `bar` gets rebuilt because `registry_shared` got rebuilt. p.cargo("build --release -v --manifest-path bar/Cargo.toml") .with_stderr_data( str![[r#" [COMPILING] registry-shared v0.0.1 [FRESH] registry v0.0.1 [RUNNING] `rustc --crate-name registry_shared [..]-C embed-bitcode=no [..]` [DIRTY] bar v0.0.0 ([..]): dependency info changed [COMPILING] bar v0.0.0 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar [..]--crate-type dylib [..]-C embed-bitcode=no [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); // Testing just `bar` causes `registry` to get rebuilt because it switches // to needing both Object (for the `bar` dylib) and Bitcode (for the test // built with LTO). // // `bar` the dylib gets rebuilt because `registry` got rebuilt. p.cargo("test --release -v --manifest-path bar/Cargo.toml") .with_stderr_data( str![[r#" [FRESH] registry-shared v0.0.1 [COMPILING] registry v0.0.1 [RUNNING] `rustc --crate-name registry [..]` [DIRTY] bar v0.0.0 ([..]): dependency info changed [COMPILING] bar v0.0.0 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar [..]--crate-type dylib [..]-C embed-bitcode=no [..]` [RUNNING] `rustc --crate-name bar [..]-C lto [..]--test [..]` [RUNNING] `rustc --crate-name b [..]-C lto [..]--test [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/release/deps/bar-[HASH][EXE]` [RUNNING] `[ROOT]/foo/target/release/deps/b-[HASH][EXE]` "#]] .unordered(), ) .run(); } #[cargo_test] // This is currently broken on windows-gnu, see https://github.com/rust-lang/rust/issues/109797 #[cfg_attr( all(target_os = "windows", target_env = "gnu"), ignore = "windows-gnu not working" )] fn test_profile() { Package::new("bar", "0.0.1") .file("src/lib.rs", "pub fn foo() -> i32 { 123 } ") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [profile.test] lto = 'thin' [dependencies] bar = "*" "#, ) .file( "src/lib.rs", r#" #[test] fn t1() { assert_eq!(123, bar::foo()); } "#, ) .build(); p.cargo("test -v") // unordered because the two `foo` builds start in parallel .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [COMPILING] bar v0.0.1 [RUNNING] `rustc --crate-name bar [..]--crate-type lib [..]` [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]--crate-type lib --emit=dep-info,metadata,link -C linker-plugin-lto [..]` [RUNNING] `rustc --crate-name foo [..]--emit=dep-info,link -C lto=thin [..]--test [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [DOCTEST] foo [RUNNING] `rustdoc [..] "#]].unordered()) .run(); } #[cargo_test] fn doctest() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [profile.release] lto = true [dependencies] bar = { path = "bar" } "#, ) .file( "src/lib.rs", r#" /// Foo! /// /// ``` /// foo::foo(); /// ``` pub fn foo() { bar::bar(); } "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file( "bar/src/lib.rs", r#" pub fn bar() { println!("hi!"); } "#, ) .build(); p.cargo("test --doc --release -v") // embed-bitcode should be harmless here .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar [..]--crate-type lib [..]-C linker-plugin-lto [..]` [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]--crate-type lib [..]-C linker-plugin-lto [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [DOCTEST] foo [RUNNING] `rustdoc [..]` "#]]) .run(); // Try with bench profile. p.cargo("test --doc --release -v") .env("CARGO_PROFILE_BENCH_LTO", "true") .with_stderr_data( str![[r#" [DOCTEST] foo [RUNNING] `rustdoc [..]-C lto [..]` [FRESH] bar v0.1.0 ([ROOT]/foo/bar) [FRESH] foo v0.1.0 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn dylib_rlib_bin() { // dylib+rlib linked with a binary let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] crate-type = ["dylib", "rlib"] [profile.release] lto = true "#, ) .file("src/lib.rs", "pub fn foo() { println!(\"hi!\"); }") .file("src/bin/ferret.rs", "fn main() { foo::foo(); }") .build(); let output = p.cargo("build --release -v").run(); verify_lto( &output, "foo", "--crate-type dylib --crate-type rlib", Lto::ObjectAndBitcode, ); verify_lto(&output, "ferret", "--crate-type bin", Lto::Run(None)); } #[cargo_test] fn fresh_swapping_commands() { // In some rare cases, different commands end up building dependencies // with different LTO settings. This checks that it doesn't cause the // cache to thrash in that scenario. Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" [profile.release] lto = true "#, ) .file("src/lib.rs", "pub fn foo() { println!(\"hi!\"); }") .build(); p.cargo("build --release -v") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [COMPILING] bar v1.0.0 [RUNNING] `rustc --crate-name bar [..]-C linker-plugin-lto [..]` [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]-C linker-plugin-lto [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("test --release -v") .with_stderr_data( str![[r#" [FRESH] bar v1.0.0 [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]-C lto [..]--test [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/release/deps/foo-[HASH][EXE]` [DOCTEST] foo [RUNNING] `rustdoc [..]-C lto [..]` "#]] .unordered(), ) .run(); p.cargo("build --release -v") .with_stderr_data(str![[r#" [FRESH] bar v1.0.0 [FRESH] foo v0.1.0 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("test --release -v --no-run -v") .with_stderr_data(str![[r#" [FRESH] bar v1.0.0 [FRESH] foo v0.1.0 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [EXECUTABLE] `[ROOT]/foo/target/release/deps/foo-[HASH][EXE]` "#]]) .run(); } cargo-0.86.0/tests/testsuite/main.rs000064400000000000000000000066341046102023000155100ustar 00000000000000#![allow(clippy::disallowed_methods)] #![allow(clippy::print_stderr)] #![allow(clippy::print_stdout)] mod advanced_env; mod alt_registry; mod artifact_dep; mod artifact_dir; mod bad_config; mod bad_manifest_path; mod bench; mod binary_name; mod build; mod build_plan; mod build_script; mod build_script_env; mod build_script_extra_link_arg; mod cache_lock; mod cache_messages; mod cargo; mod cargo_add; mod cargo_alias_config; mod cargo_bench; mod cargo_build; mod cargo_check; mod cargo_clean; mod cargo_command; mod cargo_config; mod cargo_doc; mod cargo_env_config; mod cargo_features; mod cargo_fetch; mod cargo_fix; mod cargo_generate_lockfile; mod cargo_git_checkout; mod cargo_help; mod cargo_info; mod cargo_init; mod cargo_install; mod cargo_locate_project; mod cargo_login; mod cargo_logout; mod cargo_metadata; mod cargo_new; mod cargo_owner; mod cargo_package; mod cargo_pkgid; mod cargo_publish; mod cargo_read_manifest; mod cargo_remove; mod cargo_report; mod cargo_run; mod cargo_rustc; mod cargo_rustdoc; mod cargo_search; mod cargo_targets; mod cargo_test; mod cargo_tree; mod cargo_uninstall; mod cargo_update; mod cargo_vendor; mod cargo_verify_project; mod cargo_version; mod cargo_yank; mod cfg; mod check; mod check_cfg; mod clean; mod collisions; mod concurrent; mod config; mod config_cli; mod config_include; mod corrupt_git; mod credential_process; mod cross_compile; mod cross_publish; mod custom_target; mod death; mod dep_info; mod diagnostics; mod direct_minimal_versions; mod directory; mod doc; mod docscrape; mod edition; mod error; mod features; mod features2; mod features_namespaced; mod fetch; mod fix; mod fix_n_times; mod freshness; mod freshness_checksum; mod future_incompat_report; mod generate_lockfile; mod git; mod git_auth; mod git_gc; mod git_shallow; mod glob_targets; mod global_cache_tracker; mod help; mod https; mod inheritable_workspace_fields; mod install; mod install_upgrade; mod jobserver; mod lints; mod lints_table; mod list_availables; mod local_registry; mod locate_project; mod lockfile_compat; mod lockfile_path; mod login; mod logout; mod lto; mod member_discovery; mod member_errors; mod message_format; mod messages; mod metabuild; mod metadata; mod minimal_versions; mod multitarget; mod net_config; mod new; mod offline; mod old_cargos; mod open_namespaces; mod owner; mod package; mod package_features; mod patch; mod path; mod paths; mod pgo; mod pkgid; mod precise_pre_release; mod proc_macro; mod profile_config; mod profile_custom; mod profile_overrides; mod profile_targets; mod profile_trim_paths; mod profiles; mod progress; mod pub_priv; mod publish; mod publish_lockfile; mod read_manifest; mod registry; mod registry_auth; mod registry_overlay; mod rename_deps; mod replace; mod required_features; mod run; mod rust_version; mod rustc; mod rustc_info_cache; mod rustdoc; mod rustdoc_extern_html; mod rustdocflags; mod rustflags; mod rustup; mod script; mod search; mod shell_quoting; mod source_replacement; mod ssh; mod standard_lib; mod test; mod timings; mod tool_paths; mod tree; mod tree_graph_features; mod unit_graph; mod update; mod vendor; mod verify_project; mod version; mod warn_on_failure; mod warning_override; mod weak_dep_features; mod workspaces; mod yank; use cargo_test_support::prelude::*; #[cargo_test] fn aaa_trigger_cross_compile_disabled_check() { // This triggers the cross compile disabled check to run ASAP, see #5141 cargo_test_support::cross_compile::disabled(); } cargo-0.86.0/tests/testsuite/member_discovery.rs000064400000000000000000000024661046102023000201210ustar 00000000000000//! Tests for workspace member discovery. use cargo::core::{Shell, Workspace}; use cargo::util::context::GlobalContext; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry; /// Tests exclusion of non-directory files from workspace member discovery using glob `*`. #[cargo_test] fn bad_file_member_exclusion() { let p = project() .file( "Cargo.toml", r#" [workspace] members = [ "crates/*" ] "#, ) .file("crates/.DS_Store", "PLACEHOLDER") .file( "crates/bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" authors = [] "#, ) .file("crates/bar/src/main.rs", "fn main() {}") .build(); // Prevent this test from accessing the network by setting up .cargo/config. registry::init(); let gctx = GlobalContext::new( Shell::from_write(Box::new(Vec::new())), paths::cargo_home(), paths::cargo_home(), ); let ws = Workspace::new(&p.root().join("Cargo.toml"), &gctx).unwrap(); assert_eq!(ws.members().count(), 1); assert_eq!(ws.members().next().unwrap().name(), "bar"); } cargo-0.86.0/tests/testsuite/member_errors.rs000064400000000000000000000115541046102023000174240ustar 00000000000000//! Tests for workspace member errors. use cargo::core::resolver::ResolveError; use cargo::core::{compiler::CompileMode, Shell, Workspace}; use cargo::ops::{self, CompileOptions}; use cargo::util::{context::GlobalContext, errors::ManifestError}; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry; use cargo_test_support::str; /// Tests inclusion of a `ManifestError` pointing to a member manifest /// when that manifest fails to deserialize. #[cargo_test] fn toml_deserialize_manifest_error() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = [] [dependencies] bar = { path = "bar" } [workspace] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" authors = [] [dependencies] foobar == "0.55" "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid string expected `"`, `'` --> bar/Cargo.toml:8:25 | 8 | foobar == "0.55" | ^ | [ERROR] failed to load manifest for dependency `bar` "#]]) .run(); } /// Tests inclusion of a `ManifestError` pointing to a member manifest /// when that manifest has an invalid dependency path. #[cargo_test] fn member_manifest_path_io_error() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = [] [dependencies] bar = { path = "bar" } [workspace] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" authors = [] [dependencies] foobar = { path = "nosuch" } "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); let root_manifest_path = p.root().join("Cargo.toml"); let member_manifest_path = p.root().join("bar").join("Cargo.toml"); let missing_manifest_path = p.root().join("bar").join("nosuch").join("Cargo.toml"); let error = Workspace::new(&root_manifest_path, &GlobalContext::default().unwrap()).unwrap_err(); eprintln!("{:?}", error); let manifest_err: &ManifestError = error.downcast_ref().expect("Not a ManifestError"); assert_eq!(manifest_err.manifest_path(), &root_manifest_path); let causes: Vec<_> = manifest_err.manifest_causes().collect(); assert_eq!(causes.len(), 2, "{:?}", causes); assert_eq!(causes[0].manifest_path(), &member_manifest_path); assert_eq!(causes[1].manifest_path(), &missing_manifest_path); } /// Tests dependency version errors provide which package failed via a `ResolveError`. #[cargo_test] fn member_manifest_version_error() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = [] [dependencies] bar = { path = "bar" } [workspace] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" authors = [] [dependencies] i-dont-exist = "0.55" "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); // Prevent this test from accessing the network by setting up .cargo/config. registry::init(); let gctx = GlobalContext::new( Shell::from_write(Box::new(Vec::new())), paths::cargo_home(), paths::cargo_home(), ); let ws = Workspace::new(&p.root().join("Cargo.toml"), &gctx).unwrap(); let compile_options = CompileOptions::new(&gctx, CompileMode::Build).unwrap(); let member_bar = ws.members().find(|m| &*m.name() == "bar").unwrap(); let error = ops::compile(&ws, &compile_options).map(|_| ()).unwrap_err(); eprintln!("{:?}", error); let resolve_err: &ResolveError = error.downcast_ref().expect("Not a ResolveError"); let package_path = resolve_err.package_path(); assert_eq!(package_path.len(), 1, "package_path: {:?}", package_path); assert_eq!(package_path[0], member_bar.package_id()); } cargo-0.86.0/tests/testsuite/message_format.rs000064400000000000000000000077461046102023000175650ustar 00000000000000//! Tests for --message-format flag. use cargo_test_support::prelude::*; use cargo_test_support::{basic_lib_manifest, basic_manifest, project, str}; #[cargo_test] fn cannot_specify_two() { let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/main.rs", "fn main() {}") .build(); let formats = ["human", "json", "short"]; for a in formats.iter() { for b in formats.iter() { p.cargo(&format!("build --message-format {},{}", a, b)) .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot specify two kinds of `message-format` arguments "#]]) .run(); } } } #[cargo_test] fn double_json_works() { let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check --message-format json,json-render-diagnostics") .run(); p.cargo("check --message-format json,json-diagnostic-short") .run(); p.cargo("check --message-format json,json-diagnostic-rendered-ansi") .run(); p.cargo("check --message-format json --message-format json-diagnostic-rendered-ansi") .run(); p.cargo("check --message-format json-diagnostic-rendered-ansi") .run(); p.cargo("check --message-format json-diagnostic-short,json-diagnostic-rendered-ansi") .run(); } #[cargo_test] fn cargo_renders() { let p = project() .file( "Cargo.toml", r#" [package] name = 'foo' version = '0.1.0' [dependencies] bar = { path = 'bar' } "#, ) .file("src/main.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "") .build(); p.cargo("check --message-format json-render-diagnostics") .with_status(101) .with_stdout_data( str![[r#" [ { "reason": "compiler-artifact", "...": "{...}" }, { "reason": "build-finished", "success": false } ] "#]] .is_json() .against_jsonlines(), ) .with_stderr_contains( "\ [CHECKING] bar [..] [CHECKING] foo [..] error[..]`main`[..] ", ) .run(); } #[cargo_test] fn cargo_renders_short() { let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/main.rs", "") .build(); p.cargo("check --message-format json-render-diagnostics,json-diagnostic-short") .with_status(101) .with_stderr_data(str![[r#" [CHECKING] foo v0.1.0 ([ROOT]/foo) error[E0601]: `main` function not found in crate `foo` [ERROR] could not compile `foo` (bin "foo") due to 1 previous error "#]]) .run(); } #[cargo_test] fn cargo_renders_ansi() { let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/main.rs", "") .build(); p.cargo("check --message-format json-diagnostic-rendered-ansi") .with_status(101) .with_stdout_contains("[..]\\u001b[38;5;9merror[..]") .run(); } #[cargo_test] fn cargo_renders_doctests() { let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file( "src/lib.rs", "\ /// ```rust /// bar() /// ``` pub fn bar() {} ", ) .build(); p.cargo("test --doc --message-format short") .with_status(101) .with_stdout_data(str![[r#" running 1 test test src/lib.rs - bar (line 1) ... FAILED failures: ---- src/lib.rs - bar (line 1) stdout ---- src/lib.rs:2:1: error[E0425]: cannot find function `bar`[..] [ERROR] aborting due to 1 previous error Couldn't compile the test. failures: src/lib.rs - bar (line 1) test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/messages.rs000064400000000000000000000117511046102023000163670ustar 00000000000000//! General tests specifically about diagnostics and other messages. //! //! Tests for message caching can be found in `cache_messages`. use cargo_test_support::compare::assert_e2e; use cargo_test_support::prelude::*; use cargo_test_support::{process, project, Project}; use cargo_util::ProcessError; /// Captures the actual diagnostics displayed by rustc. This is done to avoid /// relying on the exact message formatting in rustc. pub fn raw_rustc_output(project: &Project, path: &str, extra: &[&str]) -> String { let mut proc = process("rustc"); if cfg!(windows) { // Sanitize in case the caller wants to do direct string comparison with Cargo's output. proc.arg(path.replace('/', "\\")); } else { proc.arg(path); } let rustc_output = match proc .arg("--crate-type=lib") .args(extra) .cwd(project.root()) .exec_with_output() { Ok(output) => output.stderr, Err(e) => e.downcast::().unwrap().stderr.unwrap(), }; // Do a little dance to remove rustc's "warnings emitted" message and the subsequent newline. let stderr = std::str::from_utf8(&rustc_output).expect("utf8"); let mut lines = stderr.lines(); let mut result = String::new(); while let Some(line) = lines.next() { if line.contains("warning emitted") || line.contains("warnings emitted") || line.contains("aborting due to") { // Eat blank line. match lines.next() { None | Some("") => continue, Some(s) => panic!("unexpected str {}", s), } } result.push_str(line); result.push('\n'); } result } fn redact_rustc_message(msg: &str) -> impl IntoData { use snapbox::filter::{Filter, FilterPaths}; let assert = assert_e2e(); let redactions = assert.redactions(); let msg = redactions.redact(msg); FilterPaths.filter(msg.into()) } #[cargo_test] fn deduplicate_messages_basic() { let p = project() .file( "src/lib.rs", r#" pub fn foo() { let x = 1; } "#, ) .build(); let rustc_message = raw_rustc_output(&p, "src/lib.rs", &[]); let expected_output = format!( "{}\ [WARNING] `foo` (lib) generated 1 warning[..] [WARNING] `foo` (lib test) generated 1 warning (1 duplicate) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) ", rustc_message ); p.cargo("test --no-run -j1") .with_stderr_data(redact_rustc_message(&format!( "\ [COMPILING] foo v0.0.1 ([ROOT]/foo) {}", expected_output ))) .run(); // Run again, to check for caching behavior. p.cargo("test --no-run -j1") .with_stderr_data(redact_rustc_message(&expected_output)) .run(); } #[cargo_test] fn deduplicate_messages_mismatched_warnings() { // One execution prints 1 warning, the other prints 2 where there is an overlap. let p = project() .file( "src/lib.rs", r#" pub fn foo() { let x = 1; } #[test] fn t1() { let MY_VALUE = 1; assert_eq!(MY_VALUE, 1); } "#, ) .build(); let lib_output = raw_rustc_output(&p, "src/lib.rs", &[]); let mut lib_test_output = raw_rustc_output(&p, "src/lib.rs", &["--test"]); // Remove the duplicate warning. let start = lib_test_output.find(&lib_output).expect("same warning"); lib_test_output.replace_range(start..start + lib_output.len(), ""); let expected_output = format!( "\ {}\ [WARNING] `foo` (lib) generated 1 warning[..] {}\ [WARNING] `foo` (lib test) generated 2 warnings (1 duplicate) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) ", lib_output, lib_test_output ); p.cargo("test --no-run -j1") .with_stderr_data(redact_rustc_message(&format!( "\ [COMPILING] foo v0.0.1 ([ROOT]/foo) {}", expected_output ))) .run(); // Run again, to check for caching behavior. p.cargo("test --no-run -j1") .with_stderr_data(redact_rustc_message(&expected_output)) .run(); } #[cargo_test] fn deduplicate_errors() { let p = project() .file( "src/lib.rs", r#" this should not compile "#, ) .build(); let rustc_message = raw_rustc_output(&p, "src/lib.rs", &[]); p.cargo("test -j1") .with_status(101) .with_stderr_data(redact_rustc_message(&format!( "\ [COMPILING] foo v0.0.1 ([ROOT]/foo) {}[ERROR] could not compile `foo` (lib) due to 1 previous error ", rustc_message ))) .run(); } cargo-0.86.0/tests/testsuite/metabuild.rs000064400000000000000000000507511046102023000165310ustar 00000000000000//! Tests for the metabuild feature (declarative build scripts). use std::str; use cargo_test_support::prelude::*; use cargo_test_support::{ basic_lib_manifest, basic_manifest, is_coarse_mtime, project, registry::Package, rustc_host, str, Project, }; #[cargo_test] fn metabuild_gated() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" metabuild = ["mb"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .masquerade_as_nightly_cargo(&["metabuild"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `metabuild` is required The package requires the Cargo feature called `metabuild`, but that feature is not stabilized in this version of Cargo ([..]). Consider adding `cargo-features = ["metabuild"]` to the top of Cargo.toml (above the [package] table) to tell Cargo you are opting in to use this unstable feature. See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#metabuild for more information about the status of this feature. "#]]) .run(); } fn basic_project() -> Project { project() .file( "Cargo.toml", r#" cargo-features = ["metabuild"] [package] name = "foo" version = "0.0.1" edition = "2015" metabuild = ["mb", "mb-other"] [build-dependencies] mb = {path="mb"} mb-other = {path="mb-other"} "#, ) .file("src/lib.rs", "") .file("mb/Cargo.toml", &basic_lib_manifest("mb")) .file( "mb/src/lib.rs", r#"pub fn metabuild() { println!("Hello mb"); }"#, ) .file( "mb-other/Cargo.toml", r#" [package] name = "mb-other" version = "0.0.1" edition = "2015" "#, ) .file( "mb-other/src/lib.rs", r#"pub fn metabuild() { println!("Hello mb-other"); }"#, ) .build() } #[cargo_test] fn metabuild_basic() { let p = basic_project(); p.cargo("check -vv") .masquerade_as_nightly_cargo(&["metabuild"]) .with_stdout_data(str![[r#" [foo 0.0.1] Hello mb [foo 0.0.1] Hello mb-other "#]]) .run(); } #[cargo_test] fn metabuild_error_both() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["metabuild"] [package] name = "foo" version = "0.0.1" edition = "2015" metabuild = "mb" [build-dependencies] mb = {path="mb"} "#, ) .file("src/lib.rs", "") .file("build.rs", r#"fn main() {}"#) .file("mb/Cargo.toml", &basic_lib_manifest("mb")) .file( "mb/src/lib.rs", r#"pub fn metabuild() { println!("Hello mb"); }"#, ) .build(); p.cargo("check -vv") .masquerade_as_nightly_cargo(&["metabuild"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: cannot specify both `metabuild` and `build` "#]]) .run(); } #[cargo_test] fn metabuild_missing_dep() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["metabuild"] [package] name = "foo" version = "0.0.1" edition = "2015" metabuild = "mb" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -vv") .masquerade_as_nightly_cargo(&["metabuild"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: metabuild package `mb` must be specified in `build-dependencies` "#]]) .run(); } #[cargo_test] fn metabuild_optional_dep() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["metabuild"] [package] name = "foo" version = "0.0.1" edition = "2015" metabuild = "mb" [build-dependencies] mb = {path="mb", optional=true} "#, ) .file("src/lib.rs", "") .file("mb/Cargo.toml", &basic_lib_manifest("mb")) .file( "mb/src/lib.rs", r#"pub fn metabuild() { println!("Hello mb"); }"#, ) .build(); p.cargo("check -vv") .masquerade_as_nightly_cargo(&["metabuild"]) .with_stdout_does_not_contain("[foo 0.0.1] Hello mb") .run(); p.cargo("check -vv --features mb") .masquerade_as_nightly_cargo(&["metabuild"]) .with_stdout_contains("[foo 0.0.1] Hello mb") .run(); } #[cargo_test] fn metabuild_lib_name() { // Test when setting `name` on [lib]. let p = project() .file( "Cargo.toml", r#" cargo-features = ["metabuild"] [package] name = "foo" version = "0.0.1" edition = "2015" metabuild = "mb" [build-dependencies] mb = {path="mb"} "#, ) .file("src/lib.rs", "") .file( "mb/Cargo.toml", r#" [package] name = "mb" version = "0.0.1" edition = "2015" [lib] name = "other" "#, ) .file( "mb/src/lib.rs", r#"pub fn metabuild() { println!("Hello mb"); }"#, ) .build(); p.cargo("check -vv") .masquerade_as_nightly_cargo(&["metabuild"]) .with_stdout_data(str![[r#" [foo 0.0.1] Hello mb "#]]) .run(); } #[cargo_test] fn metabuild_fresh() { if is_coarse_mtime() { // This test doesn't work on coarse mtimes very well. Because the // metabuild script is created at build time, its mtime is almost // always equal to the mtime of the output. The second call to `build` // will then think it needs to be rebuilt when it should be fresh. return; } // Check that rebuild is fresh. let p = project() .file( "Cargo.toml", r#" cargo-features = ["metabuild"] [package] name = "foo" version = "0.0.1" edition = "2015" metabuild = "mb" [build-dependencies] mb = {path="mb"} "#, ) .file("src/lib.rs", "") .file("mb/Cargo.toml", &basic_lib_manifest("mb")) .file( "mb/src/lib.rs", r#"pub fn metabuild() { println!("Hello mb"); }"#, ) .build(); p.cargo("check -vv") .masquerade_as_nightly_cargo(&["metabuild"]) .with_stdout_contains("[foo 0.0.1] Hello mb") .run(); p.cargo("check -vv") .masquerade_as_nightly_cargo(&["metabuild"]) .with_stdout_does_not_contain("[foo 0.0.1] Hello mb") .with_stderr_data(str![[r#" [FRESH] mb v0.5.0 ([ROOT]/foo/mb) [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn metabuild_links() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["metabuild"] [package] name = "foo" version = "0.0.1" edition = "2015" links = "cat" metabuild = "mb" [build-dependencies] mb = {path="mb"} "#, ) .file("src/lib.rs", "") .file("mb/Cargo.toml", &basic_lib_manifest("mb")) .file( "mb/src/lib.rs", r#" pub fn metabuild() { assert_eq!(std::env::var("CARGO_MANIFEST_LINKS"), Ok("cat".to_string())); println!("Hello mb"); } "#, ) .build(); p.cargo("check -vv") .masquerade_as_nightly_cargo(&["metabuild"]) .with_stdout_data(str![[r#" [foo 0.0.1] Hello mb "#]]) .run(); } #[cargo_test] fn metabuild_override() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["metabuild"] [package] name = "foo" version = "0.0.1" edition = "2015" links = "cat" metabuild = "mb" [build-dependencies] mb = {path="mb"} "#, ) .file("src/lib.rs", "") .file("mb/Cargo.toml", &basic_lib_manifest("mb")) .file( "mb/src/lib.rs", r#"pub fn metabuild() { panic!("should not run"); }"#, ) .file( ".cargo/config.toml", &format!( r#" [target.{}.cat] rustc-link-lib = ["a"] "#, rustc_host() ), ) .build(); p.cargo("check -vv") .masquerade_as_nightly_cargo(&["metabuild"]) .run(); } #[cargo_test] fn metabuild_workspace() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["member1", "member2"] "#, ) .file( "member1/Cargo.toml", r#" cargo-features = ["metabuild"] [package] name = "member1" version = "0.0.1" edition = "2015" metabuild = ["mb1", "mb2"] [build-dependencies] mb1 = {path="../../mb1"} mb2 = {path="../../mb2"} "#, ) .file("member1/src/lib.rs", "") .file( "member2/Cargo.toml", r#" cargo-features = ["metabuild"] [package] name = "member2" version = "0.0.1" edition = "2015" metabuild = ["mb1"] [build-dependencies] mb1 = {path="../../mb1"} "#, ) .file("member2/src/lib.rs", "") .build(); project() .at("mb1") .file("Cargo.toml", &basic_lib_manifest("mb1")) .file( "src/lib.rs", r#"pub fn metabuild() { println!("Hello mb1 {}", std::env::var("CARGO_MANIFEST_DIR").unwrap()); }"#, ) .build(); project() .at("mb2") .file("Cargo.toml", &basic_lib_manifest("mb2")) .file( "src/lib.rs", r#"pub fn metabuild() { println!("Hello mb2 {}", std::env::var("CARGO_MANIFEST_DIR").unwrap()); }"#, ) .build(); p.cargo("check -vv --workspace") .masquerade_as_nightly_cargo(&["metabuild"]) .with_stdout_contains("[member1 0.0.1] Hello mb1 [..]member1") .with_stdout_contains("[member1 0.0.1] Hello mb2 [..]member1") .with_stdout_contains("[member2 0.0.1] Hello mb1 [..]member2") .with_stdout_does_not_contain("[member2 0.0.1] Hello mb2 [..]member2") .run(); } #[cargo_test] fn metabuild_metadata() { // The metabuild Target is filtered out of the `metadata` results. let p = basic_project(); let meta = p .cargo("metadata --format-version=1") .masquerade_as_nightly_cargo(&["metabuild"]) .run_json(); let mb_info: Vec<&str> = meta["packages"] .as_array() .unwrap() .iter() .find(|p| p["name"].as_str().unwrap() == "foo") .unwrap()["metabuild"] .as_array() .unwrap() .iter() .map(|s| s.as_str().unwrap()) .collect(); assert_eq!(mb_info, ["mb", "mb-other"]); } #[cargo_test] fn metabuild_build_plan() { let p = basic_project(); p.cargo("build --build-plan -Zunstable-options") .masquerade_as_nightly_cargo(&["metabuild", "build-plan"]) .with_stdout_data( str![[r#" { "inputs": [ "[ROOT]/foo/Cargo.toml", "[ROOT]/foo/mb/Cargo.toml", "[ROOT]/foo/mb-other/Cargo.toml" ], "invocations": [ { "args": "{...}", "compile_mode": "build", "cwd": "[ROOT]/foo", "deps": [], "env": "{...}", "kind": null, "links": {}, "outputs": [ "[ROOT]/foo/target/debug/deps/libmb-[HASH].rlib", "[ROOT]/foo/target/debug/deps/libmb-[HASH].rmeta" ], "package_name": "mb", "package_version": "0.5.0", "program": "rustc", "target_kind": [ "lib" ] }, { "args": "{...}", "compile_mode": "build", "cwd": "[ROOT]/foo", "deps": [], "env": "{...}", "kind": null, "links": {}, "outputs": [ "[ROOT]/foo/target/debug/deps/libmb_other-[HASH].rlib", "[ROOT]/foo/target/debug/deps/libmb_other-[HASH].rmeta" ], "package_name": "mb-other", "package_version": "0.0.1", "program": "rustc", "target_kind": [ "lib" ] }, { "args": "{...}", "compile_mode": "build", "cwd": "[ROOT]/foo", "deps": [ 0, 1 ], "env": "{...}", "kind": null, "links": "{...}", "outputs": "{...}", "package_name": "foo", "package_version": "0.0.1", "program": "rustc", "target_kind": [ "custom-build" ] }, { "args": "{...}", "compile_mode": "run-custom-build", "cwd": "[ROOT]/foo", "deps": [ 2 ], "env": "{...}", "kind": null, "links": {}, "outputs": [], "package_name": "foo", "package_version": "0.0.1", "program": "[ROOT]/foo/target/debug/build/foo-[HASH]/metabuild-foo", "target_kind": [ "custom-build" ] }, { "args": "{...}", "compile_mode": "build", "cwd": "[ROOT]/foo", "deps": [ 3 ], "env": "{...}", "kind": null, "links": "{...}", "outputs": [ "[ROOT]/foo/target/debug/deps/libfoo-[HASH].rlib", "[ROOT]/foo/target/debug/deps/libfoo-[HASH].rmeta" ], "package_name": "foo", "package_version": "0.0.1", "program": "rustc", "target_kind": [ "lib" ] } ] } "#]] .is_json(), ) .run(); assert_eq!(p.glob("target/.metabuild/metabuild-foo-*.rs").count(), 1); } #[cargo_test] fn metabuild_two_versions() { // Two versions of a metabuild dep with the same name. let p = project() .at("ws") .file( "Cargo.toml", r#" [workspace] members = ["member1", "member2"] "#, ) .file( "member1/Cargo.toml", r#" cargo-features = ["metabuild"] [package] name = "member1" version = "0.0.1" edition = "2015" metabuild = ["mb"] [build-dependencies] mb = {path="../../mb1"} "#, ) .file("member1/src/lib.rs", "") .file( "member2/Cargo.toml", r#" cargo-features = ["metabuild"] [package] name = "member2" version = "0.0.1" edition = "2015" metabuild = ["mb"] [build-dependencies] mb = {path="../../mb2"} "#, ) .file("member2/src/lib.rs", "") .build(); project().at("mb1") .file("Cargo.toml", r#" [package] name = "mb" version = "0.0.1" edition = "2015" "#) .file( "src/lib.rs", r#"pub fn metabuild() { println!("Hello mb1 {}", std::env::var("CARGO_MANIFEST_DIR").unwrap()); }"#, ) .build(); project().at("mb2") .file("Cargo.toml", r#" [package] name = "mb" version = "0.0.2" edition = "2015" "#) .file( "src/lib.rs", r#"pub fn metabuild() { println!("Hello mb2 {}", std::env::var("CARGO_MANIFEST_DIR").unwrap()); }"#, ) .build(); p.cargo("check -vv --workspace") .masquerade_as_nightly_cargo(&["metabuild"]) .with_stdout_data( str![[r#" [member2 0.0.1] Hello mb2 [ROOT]/ws/member2 [member1 0.0.1] Hello mb1 [ROOT]/ws/member1 "#]] .unordered(), ) .run(); assert_eq!( p.glob("target/.metabuild/metabuild-member?-*.rs").count(), 2 ); } #[cargo_test] fn metabuild_external_dependency() { Package::new("mb", "1.0.0") .file("Cargo.toml", &basic_manifest("mb", "1.0.0")) .file( "src/lib.rs", r#"pub fn metabuild() { println!("Hello mb"); }"#, ) .publish(); Package::new("dep", "1.0.0") .file( "Cargo.toml", r#" cargo-features = ["metabuild"] [package] name = "dep" version = "1.0.0" edition = "2015" metabuild = ["mb"] [build-dependencies] mb = "1.0" "#, ) .file("src/lib.rs", "") .build_dep("mb", "1.0.0") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] dep = "1.0" "#, ) .file("src/lib.rs", "extern crate dep;") .build(); p.cargo("check -vv") .masquerade_as_nightly_cargo(&["metabuild"]) .with_stdout_data(str![[r#" [dep 1.0.0] Hello mb "#]]) .run(); assert_eq!(p.glob("target/.metabuild/metabuild-dep-*.rs").count(), 1); } #[cargo_test] fn metabuild_json_artifact() { let p = basic_project(); p.cargo("check --message-format=json") .masquerade_as_nightly_cargo(&["metabuild"]) .with_stdout_data( str![[r#" [ "{...}", { "executable": null, "features": [], "filenames": "{...}", "fresh": false, "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.0.1", "profile": "{...}", "reason": "compiler-artifact", "target": { "crate_types": [ "bin" ], "doc": false, "doctest": false, "edition": "2018", "kind": [ "custom-build" ], "name": "metabuild-foo", "src_path": "[ROOT]/foo/target/.metabuild/metabuild-foo-[HASH].rs", "test": false } }, { "cfgs": [], "env": [], "linked_libs": [], "linked_paths": [], "out_dir": "[ROOT]/foo/target/debug/build/foo-[HASH]/out", "package_id": "path+[ROOTURL]/foo#0.0.1", "reason": "build-script-executed" }, "{...}" ] "#]] .is_json() .against_jsonlines(), ) .run(); } #[cargo_test] fn metabuild_failed_build_json() { let p = basic_project(); // Modify the metabuild dep so that it fails to compile. p.change_file("mb/src/lib.rs", ""); p.cargo("check --message-format=json") .masquerade_as_nightly_cargo(&["metabuild"]) .with_status(101) .with_stdout_data( str![[r#" [ "{...}", { "manifest_path": "[ROOT]/foo/Cargo.toml", "message": { "level": "error", "message": "cannot find function `metabuild` in crate `mb`", "...": "{...}" }, "package_id": "path+[ROOTURL]/foo#0.0.1", "reason": "compiler-message", "target": { "crate_types": [ "bin" ], "doc": false, "doctest": false, "edition": "2018", "kind": [ "custom-build" ], "name": "metabuild-foo", "src_path": null, "test": false } }, "{...}" ] "#]] .is_json() .against_jsonlines(), ) .run(); } cargo-0.86.0/tests/testsuite/metadata.rs000064400000000000000000003506061046102023000163450ustar 00000000000000//! Tests for the `cargo metadata` command. use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{ basic_bin_manifest, basic_lib_manifest, main_file, project, rustc_host, str, }; use serde_json::json; #[cargo_test] fn cargo_metadata_simple() { let p = project() .file("src/foo.rs", "") .file("Cargo.toml", &basic_bin_manifest("foo")) .build(); p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "foo", "src_path": "[ROOT]/foo/src/foo.rs", "test": true } ], "version": "0.5.0" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo#0.5.0" } ], "root": "path+[ROOTURL]/foo#0.5.0" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn cargo_metadata_warns_on_implicit_version() { let p = project() .file("src/foo.rs", "") .file("Cargo.toml", &basic_bin_manifest("foo")) .build(); p.cargo("metadata") .with_stderr_data(str![[r#" [WARNING] please specify `--format-version` flag explicitly to avoid compatibility problems "#]]) .run(); p.cargo("metadata --format-version 1") .with_stderr_data("") .run(); } #[cargo_test] fn library_with_several_crate_types() { let p = project() .file("src/lib.rs", "") .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" [lib] crate-type = ["lib", "staticlib"] "#, ) .build(); p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib", "staticlib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib", "staticlib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } ], "version": "0.5.0" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo#0.5.0" } ], "root": "path+[ROOTURL]/foo#0.5.0" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn library_with_features() { let p = project() .file("src/lib.rs", "") .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" [features] default = ["default_feat"] default_feat = [] optional_feat = [] "#, ) .build(); p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": { "default": [ "default_feat" ], "default_feat": [], "optional_feat": [] }, "homepage": null, "id": "path+[ROOTURL]/foo#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } ], "version": "0.5.0" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [ "default", "default_feat" ], "id": "path+[ROOTURL]/foo#0.5.0" } ], "root": "path+[ROOTURL]/foo#0.5.0" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn cargo_metadata_with_deps_and_version() { let p = project() .file("src/foo.rs", "") .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" authors = [] license = "MIT" description = "foo" [[bin]] name = "foo" [dependencies] bar = "*" [dev-dependencies] foobar = "*" "#, ) .build(); Package::new("baz", "0.0.1").publish(); Package::new("foobar", "0.0.1").publish(); Package::new("bar", "0.0.1").dep("baz", "0.0.1").publish(); p.cargo("metadata -q --format-version 1") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [ { "features": [], "kind": null, "name": "baz", "optional": false, "registry": null, "rename": null, "req": "^0.0.1", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true } ], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "registry+https://github.com/rust-lang/crates.io-index#bar@0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/bar-0.0.1/Cargo.toml", "metadata": null, "name": "bar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": "registry+https://github.com/rust-lang/crates.io-index", "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "bar", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/bar-0.0.1/src/lib.rs", "test": true } ], "version": "0.0.1" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "registry+https://github.com/rust-lang/crates.io-index#baz@0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/baz-0.0.1/Cargo.toml", "metadata": null, "name": "baz", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": "registry+https://github.com/rust-lang/crates.io-index", "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "baz", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/baz-0.0.1/src/lib.rs", "test": true } ], "version": "0.0.1" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [ { "features": [], "kind": null, "name": "bar", "optional": false, "registry": null, "rename": null, "req": "*", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true }, { "features": [], "kind": "dev", "name": "foobar", "optional": false, "registry": null, "rename": null, "req": "*", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true } ], "description": "foo", "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.5.0", "keywords": [], "license": "MIT", "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "foo", "src_path": "[ROOT]/foo/src/foo.rs", "test": true } ], "version": "0.5.0" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "registry+https://github.com/rust-lang/crates.io-index#foobar@0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/foobar-0.0.1/Cargo.toml", "metadata": null, "name": "foobar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": "registry+https://github.com/rust-lang/crates.io-index", "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foobar", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/foobar-0.0.1/src/lib.rs", "test": true } ], "version": "0.0.1" } ], "resolve": { "nodes": [ { "dependencies": [ "registry+https://github.com/rust-lang/crates.io-index#baz@0.0.1" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": null } ], "name": "baz", "pkg": "registry+https://github.com/rust-lang/crates.io-index#baz@0.0.1" } ], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#bar@0.0.1" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#baz@0.0.1" }, { "dependencies": [ "registry+https://github.com/rust-lang/crates.io-index#bar@0.0.1", "registry+https://github.com/rust-lang/crates.io-index#foobar@0.0.1" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": null } ], "name": "bar", "pkg": "registry+https://github.com/rust-lang/crates.io-index#bar@0.0.1" }, { "dep_kinds": [ { "kind": "dev", "target": null } ], "name": "foobar", "pkg": "registry+https://github.com/rust-lang/crates.io-index#foobar@0.0.1" } ], "features": [], "id": "path+[ROOTURL]/foo#0.5.0" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#foobar@0.0.1" } ], "root": "path+[ROOTURL]/foo#0.5.0" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } /// The `public` field should not show up in `cargo metadata` output if `-Zpublic-dependency` /// is not enabled #[cargo_test] fn cargo_metadata_public_private_dependencies_disabled() { let p = project() .file("src/foo.rs", "") .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" authors = [] license = "MIT" description = "foo" [[bin]] name = "foo" [dependencies] bar = { version = "*", public = false } foobar = { version = "*", public = true } baz = "*" "#, ) .build(); Package::new("bar", "0.0.1").publish(); Package::new("foobar", "0.0.2").publish(); Package::new("baz", "0.0.3").publish(); p.cargo("metadata -q --format-version 1") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "name": "bar", "...": "{...}" }, { "name": "baz", "...": "{...}" }, { "name": "foo", "dependencies": [ { "features": [], "kind": null, "name": "bar", "optional": false, "registry": null, "rename": null, "req": "*", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true }, { "features": [], "kind": null, "name": "baz", "optional": false, "registry": null, "rename": null, "req": "*", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true }, { "features": [], "kind": null, "name": "foobar", "optional": false, "registry": null, "rename": null, "req": "*", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true } ], "...": "{...}" }, { "name": "foobar", "...": "{...}" } ], "...": "{...}" } "#]] .is_json(), ) .run(); } #[cargo_test] fn cargo_metadata_public_private_dependencies_enabled() { let p = project() .file("src/foo.rs", "") .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" authors = [] license = "MIT" description = "foo" [[bin]] name = "foo" [dependencies] bar = { version = "*", public = false } foobar = { version = "*", public = true } baz = "*" "#, ) .build(); Package::new("bar", "0.0.1").publish(); Package::new("foobar", "0.0.2").publish(); Package::new("baz", "0.0.3").publish(); p.cargo("metadata -q --format-version 1 -Zpublic-dependency") .masquerade_as_nightly_cargo(&["public-dependency"]) .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "name": "bar", "...": "{...}" }, { "name": "baz", "...": "{...}" }, { "name": "foo", "dependencies": [ { "features": [], "kind": null, "name": "bar", "optional": false, "public": false, "registry": null, "rename": null, "req": "*", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true }, { "features": [], "kind": null, "name": "baz", "optional": false, "public": false, "registry": null, "rename": null, "req": "*", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true }, { "features": [], "kind": null, "name": "foobar", "optional": false, "public": true, "registry": null, "rename": null, "req": "*", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true } ], "...": "{...}" }, { "name": "foobar", "...": "{...}" } ], "...": "{...}" } "#]] .is_json(), ) .run(); } #[cargo_test] fn example() { let p = project() .file("src/lib.rs", "") .file("examples/ex.rs", "") .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [[example]] name = "ex" "#, ) .build(); p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.1.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true }, { "crate_types": [ "bin" ], "doc": false, "doctest": false, "edition": "2015", "kind": [ "example" ], "name": "ex", "src_path": "[ROOT]/foo/examples/ex.rs", "test": false } ], "version": "0.1.0" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo#0.1.0" } ], "root": "path+[ROOTURL]/foo#0.1.0" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn example_lib() { let p = project() .file("src/lib.rs", "") .file("examples/ex.rs", "") .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [[example]] name = "ex" crate-type = ["rlib", "dylib"] "#, ) .build(); p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.1.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true }, { "crate_types": [ "rlib", "dylib" ], "doc": false, "doctest": false, "edition": "2015", "kind": [ "example" ], "name": "ex", "src_path": "[ROOT]/foo/examples/ex.rs", "test": false } ], "version": "0.1.0" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo#0.1.0" } ], "root": "path+[ROOTURL]/foo#0.1.0" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn workspace_metadata() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] [workspace.metadata] tool1 = "hello" tool2 = [1, 2, 3] [workspace.metadata.foo] bar = 3 "#, ) .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file("bar/src/lib.rs", "") .file("baz/Cargo.toml", &basic_lib_manifest("baz")) .file("baz/src/lib.rs", "") .build(); p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": { "foo": { "bar": 3 }, "tool1": "hello", "tool2": [ 1, 2, 3 ] }, "packages": [ { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo/bar#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/bar/Cargo.toml", "metadata": null, "name": "bar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "bar", "src_path": "[ROOT]/foo/bar/src/lib.rs", "test": true } ], "version": "0.5.0" }, { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo/baz#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/baz/Cargo.toml", "metadata": null, "name": "baz", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "baz", "src_path": "[ROOT]/foo/baz/src/lib.rs", "test": true } ], "version": "0.5.0" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo/bar#0.5.0" }, { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo/baz#0.5.0" } ], "root": null }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo/bar#0.5.0", "path+[ROOTURL]/foo/baz#0.5.0" ], "workspace_members": [ "path+[ROOTURL]/foo/bar#0.5.0", "path+[ROOTURL]/foo/baz#0.5.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn workspace_metadata_with_dependencies_no_deps() { let p = project() // NOTE that 'artifact' isn't mentioned in the workspace here, yet it shows up as member. .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" authors = ["wycats@example.com"] [dependencies] baz = { path = "../baz/" } artifact = { path = "../artifact/", artifact = "bin" } "#, ) .file("bar/src/lib.rs", "") .file("baz/Cargo.toml", &basic_lib_manifest("baz")) .file("baz/src/lib.rs", "") .file("artifact/Cargo.toml", &basic_bin_manifest("artifact")) .file("artifact/src/main.rs", "fn main() {}") .build(); p.cargo("metadata --no-deps -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [ { "artifact": { "kinds": [ "bin" ], "lib": false, "target": null }, "features": [], "kind": null, "name": "artifact", "optional": false, "path": "[ROOT]/foo/artifact", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true }, { "features": [], "kind": null, "name": "baz", "optional": false, "path": "[ROOT]/foo/baz", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true } ], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo/bar#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/bar/Cargo.toml", "metadata": null, "name": "bar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "bar", "src_path": "[ROOT]/foo/bar/src/lib.rs", "test": true } ], "version": "0.5.0" }, { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo/artifact#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/artifact/Cargo.toml", "metadata": null, "name": "artifact", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "artifact", "src_path": "[ROOT]/foo/artifact/src/main.rs", "test": true } ], "version": "0.5.0" }, { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo/baz#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/baz/Cargo.toml", "metadata": null, "name": "baz", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "baz", "src_path": "[ROOT]/foo/baz/src/lib.rs", "test": true } ], "version": "0.5.0" } ], "resolve": null, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo/bar#0.5.0", "path+[ROOTURL]/foo/artifact#0.5.0", "path+[ROOTURL]/foo/baz#0.5.0" ], "workspace_members": [ "path+[ROOTURL]/foo/bar#0.5.0", "path+[ROOTURL]/foo/artifact#0.5.0", "path+[ROOTURL]/foo/baz#0.5.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn workspace_metadata_with_dependencies_and_resolve() { let alt_target = "wasm32-unknown-unknown"; let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "artifact", "non-artifact", "bin-only-artifact"] "#, ) .file( "bar/Cargo.toml", &r#" [package] name = "bar" version = "0.5.0" authors = [] [build-dependencies] artifact = { path = "../artifact/", artifact = "bin", target = "target" } bin-only-artifact = { path = "../bin-only-artifact/", artifact = "bin", target = "$ALT_TARGET" } non-artifact = { path = "../non-artifact" } [dependencies] artifact = { path = "../artifact/", artifact = ["cdylib", "staticlib", "bin:baz-name"], lib = true, target = "$ALT_TARGET" } bin-only-artifact = { path = "../bin-only-artifact/", artifact = "bin:a-name" } non-artifact = { path = "../non-artifact" } [dev-dependencies] artifact = { path = "../artifact/" } non-artifact = { path = "../non-artifact" } bin-only-artifact = { path = "../bin-only-artifact/", artifact = "bin:b-name" } "#.replace("$ALT_TARGET", alt_target), ) .file("bar/src/lib.rs", "") .file("bar/build.rs", "fn main() {}") .file( "artifact/Cargo.toml", r#" [package] name = "artifact" version = "0.5.0" authors = [] [lib] crate-type = ["staticlib", "cdylib", "rlib"] [[bin]] name = "bar-name" [[bin]] name = "baz-name" "#, ) .file("artifact/src/main.rs", "fn main() {}") .file("artifact/src/lib.rs", "") .file( "bin-only-artifact/Cargo.toml", r#" [package] name = "bin-only-artifact" version = "0.5.0" authors = [] [[bin]] name = "a-name" [[bin]] name = "b-name" "#, ) .file("bin-only-artifact/src/main.rs", "fn main() {}") .file("non-artifact/Cargo.toml", r#" [package] name = "non-artifact" version = "0.5.0" authors = [] "#, ) .file("non-artifact/src/lib.rs", "") .build(); p.cargo("metadata -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo/artifact#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/artifact/Cargo.toml", "metadata": null, "name": "artifact", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "staticlib", "cdylib", "rlib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "staticlib", "cdylib", "rlib" ], "name": "artifact", "src_path": "[ROOT]/foo/artifact/src/lib.rs", "test": true }, { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "bar-name", "src_path": "[ROOT]/foo/artifact/src/main.rs", "test": true }, { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "baz-name", "src_path": "[ROOT]/foo/artifact/src/main.rs", "test": true } ], "version": "0.5.0" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [ { "artifact": { "kinds": [ "cdylib", "staticlib", "bin:baz-name" ], "lib": true, "target": "wasm32-unknown-unknown" }, "features": [], "kind": null, "name": "artifact", "optional": false, "path": "[ROOT]/foo/artifact", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true }, { "artifact": { "kinds": [ "bin:a-name" ], "lib": false, "target": null }, "features": [], "kind": null, "name": "bin-only-artifact", "optional": false, "path": "[ROOT]/foo/bin-only-artifact", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true }, { "features": [], "kind": null, "name": "non-artifact", "optional": false, "path": "[ROOT]/foo/non-artifact", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true }, { "features": [], "kind": "dev", "name": "artifact", "optional": false, "path": "[ROOT]/foo/artifact", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true }, { "artifact": { "kinds": [ "bin:b-name" ], "lib": false, "target": null }, "features": [], "kind": "dev", "name": "bin-only-artifact", "optional": false, "path": "[ROOT]/foo/bin-only-artifact", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true }, { "features": [], "kind": "dev", "name": "non-artifact", "optional": false, "path": "[ROOT]/foo/non-artifact", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true }, { "artifact": { "kinds": [ "bin" ], "lib": false, "target": "target" }, "features": [], "kind": "build", "name": "artifact", "optional": false, "path": "[ROOT]/foo/artifact", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true }, { "artifact": { "kinds": [ "bin" ], "lib": false, "target": "wasm32-unknown-unknown" }, "features": [], "kind": "build", "name": "bin-only-artifact", "optional": false, "path": "[ROOT]/foo/bin-only-artifact", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true }, { "features": [], "kind": "build", "name": "non-artifact", "optional": false, "path": "[ROOT]/foo/non-artifact", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true } ], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo/bar#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/bar/Cargo.toml", "metadata": null, "name": "bar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "bar", "src_path": "[ROOT]/foo/bar/src/lib.rs", "test": true }, { "crate_types": [ "bin" ], "doc": false, "doctest": false, "edition": "2015", "kind": [ "custom-build" ], "name": "build-script-build", "src_path": "[ROOT]/foo/bar/build.rs", "test": false } ], "version": "0.5.0" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo/bin-only-artifact#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/bin-only-artifact/Cargo.toml", "metadata": null, "name": "bin-only-artifact", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "a-name", "src_path": "[ROOT]/foo/bin-only-artifact/src/main.rs", "test": true }, { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "b-name", "src_path": "[ROOT]/foo/bin-only-artifact/src/main.rs", "test": true } ], "version": "0.5.0" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo/non-artifact#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/non-artifact/Cargo.toml", "metadata": null, "name": "non-artifact", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "non_artifact", "src_path": "[ROOT]/foo/non-artifact/src/lib.rs", "test": true } ], "version": "0.5.0" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo/artifact#0.5.0" }, { "dependencies": [ "path+[ROOTURL]/foo/artifact#0.5.0", "path+[ROOTURL]/foo/bin-only-artifact#0.5.0", "path+[ROOTURL]/foo/non-artifact#0.5.0" ], "deps": [ { "dep_kinds": [ { "extern_name": "artifact", "kind": null, "target": null }, { "artifact": "cdylib", "compile_target": "wasm32-unknown-unknown", "extern_name": "artifact", "kind": null, "target": null }, { "artifact": "staticlib", "compile_target": "wasm32-unknown-unknown", "extern_name": "artifact", "kind": null, "target": null }, { "artifact": "bin", "bin_name": "baz-name", "compile_target": "wasm32-unknown-unknown", "extern_name": "baz_name", "kind": null, "target": null }, { "kind": "dev", "target": null }, { "artifact": "bin", "bin_name": "bar-name", "compile_target": "", "extern_name": "bar_name", "kind": "build", "target": null }, { "artifact": "bin", "bin_name": "baz-name", "compile_target": "", "extern_name": "baz_name", "kind": "build", "target": null } ], "name": "artifact", "pkg": "path+[ROOTURL]/foo/artifact#0.5.0" }, { "dep_kinds": [ { "artifact": "bin", "bin_name": "a-name", "extern_name": "a_name", "kind": null, "target": null }, { "artifact": "bin", "bin_name": "b-name", "extern_name": "b_name", "kind": "dev", "target": null }, { "artifact": "bin", "bin_name": "a-name", "compile_target": "wasm32-unknown-unknown", "extern_name": "a_name", "kind": "build", "target": null }, { "artifact": "bin", "bin_name": "b-name", "compile_target": "wasm32-unknown-unknown", "extern_name": "b_name", "kind": "build", "target": null } ], "name": "", "pkg": "path+[ROOTURL]/foo/bin-only-artifact#0.5.0" }, { "dep_kinds": [ { "kind": null, "target": null }, { "kind": "dev", "target": null }, { "kind": "build", "target": null } ], "name": "non_artifact", "pkg": "path+[ROOTURL]/foo/non-artifact#0.5.0" } ], "features": [], "id": "path+[ROOTURL]/foo/bar#0.5.0" }, { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo/bin-only-artifact#0.5.0" }, { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo/non-artifact#0.5.0" } ], "root": null }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo/bar#0.5.0", "path+[ROOTURL]/foo/artifact#0.5.0", "path+[ROOTURL]/foo/bin-only-artifact#0.5.0", "path+[ROOTURL]/foo/non-artifact#0.5.0" ], "workspace_members": [ "path+[ROOTURL]/foo/bar#0.5.0", "path+[ROOTURL]/foo/artifact#0.5.0", "path+[ROOTURL]/foo/bin-only-artifact#0.5.0", "path+[ROOTURL]/foo/non-artifact#0.5.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn cargo_metadata_with_invalid_manifest() { let p = project().file("Cargo.toml", "").build(); p.cargo("metadata --format-version 1") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: manifest is missing either a `[package]` or a `[workspace]` "#]]) .run(); } #[cargo_test] fn cargo_metadata_with_invalid_authors_field() { let p = project() .file("src/foo.rs", "") .file( "Cargo.toml", r#" [package] authors = "" "#, ) .build(); p.cargo("metadata") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid type: string "", expected a vector of strings or workspace --> Cargo.toml:3:27 | 3 | authors = "" | ^^ | "#]]) .run(); } #[cargo_test] fn cargo_metadata_with_invalid_version_field() { let p = project() .file("src/foo.rs", "") .file( "Cargo.toml", r#" [package] version = 1 "#, ) .build(); p.cargo("metadata") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid type: integer `1`, expected SemVer version --> Cargo.toml:3:27 | 3 | version = 1 | ^ | "#]]) .run(); } #[cargo_test] fn cargo_metadata_with_invalid_publish_field() { let p = project() .file("src/foo.rs", "") .file( "Cargo.toml", r#" [package] publish = "foo" "#, ) .build(); p.cargo("metadata") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid type: string "foo", expected a boolean, a vector of strings, or workspace --> Cargo.toml:3:27 | 3 | publish = "foo" | ^^^^^ | "#]]) .run(); } #[cargo_test] fn cargo_metadata_with_invalid_artifact_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" [dependencies] artifact = { path = "artifact", artifact = "bin:notfound" } "#, ) .file("src/lib.rs", "") .file("artifact/Cargo.toml", &basic_bin_manifest("artifact")) .file("artifact/src/main.rs", "fn main() {}") .build(); p.cargo("metadata -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_status(101) .with_stderr_data(str![[r#" [WARNING] please specify `--format-version` flag explicitly to avoid compatibility problems [LOCKING] 1 package to latest compatible version [ERROR] dependency `artifact` in package `foo` requires a `bin:notfound` artifact to be present. "#]]) .run(); } #[cargo_test] fn cargo_metadata_with_invalid_duplicate_renamed_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" [dependencies] bar = { path = "bar" } baz = { path = "bar", package = "bar" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file("bar/src/lib.rs", "") .build(); p.cargo("metadata") .with_status(101) .with_stderr_data(str![[r#" [WARNING] please specify `--format-version` flag explicitly to avoid compatibility problems [LOCKING] 1 package to latest compatible version [ERROR] the crate `foo v0.5.0 ([ROOT]/foo)` depends on crate `bar v0.5.0 ([ROOT]/foo/bar)` multiple times with different names "#]]) .run(); } #[cargo_test] fn cargo_metadata_no_deps_path_to_cargo_toml_relative() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("metadata --no-deps --manifest-path foo/Cargo.toml") .cwd(p.root().parent().unwrap()) .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "foo", "src_path": "[ROOT]/foo/src/foo.rs", "test": true } ], "version": "0.5.0" } ], "resolve": null, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn cargo_metadata_no_deps_path_to_cargo_toml_absolute() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("metadata --no-deps --manifest-path") .arg(p.root().join("Cargo.toml")) .cwd(p.root().parent().unwrap()) .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "foo", "src_path": "[ROOT]/foo/src/foo.rs", "test": true } ], "version": "0.5.0" } ], "resolve": null, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn cargo_metadata_no_deps_path_to_cargo_toml_parent_relative() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("metadata --no-deps --manifest-path foo") .cwd(p.root().parent().unwrap()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the manifest-path must be a path to a Cargo.toml file "#]]) .run(); } #[cargo_test] fn cargo_metadata_no_deps_path_to_cargo_toml_parent_absolute() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("metadata --no-deps --manifest-path") .arg(p.root()) .cwd(p.root().parent().unwrap()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the manifest-path must be a path to a Cargo.toml file "#]]) .run(); } #[cargo_test] fn cargo_metadata_no_deps_cwd() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("metadata --no-deps") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "foo", "src_path": "[ROOT]/foo/src/foo.rs", "test": true } ], "version": "0.5.0" } ], "resolve": null, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn cargo_metadata_bad_version() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("metadata --no-deps --format-version 2") .with_status(1) .with_stderr_data(str![[r#" [ERROR] invalid value '2' for '--format-version ' [possible values: 1] ... "#]]) .run(); } #[cargo_test] fn multiple_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = [] [features] a = [] b = [] "#, ) .file("src/lib.rs", "") .build(); p.cargo("metadata --features").arg("a b").run(); } #[cargo_test] fn package_metadata() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = ["wycats@example.com"] categories = ["database"] keywords = ["database"] readme = "README.md" repository = "https://github.com/rust-lang/cargo" homepage = "https://rust-lang.org" documentation = "https://doc.rust-lang.org/stable/std/" [package.metadata.bar] baz = "quux" "#, ) .file("README.md", "") .file("src/lib.rs", "") .build(); p.cargo("metadata --no-deps") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [ "wycats@example.com" ], "categories": [ "database" ], "default_run": null, "dependencies": [], "description": null, "documentation": "https://doc.rust-lang.org/stable/std/", "edition": "2015", "features": {}, "homepage": "https://rust-lang.org", "id": "path+[ROOTURL]/foo#0.1.0", "keywords": [ "database" ], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": { "bar": { "baz": "quux" } }, "name": "foo", "publish": null, "readme": "README.md", "repository": "https://github.com/rust-lang/cargo", "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } ], "version": "0.1.0" } ], "resolve": null, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn package_publish() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = ["wycats@example.com"] categories = ["database"] keywords = ["database"] readme = "README.md" repository = "https://github.com/rust-lang/cargo" publish = ["my-registry"] "#, ) .file("README.md", "") .file("src/lib.rs", "") .build(); p.cargo("metadata --no-deps") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [ "wycats@example.com" ], "categories": [ "database" ], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.1.0", "keywords": [ "database" ], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": [ "my-registry" ], "readme": "README.md", "repository": "https://github.com/rust-lang/cargo", "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } ], "version": "0.1.0" } ], "resolve": null, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn cargo_metadata_path_to_cargo_toml_project() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] "#, ) .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file("bar/src/lib.rs", "") .build(); p.cargo("package --manifest-path") .arg(p.root().join("bar/Cargo.toml")) .cwd(p.root().parent().unwrap()) .run(); p.cargo("metadata --manifest-path") .arg(p.root().join("target/package/bar-0.5.0/Cargo.toml")) .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo/target/package/bar-0.5.0#bar@0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/target/package/bar-0.5.0/Cargo.toml", "metadata": null, "name": "bar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "bar", "src_path": "[ROOT]/foo/target/package/bar-0.5.0/src/lib.rs", "test": true } ], "version": "0.5.0" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo/target/package/bar-0.5.0#bar@0.5.0" } ], "root": "path+[ROOTURL]/foo/target/package/bar-0.5.0#bar@0.5.0" }, "target_directory": "[ROOT]/foo/target/package/bar-0.5.0/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo/target/package/bar-0.5.0#bar@0.5.0" ], "workspace_members": [ "path+[ROOTURL]/foo/target/package/bar-0.5.0#bar@0.5.0" ], "workspace_root": "[ROOT]/foo/target/package/bar-0.5.0" } "#]] .is_json(), ) .run(); } #[cargo_test] fn package_edition_2018() { let p = project() .file("src/lib.rs", "") .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = ["wycats@example.com"] edition = "2018" "#, ) .build(); p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2018", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.1.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2018", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } ], "version": "0.1.0" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo#0.1.0" } ], "root": "path+[ROOTURL]/foo#0.1.0" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn package_default_run() { let p = project() .file("src/lib.rs", "") .file("src/bin/a.rs", r#"fn main() { println!("hello A"); }"#) .file("src/bin/b.rs", r#"fn main() { println!("hello B"); }"#) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = ["wycats@example.com"] edition = "2018" default-run = "a" "#, ) .build(); let json = p.cargo("metadata").run_json(); assert_eq!(json["packages"][0]["default_run"], json!("a")); } #[cargo_test] fn package_rust_version() { let p = project() .file("src/lib.rs", "") .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = ["wycats@example.com"] edition = "2018" rust-version = "1.56" "#, ) .build(); let json = p.cargo("metadata").run_json(); assert_eq!(json["packages"][0]["rust_version"], json!("1.56")); } #[cargo_test] fn target_edition_2018() { let p = project() .file("src/lib.rs", "") .file("src/main.rs", "") .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = ["wycats@example.com"] edition = "2015" [lib] edition = "2018" "#, ) .build(); p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.1.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2018", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true }, { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "foo", "src_path": "[ROOT]/foo/src/main.rs", "test": true } ], "version": "0.1.0" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo#0.1.0" } ], "root": "path+[ROOTURL]/foo#0.1.0" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn rename_dependency() { Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.2.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [dependencies] bar = { version = "0.1.0" } baz = { version = "0.2.0", package = "bar" } "#, ) .file("src/lib.rs", "extern crate bar; extern crate baz;") .build(); p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "registry+https://github.com/rust-lang/crates.io-index#bar@0.1.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/bar-0.1.0/Cargo.toml", "metadata": null, "name": "bar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": "registry+https://github.com/rust-lang/crates.io-index", "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "bar", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/bar-0.1.0/src/lib.rs", "test": true } ], "version": "0.1.0" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "registry+https://github.com/rust-lang/crates.io-index#bar@0.2.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/bar-0.2.0/Cargo.toml", "metadata": null, "name": "bar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": "registry+https://github.com/rust-lang/crates.io-index", "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "bar", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/bar-0.2.0/src/lib.rs", "test": true } ], "version": "0.2.0" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [ { "features": [], "kind": null, "name": "bar", "optional": false, "registry": null, "rename": null, "req": "^0.1.0", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true }, { "features": [], "kind": null, "name": "bar", "optional": false, "registry": null, "rename": "baz", "req": "^0.2.0", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true } ], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } ], "version": "0.0.1" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#bar@0.1.0" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#bar@0.2.0" }, { "dependencies": [ "registry+https://github.com/rust-lang/crates.io-index#bar@0.1.0", "registry+https://github.com/rust-lang/crates.io-index#bar@0.2.0" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": null } ], "name": "bar", "pkg": "registry+https://github.com/rust-lang/crates.io-index#bar@0.1.0" }, { "dep_kinds": [ { "kind": null, "target": null } ], "name": "baz", "pkg": "registry+https://github.com/rust-lang/crates.io-index#bar@0.2.0" } ], "features": [], "id": "path+[ROOTURL]/foo#0.0.1" } ], "root": "path+[ROOTURL]/foo#0.0.1" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.0.1" ], "workspace_members": [ "path+[ROOTURL]/foo#0.0.1" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn metadata_links() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" links = "a" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.5.0", "keywords": [], "license": null, "license_file": null, "links": "a", "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true }, { "crate_types": [ "bin" ], "doc": false, "doctest": false, "edition": "2015", "kind": [ "custom-build" ], "name": "build-script-build", "src_path": "[ROOT]/foo/build.rs", "test": false } ], "version": "0.5.0" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo#0.5.0" } ], "root": "path+[ROOTURL]/foo#0.5.0" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn deps_with_bin_only() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bdep = { path = "bdep" } "#, ) .file("src/lib.rs", "") .file("bdep/Cargo.toml", &basic_bin_manifest("bdep")) .file("bdep/src/main.rs", "fn main() {}") .build(); p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [ { "features": [], "kind": null, "name": "bdep", "optional": false, "path": "[ROOT]/foo/bdep", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true } ], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.1.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } ], "version": "0.1.0" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo#0.1.0" } ], "root": "path+[ROOTURL]/foo#0.1.0" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn filter_platform() { // Testing the --filter-platform flag. Package::new("normal-dep", "0.0.1").publish(); Package::new("host-dep", "0.0.1").publish(); Package::new("alt-dep", "0.0.1").publish(); Package::new("cfg-dep", "0.0.1").publish(); // Just needs to be a valid target that is different from host. // Presumably nobody runs these tests on wasm. πŸ™ƒ let alt_target = "wasm32-unknown-unknown"; let host_target = rustc_host(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] normal-dep = "0.0.1" [target.{}.dependencies] host-dep = "0.0.1" [target.{}.dependencies] alt-dep = "0.0.1" [target.'cfg(foobar)'.dependencies] cfg-dep = "0.0.1" "#, host_target, alt_target ), ) .file("src/lib.rs", "") .build(); // We're going to be checking that we don't download excessively, // so we need to ensure that downloads will happen. let clear = || { paths::cargo_home().join("registry/cache").rm_rf(); paths::cargo_home().join("registry/src").rm_rf(); p.build_dir().rm_rf(); }; // Normal metadata, no filtering, returns *everything*. p.cargo("metadata") .with_stderr_data( str![[r#" [WARNING] please specify `--format-version` flag explicitly to avoid compatibility problems [UPDATING] `dummy-registry` index [LOCKING] 4 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] normal-dep v0.0.1 (registry `dummy-registry`) [DOWNLOADED] host-dep v0.0.1 (registry `dummy-registry`) [DOWNLOADED] cfg-dep v0.0.1 (registry `dummy-registry`) [DOWNLOADED] alt-dep v0.0.1 (registry `dummy-registry`) "#]] .unordered(), ) .with_stdout_data( str![[r#" { "packages": [ { "name": "alt-dep", "dependencies": [], "...": "{...}" }, { "name": "cfg-dep", "dependencies": [], "...": "{...}" }, { "name": "foo", "dependencies": [ { "name": "normal-dep", "target": null, "...": "{...}" }, { "name": "cfg-dep", "target": "cfg(foobar)", "...": "{...}" }, { "name": "alt-dep", "target": "wasm32-unknown-unknown", "...": "{...}" }, { "name": "host-dep", "target": "[HOST_TARGET]", "...": "{...}" } ], "...": "{...}" }, { "name": "host-dep", "dependencies": [], "...": "{...}" }, { "name": "normal-dep", "dependencies": [], "...": "{...}" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#alt-dep@0.0.1" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#cfg-dep@0.0.1" }, { "dependencies": [ "registry+https://github.com/rust-lang/crates.io-index#alt-dep@0.0.1", "registry+https://github.com/rust-lang/crates.io-index#cfg-dep@0.0.1", "registry+https://github.com/rust-lang/crates.io-index#host-dep@0.0.1", "registry+https://github.com/rust-lang/crates.io-index#normal-dep@0.0.1" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": "wasm32-unknown-unknown" } ], "name": "alt_dep", "pkg": "registry+https://github.com/rust-lang/crates.io-index#alt-dep@0.0.1" }, { "dep_kinds": [ { "kind": null, "target": "cfg(foobar)" } ], "name": "cfg_dep", "pkg": "registry+https://github.com/rust-lang/crates.io-index#cfg-dep@0.0.1" }, { "dep_kinds": [ { "kind": null, "target": "[HOST_TARGET]" } ], "name": "host_dep", "pkg": "registry+https://github.com/rust-lang/crates.io-index#host-dep@0.0.1" }, { "dep_kinds": [ { "kind": null, "target": null } ], "name": "normal_dep", "pkg": "registry+https://github.com/rust-lang/crates.io-index#normal-dep@0.0.1" } ], "features": [], "id": "path+[ROOTURL]/foo#0.1.0" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#host-dep@0.0.1" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#normal-dep@0.0.1" } ], "root": "path+[ROOTURL]/foo#0.1.0" }, "...": "{...}" } "#]] .is_json() .unordered(), ) .run(); clear(); // Filter on alternate, removes cfg and host. p.cargo("metadata --filter-platform") .arg(alt_target) .with_stderr_data( str![[r#" [WARNING] please specify `--format-version` flag explicitly to avoid compatibility problems [DOWNLOADING] crates ... [DOWNLOADED] normal-dep v0.0.1 (registry `dummy-registry`) [DOWNLOADED] host-dep v0.0.1 (registry `dummy-registry`) [DOWNLOADED] alt-dep v0.0.1 (registry `dummy-registry`) "#]] .unordered(), ) .with_stdout_data( str![[r#" { "packages": [ { "name": "alt-dep", "dependencies": [], "...": "{...}" }, { "name": "foo", "dependencies": [ { "name": "normal-dep", "target": null, "...": "{...}" }, { "name": "cfg-dep", "target": "cfg(foobar)", "...": "{...}" }, { "name": "alt-dep", "target": "wasm32-unknown-unknown", "...": "{...}" }, { "name": "host-dep", "target": "[HOST_TARGET]", "...": "{...}" } ], "...": "{...}" }, { "name": "normal-dep", "dependencies": [], "...": "{...}" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#alt-dep@0.0.1" }, { "dependencies": [ "registry+https://github.com/rust-lang/crates.io-index#alt-dep@0.0.1", "registry+https://github.com/rust-lang/crates.io-index#normal-dep@0.0.1" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": "wasm32-unknown-unknown" } ], "name": "alt_dep", "pkg": "registry+https://github.com/rust-lang/crates.io-index#alt-dep@0.0.1" }, { "dep_kinds": [ { "kind": null, "target": null } ], "name": "normal_dep", "pkg": "registry+https://github.com/rust-lang/crates.io-index#normal-dep@0.0.1" } ], "features": [], "id": "path+[ROOTURL]/foo#0.1.0" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#normal-dep@0.0.1" } ], "root": "path+[ROOTURL]/foo#0.1.0" }, "...": "{...}" } "#]] .is_json() .unordered(), ) .run(); clear(); // Filter on host, removes alt and cfg. p.cargo("metadata --filter-platform") .arg(&host_target) .with_stderr_data( str![[r#" [WARNING] please specify `--format-version` flag explicitly to avoid compatibility problems [DOWNLOADING] crates ... [DOWNLOADED] normal-dep v0.0.1 (registry `dummy-registry`) [DOWNLOADED] host-dep v0.0.1 (registry `dummy-registry`) "#]] .unordered(), ) .with_stdout_data( str![[r#" { "packages": [ { "name": "foo", "dependencies": [ { "name": "normal-dep", "target": null, "...": "{...}" }, { "name": "cfg-dep", "target": "cfg(foobar)", "...": "{...}" }, { "name": "alt-dep", "target": "wasm32-unknown-unknown", "...": "{...}" }, { "name": "host-dep", "target": "[HOST_TARGET]", "...": "{...}" } ], "...": "{...}" }, { "name": "host-dep", "dependencies": [], "...": "{...}" }, { "name": "normal-dep", "dependencies": [], "...": "{...}" } ], "resolve": { "nodes": [ { "dependencies": [ "registry+https://github.com/rust-lang/crates.io-index#host-dep@0.0.1", "registry+https://github.com/rust-lang/crates.io-index#normal-dep@0.0.1" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": "[HOST_TARGET]" } ], "name": "host_dep", "pkg": "registry+https://github.com/rust-lang/crates.io-index#host-dep@0.0.1" }, { "dep_kinds": [ { "kind": null, "target": null } ], "name": "normal_dep", "pkg": "registry+https://github.com/rust-lang/crates.io-index#normal-dep@0.0.1" } ], "features": [], "id": "path+[ROOTURL]/foo#0.1.0" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#host-dep@0.0.1" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#normal-dep@0.0.1" } ], "root": "path+[ROOTURL]/foo#0.1.0" }, "...": "{...}" } "#]] .is_json() .unordered(), ) .run(); clear(); // Filter host with cfg, removes alt only p.cargo("metadata --filter-platform") .arg(&host_target) .env("RUSTFLAGS", "--cfg=foobar") .with_stderr_data( str![[r#" [WARNING] please specify `--format-version` flag explicitly to avoid compatibility problems [DOWNLOADING] crates ... [DOWNLOADED] normal-dep v0.0.1 (registry `dummy-registry`) [DOWNLOADED] host-dep v0.0.1 (registry `dummy-registry`) [DOWNLOADED] cfg-dep v0.0.1 (registry `dummy-registry`) "#]] .unordered(), ) .with_stdout_data( str![[r#" { "packages": [ { "name": "cfg-dep", "dependencies": [], "...": "{...}" }, { "name": "foo", "dependencies": [ { "name": "normal-dep", "target": null, "...": "{...}" }, { "name": "cfg-dep", "target": "cfg(foobar)", "...": "{...}" }, { "name": "alt-dep", "target": "wasm32-unknown-unknown", "...": "{...}" }, { "name": "host-dep", "target": "[HOST_TARGET]", "...": "{...}" } ], "...": "{...}" }, { "name": "host-dep", "dependencies": [], "...": "{...}" }, { "name": "normal-dep", "dependencies": [], "...": "{...}" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#cfg-dep@0.0.1" }, { "dependencies": [ "registry+https://github.com/rust-lang/crates.io-index#cfg-dep@0.0.1", "registry+https://github.com/rust-lang/crates.io-index#host-dep@0.0.1", "registry+https://github.com/rust-lang/crates.io-index#normal-dep@0.0.1" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": "cfg(foobar)" } ], "name": "cfg_dep", "pkg": "registry+https://github.com/rust-lang/crates.io-index#cfg-dep@0.0.1" }, { "dep_kinds": [ { "kind": null, "target": "[HOST_TARGET]" } ], "name": "host_dep", "pkg": "registry+https://github.com/rust-lang/crates.io-index#host-dep@0.0.1" }, { "dep_kinds": [ { "kind": null, "target": null } ], "name": "normal_dep", "pkg": "registry+https://github.com/rust-lang/crates.io-index#normal-dep@0.0.1" } ], "features": [], "id": "path+[ROOTURL]/foo#0.1.0" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#host-dep@0.0.1" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#normal-dep@0.0.1" } ], "root": "path+[ROOTURL]/foo#0.1.0" }, "...": "{...}" } "#]] .is_json() .unordered(), ) .run(); } #[cargo_test] fn dep_kinds() { Package::new("bar", "0.1.0").publish(); Package::new("winapi", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = "0.1" [dev-dependencies] bar = "0.1" [build-dependencies] bar = "0.1" [target.'cfg(windows)'.dependencies] winapi = "0.1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": null, "packages": "{...}", "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#bar@0.1.0" }, { "dependencies": [ "registry+https://github.com/rust-lang/crates.io-index#bar@0.1.0", "registry+https://github.com/rust-lang/crates.io-index#winapi@0.1.0" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": null }, { "kind": "dev", "target": null }, { "kind": "build", "target": null } ], "name": "bar", "pkg": "registry+https://github.com/rust-lang/crates.io-index#bar@0.1.0" }, { "dep_kinds": [ { "kind": null, "target": "cfg(windows)" } ], "name": "winapi", "pkg": "registry+https://github.com/rust-lang/crates.io-index#winapi@0.1.0" } ], "features": [], "id": "path+[ROOTURL]/foo#0.1.0" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#winapi@0.1.0" } ], "root": "path+[ROOTURL]/foo#0.1.0" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn dep_kinds_workspace() { // Check for bug with duplicate dep kinds in a workspace. // If different members select different features for the same package, // they show up multiple times in the resolver `deps`. // // Here: // foo -> dep // bar -> foo[feat1] -> dep let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [features] feat1 = [] [dependencies] dep = { path="dep" } [workspace] members = ["bar"] "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" [dependencies] foo = { path="..", features=["feat1"] } "#, ) .file("bar/src/lib.rs", "") .file("dep/Cargo.toml", &basic_lib_manifest("dep")) .file("dep/src/lib.rs", "") .build(); p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": null, "packages": "{...}", "resolve": { "nodes": [ { "dependencies": [ "path+[ROOTURL]/foo#0.1.0" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": null } ], "name": "foo", "pkg": "path+[ROOTURL]/foo#0.1.0" } ], "features": [], "id": "path+[ROOTURL]/foo/bar#0.1.0" }, { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo/dep#0.5.0" }, { "dependencies": [ "path+[ROOTURL]/foo/dep#0.5.0" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": null } ], "name": "dep", "pkg": "path+[ROOTURL]/foo/dep#0.5.0" } ], "features": [ "feat1" ], "id": "path+[ROOTURL]/foo#0.1.0" } ], "root": "path+[ROOTURL]/foo#0.1.0" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.1.0" ], "workspace_members": [ "path+[ROOTURL]/foo/bar#0.1.0", "path+[ROOTURL]/foo#0.1.0", "path+[ROOTURL]/foo/dep#0.5.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } // Creating non-utf8 path is an OS-specific pain, so let's run this only on // linux, where arbitrary bytes work. #[cfg(target_os = "linux")] #[cargo_test] fn cargo_metadata_non_utf8() { use std::ffi::OsString; use std::os::unix::ffi::OsStringExt; use std::path::PathBuf; let base = PathBuf::from(OsString::from_vec(vec![255])); let p = project() .no_manifest() .file(base.join("./src/lib.rs"), "") .file(base.join("./Cargo.toml"), &basic_lib_manifest("foo")) .build(); p.cargo("metadata") .cwd(p.root().join(base)) .arg("--format-version") .arg("1") .with_stderr_data(str![[r#" [ERROR] path contains invalid UTF-8 characters "#]]) .with_status(101) .run(); } // TODO: Consider using this test instead of the version without the 'artifact' suffix or merge them because they should be pretty much the same. #[cargo_test] fn workspace_metadata_with_dependencies_no_deps_artifact() { let p = project() // NOTE that 'artifact' isn't mentioned in the workspace here, yet it shows up as member. .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" authors = ["wycats@example.com"] [dependencies] baz = { path = "../baz/" } baz-renamed = { path = "../baz/" } artifact = { path = "../artifact/", artifact = "bin" } "#, ) .file("bar/src/lib.rs", "") .file("baz/Cargo.toml", &basic_lib_manifest("baz")) .file("baz/src/lib.rs", "") .file("artifact/Cargo.toml", &basic_bin_manifest("artifact")) .file("artifact/src/main.rs", "fn main() {}") .build(); p.cargo("metadata --no-deps -Z bindeps") .masquerade_as_nightly_cargo(&["bindeps"]) .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [ { "artifact": { "kinds": [ "bin" ], "lib": false, "target": null }, "features": [], "kind": null, "name": "artifact", "optional": false, "path": "[ROOT]/foo/artifact", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true }, { "features": [], "kind": null, "name": "baz", "optional": false, "path": "[ROOT]/foo/baz", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true }, { "features": [], "kind": null, "name": "baz-renamed", "optional": false, "path": "[ROOT]/foo/baz", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true } ], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo/bar#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/bar/Cargo.toml", "metadata": null, "name": "bar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "bar", "src_path": "[ROOT]/foo/bar/src/lib.rs", "test": true } ], "version": "0.5.0" }, { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo/artifact#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/artifact/Cargo.toml", "metadata": null, "name": "artifact", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "artifact", "src_path": "[ROOT]/foo/artifact/src/main.rs", "test": true } ], "version": "0.5.0" }, { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo/baz#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/baz/Cargo.toml", "metadata": null, "name": "baz", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "baz", "src_path": "[ROOT]/foo/baz/src/lib.rs", "test": true } ], "version": "0.5.0" } ], "resolve": null, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo/bar#0.5.0", "path+[ROOTURL]/foo/artifact#0.5.0", "path+[ROOTURL]/foo/baz#0.5.0" ], "workspace_members": [ "path+[ROOTURL]/foo/bar#0.5.0", "path+[ROOTURL]/foo/artifact#0.5.0", "path+[ROOTURL]/foo/baz#0.5.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } #[cargo_test] fn versionless_packages() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" [dependencies] foobar = "0.0.1" baz = { path = "../baz/" } "#, ) .file("bar/src/lib.rs", "") .file( "baz/Cargo.toml", r#" [package] name = "baz" [dependencies] foobar = "0.0.1" "#, ) .file("baz/src/lib.rs", "") .build(); Package::new("foobar", "0.0.1").publish(); p.cargo("metadata -q --format-version 1") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [ { "features": [], "kind": null, "name": "baz", "optional": false, "path": "[ROOT]/foo/baz", "registry": null, "rename": null, "req": "*", "source": null, "target": null, "uses_default_features": true }, { "features": [], "kind": null, "name": "foobar", "optional": false, "registry": null, "rename": null, "req": "^0.0.1", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true } ], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo/bar#0.0.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/bar/Cargo.toml", "metadata": null, "name": "bar", "publish": [], "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "bar", "src_path": "[ROOT]/foo/bar/src/lib.rs", "test": true } ], "version": "0.0.0" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [ { "features": [], "kind": null, "name": "foobar", "optional": false, "registry": null, "rename": null, "req": "^0.0.1", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true } ], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo/baz#0.0.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/baz/Cargo.toml", "metadata": null, "name": "baz", "publish": [], "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "baz", "src_path": "[ROOT]/foo/baz/src/lib.rs", "test": true } ], "version": "0.0.0" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "registry+https://github.com/rust-lang/crates.io-index#foobar@0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/foobar-0.0.1/Cargo.toml", "metadata": null, "name": "foobar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": "registry+https://github.com/rust-lang/crates.io-index", "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foobar", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/foobar-0.0.1/src/lib.rs", "test": true } ], "version": "0.0.1" } ], "resolve": { "nodes": [ { "dependencies": [ "path+[ROOTURL]/foo/baz#0.0.0", "registry+https://github.com/rust-lang/crates.io-index#foobar@0.0.1" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": null } ], "name": "baz", "pkg": "path+[ROOTURL]/foo/baz#0.0.0" }, { "dep_kinds": [ { "kind": null, "target": null } ], "name": "foobar", "pkg": "registry+https://github.com/rust-lang/crates.io-index#foobar@0.0.1" } ], "features": [], "id": "path+[ROOTURL]/foo/bar#0.0.0" }, { "dependencies": [ "registry+https://github.com/rust-lang/crates.io-index#foobar@0.0.1" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": null } ], "name": "foobar", "pkg": "registry+https://github.com/rust-lang/crates.io-index#foobar@0.0.1" } ], "features": [], "id": "path+[ROOTURL]/foo/baz#0.0.0" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#foobar@0.0.1" } ], "root": null }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo/bar#0.0.0", "path+[ROOTURL]/foo/baz#0.0.0" ], "workspace_members": [ "path+[ROOTURL]/foo/bar#0.0.0", "path+[ROOTURL]/foo/baz#0.0.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } /// Record how TOML-specific types are deserialized by `toml` so we can make sure we know if these change and /// can have a conversation about what should be done. #[cargo_test] fn cargo_metadata_toml_types() { let p = project() .file("src/lib.rs", "") .file( "Cargo.toml", " [package] name = 'foo' edition = '2015' [package.metadata] offset-datetime = 1979-05-27T07:32:00Z local-datetime = 1979-05-27T07:32:00 local-date = 1979-05-27 local-time = 1979-05-27 ", ) .build(); p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.0.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": { "local-date": { "$__toml_private_datetime": "1979-05-27" }, "local-datetime": { "$__toml_private_datetime": "1979-05-27T07:32:00" }, "local-time": { "$__toml_private_datetime": "1979-05-27" }, "offset-datetime": { "$__toml_private_datetime": "1979-05-27T07:32:00Z" } }, "name": "foo", "publish": [], "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } ], "version": "0.0.0" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo#0.0.0" } ], "root": "path+[ROOTURL]/foo#0.0.0" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.0.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.0.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } cargo-0.86.0/tests/testsuite/minimal_versions.rs000064400000000000000000000023151046102023000201320ustar 00000000000000//! Tests for minimal-version resolution. //! //! Note: Some tests are located in the resolver-tests package. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry::Package; use cargo_test_support::str; // Ensure that the "-Z minimal-versions" CLI option works and the minimal // version of a dependency ends up in the lock file. #[cargo_test] fn minimal_version_cli() { Package::new("dep", "1.0.0").publish(); Package::new("dep", "1.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.1" [dependencies] dep = "1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("generate-lockfile -Zminimal-versions") .masquerade_as_nightly_cargo(&["minimal-versions"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to earliest compatible version [ADDING] dep v1.0.0 (available: v1.1.0) "#]]) .run(); let lock = p.read_lockfile(); assert!(!lock.contains("1.1.0")); } cargo-0.86.0/tests/testsuite/multitarget.rs000064400000000000000000000142111046102023000171130ustar 00000000000000//! Tests for multiple `--target` flags to subcommands use cargo_test_support::prelude::*; use cargo_test_support::{basic_manifest, cross_compile, project, rustc_host, str}; #[cargo_test] fn simple_build() { if cross_compile::disabled() { return; } let t1 = cross_compile::alternate(); let t2 = rustc_host(); let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build") .arg("--target") .arg(&t1) .arg("--target") .arg(&t2) .run(); assert!(p.target_bin(t1, "foo").is_file()); assert!(p.target_bin(t2, "foo").is_file()); } #[cargo_test] fn simple_build_with_config() { if cross_compile::disabled() { return; } let t1 = cross_compile::alternate(); let t2 = rustc_host(); let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", &format!( r#" [build] target = ["{t1}", "{t2}"] "# ), ) .build(); p.cargo("build").run(); assert!(p.target_bin(t1, "foo").is_file()); assert!(p.target_bin(t2, "foo").is_file()); } #[cargo_test] fn simple_test() { if !cross_compile::can_run_on_host() { return; } let t1 = cross_compile::alternate(); let t2 = rustc_host(); let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/lib.rs", "fn main() {}") .build(); p.cargo("test") .arg("--target") .arg(&t1) .arg("--target") .arg(&t2) .with_stderr_data( str![[r#" [RUNNING] unittests src/lib.rs (target/[ALT_TARGET]/debug/deps/foo-[HASH][EXE]) [RUNNING] unittests src/lib.rs (target/[HOST_TARGET]/debug/deps/foo-[HASH][EXE]) ... "#]] .unordered(), ) .run(); } #[cargo_test] fn simple_run() { let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/main.rs", "fn main() {}") .build(); p.cargo("run --target a --target b") .with_stderr_data(str![[r#" [ERROR] only one `--target` argument is supported "#]]) .with_status(101) .run(); } #[cargo_test] fn simple_doc() { if cross_compile::disabled() { return; } let t1 = cross_compile::alternate(); let t2 = rustc_host(); let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/lib.rs", "//! empty lib") .build(); p.cargo("doc") .arg("--target") .arg(&t1) .arg("--target") .arg(&t2) .run(); assert!(p.build_dir().join(&t1).join("doc/foo/index.html").is_file()); assert!(p.build_dir().join(&t2).join("doc/foo/index.html").is_file()); } #[cargo_test] fn simple_doc_open() { if cross_compile::disabled() { return; } let t1 = cross_compile::alternate(); let t2 = rustc_host(); let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/lib.rs", "//! empty lib") .build(); p.cargo("doc") .arg("--open") .arg("--target") .arg(&t1) .arg("--target") .arg(&t2) .with_stderr_data(str![[r#" [DOCUMENTING] foo v1.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [ERROR] only one `--target` argument is supported "#]]) .with_status(101) .run(); } #[cargo_test] fn simple_check() { if cross_compile::disabled() { return; } let t1 = cross_compile::alternate(); let t2 = rustc_host(); let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .arg("--target") .arg(&t1) .arg("--target") .arg(&t2) .run(); } #[cargo_test] fn same_value_twice() { if cross_compile::disabled() { return; } let t = rustc_host(); let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build") .arg("--target") .arg(&t) .arg("--target") .arg(&t) .run(); assert!(p.target_bin(t, "foo").is_file()); } #[cargo_test] fn same_value_twice_with_config() { if cross_compile::disabled() { return; } let t = rustc_host(); let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", &format!( r#" [build] target = ["{t}", "{t}"] "# ), ) .build(); p.cargo("build").run(); assert!(p.target_bin(t, "foo").is_file()); } #[cargo_test] fn works_with_config_in_both_string_or_list() { if cross_compile::disabled() { return; } let t = rustc_host(); let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", &format!( r#" [build] target = "{t}" "# ), ) .build(); p.cargo("build").run(); assert!(p.target_bin(t, "foo").is_file()); p.cargo("clean").run(); p.change_file( ".cargo/config.toml", &format!( r#" [build] target = ["{t}"] "# ), ); p.cargo("build").run(); assert!(p.target_bin(t, "foo").is_file()); } #[cargo_test] fn works_with_env() { let t = rustc_host(); let p = project() .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build").env("CARGO_BUILD_TARGET", t).run(); assert!(p.target_bin(t, "foo").is_file()); } cargo-0.86.0/tests/testsuite/net_config.rs000064400000000000000000000032161046102023000166700ustar 00000000000000//! Tests for network configuration. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; #[cargo_test] fn net_retry_loads_from_config() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [dependencies.bar] git = "http://127.0.0.1:11/foo/bar" "#, ) .file("src/main.rs", "") .file( ".cargo/config.toml", r#" [net] retry=1 [http] timeout=1 "#, ) .build(); p.cargo("check -v") .with_status(101) .with_stderr_data(str![[r#" ... [WARNING] spurious network error (1 tries remaining): [..] ... "#]]) .run(); } #[cargo_test] fn net_retry_git_outputs_warning() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [dependencies.bar] git = "http://127.0.0.1:11/foo/bar" "#, ) .file( ".cargo/config.toml", r#" [http] timeout=1 "#, ) .file("src/main.rs", "") .build(); p.cargo("check -v -j 1") .with_status(101) .with_stderr_data(str![[r#" ... [WARNING] spurious network error (2 tries remaining): [..] [WARNING] spurious network error (1 tries remaining): [..] ... "#]]) .run(); } cargo-0.86.0/tests/testsuite/new.rs000064400000000000000000000436431046102023000153560ustar 00000000000000//! Tests for the `cargo new` command. use std::env; use std::fs::{self, File}; use cargo_test_support::cargo_process; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::str; fn create_default_gitconfig() { // This helps on Windows where libgit2 is very aggressive in attempting to // find a git config file. let gitconfig = paths::home().join(".gitconfig"); File::create(gitconfig).unwrap(); // If we're running this under a user account that has a different default branch set up // then tests that assume the default branch is master will fail. We set the default branch // to master explicitly so that tests that rely on this behavior still pass. fs::write( paths::home().join(".gitconfig"), r#" [init] defaultBranch = master "#, ) .unwrap(); } #[cargo_test] fn simple_lib() { cargo_process("new --lib foo --vcs none --edition 2015") .with_stderr_data(str![[r#" [CREATING] library `foo` package [NOTE] see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html "#]]) .run(); assert!(paths::root().join("foo").is_dir()); assert!(paths::root().join("foo/Cargo.toml").is_file()); assert!(paths::root().join("foo/src/lib.rs").is_file()); assert!(!paths::root().join("foo/.gitignore").is_file()); let lib = paths::root().join("foo/src/lib.rs"); let contents = fs::read_to_string(&lib).unwrap(); assert_eq!( contents, r#"pub fn add(left: u64, right: u64) -> u64 { left + right } #[cfg(test)] mod tests { use super::*; #[test] fn it_works() { let result = add(2, 2); assert_eq!(result, 4); } } "# ); cargo_process("build").cwd(&paths::root().join("foo")).run(); } #[cargo_test] fn simple_bin() { cargo_process("new --bin foo --edition 2015") .with_stderr_data(str![[r#" [CREATING] binary (application) `foo` package [NOTE] see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html "#]]) .run(); assert!(paths::root().join("foo").is_dir()); assert!(paths::root().join("foo/Cargo.toml").is_file()); assert!(paths::root().join("foo/src/main.rs").is_file()); cargo_process("build").cwd(&paths::root().join("foo")).run(); assert!(paths::root() .join(&format!("foo/target/debug/foo{}", env::consts::EXE_SUFFIX)) .is_file()); } #[cargo_test] fn both_lib_and_bin() { cargo_process("new --lib --bin foo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] can't specify both lib and binary outputs "#]]) .run(); } #[cargo_test] fn simple_git() { cargo_process("new --lib foo --edition 2015").run(); assert!(paths::root().is_dir()); assert!(paths::root().join("foo/Cargo.toml").is_file()); assert!(paths::root().join("foo/src/lib.rs").is_file()); assert!(paths::root().join("foo/.git").is_dir()); assert!(paths::root().join("foo/.gitignore").is_file()); let fp = paths::root().join("foo/.gitignore"); let contents = fs::read_to_string(&fp).unwrap(); assert_eq!(contents, "/target\n",); cargo_process("build").cwd(&paths::root().join("foo")).run(); } #[cargo_test(requires = "hg")] fn simple_hg() { cargo_process("new --lib foo --edition 2015 --vcs hg").run(); assert!(paths::root().is_dir()); assert!(paths::root().join("foo/Cargo.toml").is_file()); assert!(paths::root().join("foo/src/lib.rs").is_file()); assert!(paths::root().join("foo/.hg").is_dir()); assert!(paths::root().join("foo/.hgignore").is_file()); let fp = paths::root().join("foo/.hgignore"); let contents = fs::read_to_string(&fp).unwrap(); assert_eq!(contents, "^target$\n",); cargo_process("build").cwd(&paths::root().join("foo")).run(); } #[cargo_test] fn no_argument() { cargo_process("new") .with_status(1) .with_stderr_data(str![[r#" [ERROR] the following required arguments were not provided: ... "#]]) .run(); } #[cargo_test] fn existing() { let dst = paths::root().join("foo"); fs::create_dir(&dst).unwrap(); cargo_process("new foo") .with_status(101) .with_stderr_data(str![[r#" [CREATING] binary (application) `foo` package [ERROR] destination `[ROOT]/foo` already exists Use `cargo init` to initialize the directory "#]]) .run(); } #[cargo_test] fn invalid_characters() { cargo_process("new foo.rs") .with_status(101) .with_stderr_data(str![[r#" [CREATING] binary (application) `foo.rs` package [ERROR] invalid character `.` in package name: `foo.rs`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters) If you need a package name to not match the directory name, consider using --name flag. If you need a binary with the name "foo.rs", use a valid package name, and set the binary name to be different from the package. This can be done by setting the binary filename to `src/bin/foo.rs.rs` or change the name in Cargo.toml with: [[bin]] name = "foo.rs" path = "src/main.rs" "#]]) .run(); } #[cargo_test] fn reserved_name() { cargo_process("new test") .with_status(101) .with_stderr_data(str![[r#" [CREATING] binary (application) `test` package [ERROR] the name `test` cannot be used as a package name, it conflicts with Rust's built-in test library If you need a package name to not match the directory name, consider using --name flag. If you need a binary with the name "test", use a valid package name, and set the binary name to be different from the package. This can be done by setting the binary filename to `src/bin/test.rs` or change the name in Cargo.toml with: [[bin]] name = "test" path = "src/main.rs" "#]]) .run(); } #[cargo_test] fn reserved_binary_name() { cargo_process("new --bin incremental") .with_status(101) .with_stderr_data(str![[r#" [CREATING] binary (application) `incremental` package [ERROR] the name `incremental` cannot be used as a package name, it conflicts with cargo's build directory names If you need a package name to not match the directory name, consider using --name flag. "#]]) .run(); cargo_process("new --lib incremental") .with_stderr_data(str![[r#" [CREATING] library `incremental` package [WARNING] the name `incremental` will not support binary executables with that name, it conflicts with cargo's build directory names [NOTE] see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html "#]]) .run(); } #[cargo_test] fn keyword_name() { cargo_process("new pub") .with_status(101) .with_stderr_data(str![[r#" [CREATING] binary (application) `pub` package [ERROR] the name `pub` cannot be used as a package name, it is a Rust keyword If you need a package name to not match the directory name, consider using --name flag. If you need a binary with the name "pub", use a valid package name, and set the binary name to be different from the package. This can be done by setting the binary filename to `src/bin/pub.rs` or change the name in Cargo.toml with: [[bin]] name = "pub" path = "src/main.rs" "#]]) .run(); } #[cargo_test] fn std_name() { cargo_process("new core").with_stderr_data(str![[r#" [CREATING] binary (application) `core` package [WARNING] the name `core` is part of Rust's standard library It is recommended to use a different name to avoid problems. If you need a package name to not match the directory name, consider using --name flag. If you need a binary with the name "core", use a valid package name, and set the binary name to be different from the package. This can be done by setting the binary filename to `src/bin/core.rs` or change the name in Cargo.toml with: [[bin]] name = "core" path = "src/main.rs" [NOTE] see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html "#]]).run(); } #[cargo_test] fn git_prefers_command_line() { let root = paths::root(); fs::create_dir(&root.join(".cargo")).unwrap(); fs::write( &root.join(".cargo/config.toml"), r#" [cargo-new] vcs = "none" name = "foo" email = "bar" "#, ) .unwrap(); cargo_process("new foo --vcs git").run(); assert!(paths::root().join("foo/.gitignore").exists()); assert!(!fs::read_to_string(paths::root().join("foo/Cargo.toml")) .unwrap() .contains("authors =")); } #[cargo_test] fn subpackage_no_git() { cargo_process("new foo").run(); assert!(paths::root().join("foo/.git").is_dir()); assert!(paths::root().join("foo/.gitignore").is_file()); let subpackage = paths::root().join("foo").join("components"); fs::create_dir(&subpackage).unwrap(); cargo_process("new foo/components/subcomponent").run(); assert!(!paths::root() .join("foo/components/subcomponent/.git") .is_file()); assert!(!paths::root() .join("foo/components/subcomponent/.gitignore") .is_file()); } #[cargo_test] fn subpackage_git_with_gitignore() { cargo_process("new foo").run(); assert!(paths::root().join("foo/.git").is_dir()); assert!(paths::root().join("foo/.gitignore").is_file()); let gitignore = paths::root().join("foo/.gitignore"); fs::write(gitignore, b"components").unwrap(); let subpackage = paths::root().join("foo/components"); fs::create_dir(&subpackage).unwrap(); cargo_process("new foo/components/subcomponent").run(); assert!(paths::root() .join("foo/components/subcomponent/.git") .is_dir()); assert!(paths::root() .join("foo/components/subcomponent/.gitignore") .is_file()); } #[cargo_test] fn subpackage_git_with_vcs_arg() { cargo_process("new foo").run(); let subpackage = paths::root().join("foo").join("components"); fs::create_dir(&subpackage).unwrap(); cargo_process("new foo/components/subcomponent --vcs git").run(); assert!(paths::root() .join("foo/components/subcomponent/.git") .is_dir()); assert!(paths::root() .join("foo/components/subcomponent/.gitignore") .is_file()); } #[cargo_test] fn unknown_flags() { cargo_process("new foo --flag") .with_status(1) .with_stderr_data(str![[r#" [ERROR] unexpected argument '--flag' found ... "#]]) .run(); } #[cargo_test] fn explicit_invalid_name_not_suggested() { cargo_process("new --name 10-invalid a") .with_status(101) .with_stderr_data(str![[r#" [CREATING] binary (application) `10-invalid` package [ERROR] invalid character `1` in package name: `10-invalid`, the name cannot start with a digit If you need a binary with the name "10-invalid", use a valid package name, and set the binary name to be different from the package. This can be done by setting the binary filename to `src/bin/10-invalid.rs` or change the name in Cargo.toml with: [[bin]] name = "10-invalid" path = "src/main.rs" "#]]) .run(); } #[cargo_test] fn explicit_project_name() { cargo_process("new --lib foo --name bar") .with_stderr_data(str![[r#" [CREATING] library `bar` package [NOTE] see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html "#]]) .run(); } #[cargo_test] fn new_with_edition_2015() { cargo_process("new --edition 2015 foo").run(); let manifest = fs::read_to_string(paths::root().join("foo/Cargo.toml")).unwrap(); assert!(manifest.contains("edition = \"2015\"")); } #[cargo_test] fn new_with_edition_2018() { cargo_process("new --edition 2018 foo").run(); let manifest = fs::read_to_string(paths::root().join("foo/Cargo.toml")).unwrap(); assert!(manifest.contains("edition = \"2018\"")); } #[cargo_test] fn new_default_edition() { cargo_process("new foo").run(); let manifest = fs::read_to_string(paths::root().join("foo/Cargo.toml")).unwrap(); assert!(manifest.contains("edition = \"2024\"")); } #[cargo_test] fn new_with_bad_edition() { cargo_process("new --edition something_else foo") .with_stderr_data(str![[r#" [ERROR] invalid value 'something_else' for '--edition ' ... "#]]) .with_status(1) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] fn lockfile_constant_during_new() { cargo_process("new foo").run(); cargo_process("build").cwd(&paths::root().join("foo")).run(); let before = fs::read_to_string(paths::root().join("foo/Cargo.lock")).unwrap(); cargo_process("build").cwd(&paths::root().join("foo")).run(); let after = fs::read_to_string(paths::root().join("foo/Cargo.lock")).unwrap(); assert_eq!(before, after); } #[cargo_test] fn restricted_windows_name() { if cfg!(windows) { cargo_process("new nul") .with_status(101) .with_stderr_data(str![[r#" [CREATING] binary (application) `nul` package [ERROR] cannot use name `nul`, it is a reserved Windows filename If you need a package name to not match the directory name, consider using --name flag. "#]]) .run(); } else { cargo_process("new nul").with_stderr_data(str![[r#" [CREATING] binary (application) `nul` package [WARNING] the name `nul` is a reserved Windows filename This package will not work on Windows platforms. [NOTE] see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html "#]]).run(); } } #[cargo_test] fn non_ascii_name() { cargo_process("new ΠŸΡ€ΠΈΠ²Π΅Ρ‚").with_stderr_data(str![[r#" [CREATING] binary (application) `ΠŸΡ€ΠΈΠ²Π΅Ρ‚` package [WARNING] the name `ΠŸΡ€ΠΈΠ²Π΅Ρ‚` contains non-ASCII characters Non-ASCII crate names are not supported by Rust. [WARNING] the name `ΠŸΡ€ΠΈΠ²Π΅Ρ‚` is not snake_case or kebab-case which is recommended for package names, consider `ΠΏΡ€ΠΈΠ²Π΅Ρ‚` [NOTE] see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html "#]]).run(); } #[cargo_test] fn non_ascii_name_invalid() { // These are alphanumeric characters, but not Unicode XID. cargo_process("new β’Άβ’·β’Έ") .with_status(101) .with_stderr_data(str![[r#" [CREATING] binary (application) `β’Άβ’·β’Έ` package [ERROR] invalid character `β’Ά` in package name: `β’Άβ’·β’Έ`, the first character must be a Unicode XID start character (most letters or `_`) If you need a package name to not match the directory name, consider using --name flag. If you need a binary with the name "β’Άβ’·β’Έ", use a valid package name, and set the binary name to be different from the package. This can be done by setting the binary filename to `src/bin/β’Άβ’·β’Έ.rs` or change the name in Cargo.toml with: [[bin]] name = "β’Άβ’·β’Έ" path = "src/main.rs" "#]]) .run(); cargo_process("new aΒΌ") .with_status(101) .with_stderr_data(str![[r#" [CREATING] binary (application) `aΒΌ` package [ERROR] invalid character `ΒΌ` in package name: `aΒΌ`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters) If you need a package name to not match the directory name, consider using --name flag. If you need a binary with the name "aΒΌ", use a valid package name, and set the binary name to be different from the package. This can be done by setting the binary filename to `src/bin/aΒΌ.rs` or change the name in Cargo.toml with: [[bin]] name = "aΒΌ" path = "src/main.rs" "#]]) .run(); } #[cargo_test] fn non_snake_case_name() { cargo_process("new UPPERcase_name") .with_stderr_data(str![[r#" [CREATING] binary (application) `UPPERcase_name` package [WARNING] the name `UPPERcase_name` is not snake_case or kebab-case which is recommended for package names, consider `uppercase_name` [NOTE] see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html "#]]) .run(); } #[cargo_test] fn kebab_case_name_is_accepted() { cargo_process("new kebab-case-is-valid") .with_stderr_data(str![[r#" [CREATING] binary (application) `kebab-case-is-valid` package [NOTE] see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html "#]]) .run(); } #[cargo_test] fn git_default_branch() { // Check for init.defaultBranch support. create_default_gitconfig(); cargo_process("new foo").run(); let repo = git2::Repository::open(paths::root().join("foo")).unwrap(); let head = repo.find_reference("HEAD").unwrap(); assert_eq!(head.symbolic_target().unwrap(), "refs/heads/master"); fs::write( paths::home().join(".gitconfig"), r#" [init] defaultBranch = hello "#, ) .unwrap(); cargo_process("new bar").run(); let repo = git2::Repository::open(paths::root().join("bar")).unwrap(); let head = repo.find_reference("HEAD").unwrap(); assert_eq!(head.symbolic_target().unwrap(), "refs/heads/hello"); } #[cargo_test] fn non_utf8_str_in_ignore_file() { let gitignore = paths::home().join(".gitignore"); File::create(gitignore).unwrap(); fs::write(paths::home().join(".gitignore"), &[0xFF, 0xFE]).unwrap(); cargo_process(&format!("init {} --vcs git", paths::home().display())) .with_status(101) .with_stderr_data(str![[r#" [CREATING] binary (application) package [ERROR] Failed to create package `home` at `[ROOT]/home` Caused by: Character at line 0 is invalid. Cargo only supports UTF-8. "#]]) .run(); } #[cfg(unix)] #[cargo_test] fn path_with_invalid_character() { cargo_process("new --name testing test:ing") .with_stderr_data(str![[r#" [CREATING] binary (application) `testing` package [WARNING] the path `[ROOT]/test:ing` contains invalid PATH characters (usually `:`, `;`, or `"`) It is recommended to use a different name to avoid problems. [NOTE] see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html "#]]) .run(); } cargo-0.86.0/tests/testsuite/offline.rs000064400000000000000000000510711046102023000162010ustar 00000000000000//! Tests for --offline flag. use std::fs; use cargo_test_support::prelude::*; use cargo_test_support::{ basic_manifest, git, main_file, project, registry::{Package, RegistryBuilder}, str, Execs, }; #[cargo_test] fn offline_unused_target_dep() { // --offline with a target dependency that is not used and not downloaded. Package::new("unused_dep", "1.0.0").publish(); Package::new("used_dep", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] used_dep = "1.0" [target.'cfg(unused)'.dependencies] unused_dep = "1.0" "#, ) .file("src/lib.rs", "") .build(); // Do a build that downloads only what is necessary. p.cargo("check") .with_stderr_data(str![[r#" ... [DOWNLOADED] used_dep v1.0.0 (registry `dummy-registry`) ... "#]]) .with_stderr_does_not_contain("[DOWNLOADED] unused_dep [..]") .run(); p.cargo("clean").run(); // Build offline, make sure it works. p.cargo("check --offline").run(); } #[cargo_test] fn offline_missing_optional() { Package::new("opt_dep", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] opt_dep = { version = "1.0", optional = true } "#, ) .file("src/lib.rs", "") .build(); // Do a build that downloads only what is necessary. p.cargo("check") .with_stderr_does_not_contain("[DOWNLOADED] opt_dep [..]") .run(); p.cargo("clean").run(); // Build offline, make sure it works. p.cargo("check --offline").run(); p.cargo("check --offline --features=opt_dep") .with_stderr_data(str![[r#" [ERROR] failed to download `opt_dep v1.0.0` Caused by: attempting to make an HTTP request, but --offline was specified "#]]) .with_status(101) .run(); } #[cargo_test] fn cargo_compile_path_with_offline() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("check --offline").run(); } #[cargo_test] fn cargo_compile_with_downloaded_dependency_with_offline() { Package::new("present_dep", "1.2.3") .file("Cargo.toml", &basic_manifest("present_dep", "1.2.3")) .file("src/lib.rs", "") .publish(); // make package downloaded let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] present_dep = "1.2.3" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); let p2 = project() .at("bar") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [dependencies] present_dep = "1.2.3" "#, ) .file("src/lib.rs", "") .build(); p2.cargo("check --offline") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] present_dep v1.2.3 [CHECKING] bar v0.1.0 ([ROOT]/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cargo_compile_offline_not_try_update() { // When --offline needs to download the registry, provide a reasonable // error hint to run without --offline. let p = project() .at("bar") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [dependencies] not_cached_dep = "1.2.5" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check --offline") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no matching package named `not_cached_dep` found location searched: crates.io index required by package `bar v0.1.0 ([ROOT]/bar)` As a reminder, you're using offline mode (--offline) which can sometimes cause surprising resolution failures, if this error is too confusing you may wish to retry without the offline flag. "#]]) .run(); // While we're here, also check the config works. p.change_file(".cargo/config.toml", "net.offline = true"); p.cargo("check").with_status(101).with_stderr_data(str![[r#" [ERROR] no matching package named `not_cached_dep` found location searched: crates.io index required by package `bar v0.1.0 ([ROOT]/bar)` As a reminder, you're using offline mode (--offline) which can sometimes cause surprising resolution failures, if this error is too confusing you may wish to retry without the offline flag. "#]]).run(); } #[cargo_test] fn compile_offline_without_maxvers_cached() { Package::new("present_dep", "1.2.1").publish(); Package::new("present_dep", "1.2.2").publish(); Package::new("present_dep", "1.2.3") .file("Cargo.toml", &basic_manifest("present_dep", "1.2.3")) .file( "src/lib.rs", r#"pub fn get_version()->&'static str {"1.2.3"}"#, ) .publish(); Package::new("present_dep", "1.2.5") .file("Cargo.toml", &basic_manifest("present_dep", "1.2.5")) .file("src/lib.rs", r#"pub fn get_version(){"1.2.5"}"#) .publish(); // make package cached let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] present_dep = "=1.2.3" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build").run(); let p2 = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] present_dep = "1.2" "#, ) .file( "src/main.rs", "\ extern crate present_dep; fn main(){ println!(\"{}\", present_dep::get_version()); }", ) .build(); p2.cargo("run --offline") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] present_dep v1.2.3 [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .with_stdout_data(str![[r#" 1.2.3 "#]]) .run(); } #[cargo_test] fn cargo_compile_forbird_git_httpsrepo_offline() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["chabapok@example.com"] [dependencies.dep1] git = 'https://github.com/some_user/dep1.git' "#, ) .file("src/main.rs", "") .build(); p.cargo("check --offline").with_status(101).with_stderr_data(str![[r#" [ERROR] failed to get `dep1` as a dependency of package `foo v0.5.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `dep1` Caused by: Unable to update https://github.com/some_user/dep1.git Caused by: can't checkout from 'https://github.com/some_user/dep1.git': you are in the offline mode (--offline) "#]]).run(); } #[cargo_test] fn compile_offline_while_transitive_dep_not_cached() { let baz = Package::new("baz", "1.0.0"); let baz_path = baz.archive_dst(); baz.publish(); let baz_content = fs::read(&baz_path).unwrap(); // Truncate the file to simulate a download failure. fs::write(&baz_path, &[]).unwrap(); Package::new("bar", "0.1.0").dep("baz", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "0.1.0" "#, ) .file("src/main.rs", "fn main(){}") .build(); // simulate download bar, but fail to download baz p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" ... Caused by: failed to verify the checksum of `baz v1.0.0 (registry `dummy-registry`)` "#]]) .run(); // Restore the file contents. fs::write(&baz_path, &baz_content).unwrap(); p.cargo("check --offline") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to download `bar v0.1.0` Caused by: attempting to make an HTTP request, but --offline was specified "#]]) .run(); } fn update_offline_not_cached() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("update --offline") .with_status(101) .with_stderr_data(str![[" [ERROR] no matching package named `bar` found location searched: [..] required by package `foo v0.0.1 ([ROOT]/foo)` As a reminder, you're using offline mode (--offline) which can sometimes cause surprising resolution failures, if this error is too confusing you may wish to retry without the offline flag. "]]) .run(); } #[cargo_test] fn update_offline_not_cached_sparse() { let _registry = RegistryBuilder::new().http_index().build(); update_offline_not_cached() } #[cargo_test] fn update_offline_not_cached_git() { update_offline_not_cached() } #[cargo_test] fn cargo_compile_offline_with_cached_git_dep() { compile_offline_with_cached_git_dep(false) } #[cargo_test] fn gitoxide_cargo_compile_offline_with_cached_git_dep_shallow_dep() { compile_offline_with_cached_git_dep(true) } fn compile_offline_with_cached_git_dep(shallow: bool) { let git_project = git::new("dep1", |project| { project .file("Cargo.toml", &basic_manifest("dep1", "0.5.0")) .file( "src/lib.rs", r#" pub static COOL_STR:&str = "cached git repo rev1"; "#, ) }); let repo = git2::Repository::open(&git_project.root()).unwrap(); let rev1 = repo.revparse_single("HEAD").unwrap().id(); // Commit the changes and make sure we trigger a recompile git_project.change_file( "src/lib.rs", r#"pub static COOL_STR:&str = "cached git repo rev2";"#, ); git::add(&repo); let rev2 = git::commit(&repo); // cache to registry rev1 and rev2 let prj = project() .at("cache_git_dep") .file( "Cargo.toml", &format!( r#" [package] name = "cache_git_dep" version = "0.5.0" edition = "2015" [dependencies.dep1] git = '{}' rev = "{}" "#, git_project.url(), rev1 ), ) .file("src/main.rs", "fn main(){}") .build(); let maybe_use_shallow = |mut cargo: Execs| -> Execs { if shallow { cargo .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-deps") .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]); } cargo }; maybe_use_shallow(prj.cargo("build")).run(); prj.change_file( "Cargo.toml", &format!( r#" [package] name = "cache_git_dep" version = "0.5.0" edition = "2015" [dependencies.dep1] git = '{}' rev = "{}" "#, git_project.url(), rev2 ), ); maybe_use_shallow(prj.cargo("build")).run(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" [dependencies.dep1] git = '{}' "#, git_project.url() ), ) .file( "src/main.rs", &main_file(r#""hello from {}", dep1::COOL_STR"#, &["dep1"]), ) .build(); let mut cargo = p.cargo("build --offline"); cargo.with_stderr_data(format!( "\ [LOCKING] 1 package to latest compatible version [COMPILING] dep1 v0.5.0 ([ROOTURL]/dep1#[..]) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s ", )); maybe_use_shallow(cargo).run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data("hello from cached git repo rev2\n") .run(); p.change_file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" [dependencies.dep1] git = '{}' rev = "{}" "#, git_project.url(), rev1 ), ); maybe_use_shallow(p.cargo("build --offline")).run(); p.process(&p.bin("foo")) .with_stdout_data("hello from cached git repo rev1\n") .run(); } #[cargo_test] fn offline_resolve_optional_fail() { // Example where resolve fails offline. // // This happens if at least 1 version of an optional dependency is // available, but none of them satisfy the requirements. The current logic // that handles this is `RegistryIndex::query_inner`, and it doesn't know // if the package being queried is an optional one. This is not ideal, it // would be best if it just ignored optional (unselected) dependencies. Package::new("dep", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] dep = { version = "1.0", optional = true } "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch").run(); // Change dep to 2.0. p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] dep = { version = "2.0", optional = true } "#, ); p.cargo("check --offline") .with_status(101) .with_stderr_data( str![[r#" [ERROR] failed to select a version for the requirement `dep = "^2.0"` candidate versions found which didn't match: 1.0.0 location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.1.0 ([ROOT]/foo)` perhaps a crate was updated and forgotten to be re-vendored? As a reminder, you're using offline mode (--offline) which can sometimes cause surprising resolution failures, if this error is too confusing you may wish to retry without the offline flag. "#]] ) .run(); } #[cargo_test] fn offline_with_all_patched() { // Offline works if everything is patched. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] dep = "1.0" [patch.crates-io] dep = {path = "dep"} "#, ) .file("src/lib.rs", "pub fn f() { dep::foo(); }") .file("dep/Cargo.toml", &basic_manifest("dep", "1.0.0")) .file("dep/src/lib.rs", "pub fn foo() {}") .build(); p.cargo("check --offline").run(); } #[cargo_test] fn update_offline_cached() { // Cache a few versions to update against let p = project().file("src/lib.rs", "").build(); let versions = ["1.2.3", "1.2.5", "1.2.9"]; for vers in versions.iter() { Package::new("present_dep", vers) .file("Cargo.toml", &basic_manifest("present_dep", vers)) .file( "src/lib.rs", format!(r#"pub fn get_version()->&'static str {{ "{}" }}"#, vers).as_str(), ) .publish(); // make package cached p.change_file( "Cargo.toml", format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] present_dep = "={}" "#, vers ) .as_str(), ); p.cargo("build").run(); } let p2 = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] present_dep = "1.2" "#, ) .file( "src/main.rs", "\ extern crate present_dep; fn main(){ println!(\"{}\", present_dep::get_version()); }", ) .build(); p2.cargo("build --offline") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] present_dep v1.2.9 [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p2.rename_run("foo", "with_1_2_9") .with_stdout_data(str![[r#" 1.2.9 "#]]) .run(); // updates happen without updating the index p2.cargo("update present_dep --precise 1.2.3 --offline") .with_status(0) .with_stderr_data(str![[r#" [DOWNGRADING] present_dep v1.2.9 -> v1.2.3 "#]]) .run(); p2.cargo("build --offline") .with_stderr_data(str![[r#" [COMPILING] present_dep v1.2.3 [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p2.rename_run("foo", "with_1_2_3") .with_stdout_data(str![[r#" 1.2.3 "#]]) .run(); // Offline update should only print package details and not index updating p2.cargo("update --offline") .with_status(0) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [UPDATING] present_dep v1.2.3 -> v1.2.9 "#]]) .run(); // No v1.2.8 loaded into the cache so expect failure. p2.cargo("update present_dep --precise 1.2.8 --offline") .with_status(101) .with_stderr_data( str![[r#" [ERROR] no matching package named `present_dep` found location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.1.0 ([ROOT]/foo)` As a reminder, you're using offline mode (--offline) which can sometimes cause surprising resolution failures, if this error is too confusing you may wish to retry without the offline flag. "#]] ) .run(); } #[cargo_test] fn offline_and_frozen_and_no_lock() { let p = project().file("src/lib.rs", "").build(); p.cargo("check --frozen --offline") .with_status(101) .with_stderr_data(str![[r#" [ERROR] the lock file [ROOT]/foo/Cargo.lock needs to be updated but --frozen was passed to prevent this If you want to try to generate the lock file without accessing the network, remove the --frozen flag and use --offline instead. "#]]) .run(); } #[cargo_test] fn offline_and_locked_and_no_frozen() { let p = project().file("src/lib.rs", "").build(); p.cargo("check --locked --offline") .with_status(101) .with_stderr_data(str![[r#" [ERROR] the lock file [ROOT]/foo/Cargo.lock needs to be updated but --locked was passed to prevent this If you want to try to generate the lock file without accessing the network, remove the --locked flag and use --offline instead. "#]]) .run(); } cargo-0.86.0/tests/testsuite/old_cargos.rs000064400000000000000000000643201046102023000166740ustar 00000000000000//! Tests for checking behavior of old cargos. //! //! These tests are ignored because it is intended to be run on a developer //! system with a bunch of toolchains installed. This requires `rustup` to be //! installed. It will iterate over installed toolchains, and run some tests //! over each one, producing a report at the end. As of this writing, I have //! tested 1.0 to 1.51. Run this with: //! //! ```console //! cargo test --test testsuite -- old_cargos --nocapture --ignored //! ``` use std::fs; use cargo::CargoResult; use cargo_test_support::prelude::*; use cargo_test_support::registry::{self, Dependency, Package}; use cargo_test_support::{cargo_exe, execs, paths, process, project, rustc_host, str}; use cargo_util::{ProcessBuilder, ProcessError}; use semver::Version; fn tc_process(cmd: &str, toolchain: &str) -> ProcessBuilder { let mut p = if toolchain == "this" { if cmd == "cargo" { process(&cargo_exe()) } else { process(cmd) } } else { let mut cmd = process(cmd); cmd.arg(format!("+{}", toolchain)); cmd }; // Reset PATH since `process` modifies it to remove rustup. p.env("PATH", std::env::var_os("PATH").unwrap()); p } /// Returns a sorted list of all toolchains. /// /// The returned value includes the parsed version, and the rustup toolchain /// name as a string. fn collect_all_toolchains() -> Vec<(Version, String)> { let rustc_version = |tc| { let mut cmd = tc_process("rustc", tc); cmd.arg("-V"); let output = cmd.exec_with_output().expect("rustc installed"); let version = std::str::from_utf8(&output.stdout).unwrap(); let parts: Vec<_> = version.split_whitespace().collect(); assert_eq!(parts[0], "rustc"); assert!(parts[1].starts_with("1.")); Version::parse(parts[1]).expect("valid version") }; // Provide a way to override the list. if let Ok(tcs) = std::env::var("OLD_CARGO") { return tcs .split(',') .map(|tc| (rustc_version(tc), tc.to_string())) .collect(); } let host = rustc_host(); // I tend to have lots of toolchains installed, but I don't want to test // all of them (like dated nightlies, or toolchains for non-host targets). let valid_names = &[ format!("stable-{}", host), format!("beta-{}", host), format!("nightly-{}", host), ]; let output = ProcessBuilder::new("rustup") .args(&["toolchain", "list"]) .exec_with_output() .expect("rustup should be installed"); let stdout = std::str::from_utf8(&output.stdout).unwrap(); let mut toolchains: Vec<_> = stdout .lines() .map(|line| { // Some lines say things like (default), just get the version. line.split_whitespace().next().expect("non-empty line") }) .filter(|line| { line.ends_with(&host) && (line.starts_with("1.") || valid_names.iter().any(|name| name == line)) }) .map(|line| (rustc_version(line), line.to_string())) .collect(); toolchains.sort_by(|a, b| a.0.cmp(&b.0)); toolchains } /// Returns whether the default toolchain is the stable version. fn default_toolchain_is_stable() -> bool { let default = tc_process("rustc", "this").arg("-V").exec_with_output(); let stable = tc_process("rustc", "stable").arg("-V").exec_with_output(); match (default, stable) { (Ok(d), Ok(s)) => d.stdout == s.stdout, _ => false, } } // This is a test for exercising the behavior of older versions of cargo with // the new feature syntax. // // The test involves a few dependencies with different feature requirements: // // * `bar` 1.0.0 is the base version that does not use the new syntax. // * `bar` 1.0.1 has a feature with the new syntax, but the feature is unused. // The optional dependency `new-baz-dep` should not be activated. // * `bar` 1.0.2 has a dependency on `baz` that *requires* the new feature // syntax. #[ignore = "must be run manually, requires old cargo installations"] #[cargo_test] fn new_features() { let registry = registry::init(); if std::process::Command::new("rustup").output().is_err() { panic!("old_cargos requires rustup to be installed"); } Package::new("new-baz-dep", "1.0.0").publish(); Package::new("baz", "1.0.0").publish(); let baz101_cksum = Package::new("baz", "1.0.1") .add_dep(Dependency::new("new-baz-dep", "1.0").optional(true)) .feature("new-feat", &["dep:new-baz-dep"]) .publish(); let bar100_cksum = Package::new("bar", "1.0.0") .add_dep(Dependency::new("baz", "1.0").optional(true)) .feature("feat", &["baz"]) .publish(); let bar101_cksum = Package::new("bar", "1.0.1") .add_dep(Dependency::new("baz", "1.0").optional(true)) .feature("feat", &["dep:baz"]) .publish(); let bar102_cksum = Package::new("bar", "1.0.2") .add_dep(Dependency::new("baz", "1.0").enable_features(&["new-feat"])) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); let lock_bar_to = |toolchain_version: &Version, bar_version| { let lock = if toolchain_version < &Version::new(1, 12, 0) { let url = registry.index_url(); match bar_version { 100 => format!( r#" [root] name = "foo" version = "0.1.0" dependencies = [ "bar 1.0.0 (registry+{url})", ] [[package]] name = "bar" version = "1.0.0" source = "registry+{url}" "#, url = url ), 101 => format!( r#" [root] name = "foo" version = "0.1.0" dependencies = [ "bar 1.0.1 (registry+{url})", ] [[package]] name = "bar" version = "1.0.1" source = "registry+{url}" "#, url = url ), 102 => format!( r#" [root] name = "foo" version = "0.1.0" dependencies = [ "bar 1.0.2 (registry+{url})", ] [[package]] name = "bar" version = "1.0.2" source = "registry+{url}" dependencies = [ "baz 1.0.1 (registry+{url})", ] [[package]] name = "baz" version = "1.0.1" source = "registry+{url}" "#, url = url ), _ => panic!("unexpected version"), } } else { match bar_version { 100 => format!( r#" [root] name = "foo" version = "0.1.0" dependencies = [ "bar 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bar" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum bar 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "{}" "#, bar100_cksum ), 101 => format!( r#" [root] name = "foo" version = "0.1.0" dependencies = [ "bar 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bar" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum bar 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "{}" "#, bar101_cksum ), 102 => format!( r#" [root] name = "foo" version = "0.1.0" dependencies = [ "bar 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bar" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "baz 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "baz" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum bar 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "{bar102_cksum}" "checksum baz 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "{baz101_cksum}" "#, bar102_cksum = bar102_cksum, baz101_cksum = baz101_cksum ), _ => panic!("unexpected version"), } }; p.change_file("Cargo.lock", &lock); }; let toolchains = collect_all_toolchains(); let config_path = paths::home().join(".cargo/config"); let lock_path = p.root().join("Cargo.lock"); struct ToolchainBehavior { bar: Option, baz: Option, new_baz_dep: Option, } // Collect errors to print at the end. One entry per toolchain, a list of // strings to print. let mut unexpected_results: Vec> = Vec::new(); for (version, toolchain) in &toolchains { if version >= &Version::new(1, 15, 0) && version < &Version::new(1, 18, 0) { // These versions do not stay within the sandbox, and chokes on // Cargo's own `Cargo.toml`. continue; } let mut tc_result = Vec::new(); // Write a config appropriate for this version. if version < &Version::new(1, 12, 0) { fs::write( &config_path, format!( r#" [registry] index = "{}" "#, registry.index_url() ), ) .unwrap(); } else { fs::write( &config_path, format!( " [source.crates-io] registry = 'https://wut' # only needed by 1.12 replace-with = 'dummy-registry' [source.dummy-registry] registry = '{}' ", registry.index_url() ), ) .unwrap(); } // Fetches the version of a package in the lock file. let pkg_version = |pkg| -> Option { let output = tc_process("cargo", toolchain) .args(&["pkgid", pkg]) .cwd(p.root()) .exec_with_output() .ok()?; let stdout = std::str::from_utf8(&output.stdout).unwrap(); let version = stdout .trim() .rsplitn(2, ['@', ':']) .next() .expect("version after colon"); Some(Version::parse(version).expect("parseable version")) }; // Runs `cargo build` and returns the versions selected in the lock. let run_cargo = || -> CargoResult { match tc_process("cargo", toolchain) .args(&["build", "--verbose"]) .cwd(p.root()) .exec_with_output() { Ok(_output) => { eprintln!("{} ok", toolchain); let bar = pkg_version("bar"); let baz = pkg_version("baz"); let new_baz_dep = pkg_version("new-baz-dep"); Ok(ToolchainBehavior { bar, baz, new_baz_dep, }) } Err(e) => { eprintln!("{} err {}", toolchain, e); Err(e) } } }; macro_rules! check_lock { ($tc_result:ident, $pkg:expr, $which:expr, $actual:expr, None) => { check_lock!(= $tc_result, $pkg, $which, $actual, None); }; ($tc_result:ident, $pkg:expr, $which:expr, $actual:expr, $expected:expr) => { check_lock!(= $tc_result, $pkg, $which, $actual, Some(Version::parse($expected).unwrap())); }; (= $tc_result:ident, $pkg:expr, $which:expr, $actual:expr, $expected:expr) => { let exp: Option = $expected; if $actual != $expected { $tc_result.push(format!( "{} for {} saw {:?} but expected {:?}", $which, $pkg, $actual, exp )); } }; } let check_err_contains = |tc_result: &mut Vec<_>, err: anyhow::Error, contents| { if let Some(ProcessError { stderr: Some(stderr), .. }) = err.downcast_ref::() { let stderr = std::str::from_utf8(stderr).unwrap(); if !stderr.contains(contents) { tc_result.push(format!( "{} expected to see error contents:\n{}\nbut saw:\n{}", toolchain, contents, stderr )); } } else { panic!("{} unexpected error {}", toolchain, err); } }; // Unlocked behavior. let which = "unlocked"; lock_path.rm_rf(); p.build_dir().rm_rf(); match run_cargo() { Ok(behavior) => { if version < &Version::new(1, 51, 0) { check_lock!(tc_result, "bar", which, behavior.bar, "1.0.2"); check_lock!(tc_result, "baz", which, behavior.baz, "1.0.1"); check_lock!(tc_result, "new-baz-dep", which, behavior.new_baz_dep, None); } else if version >= &Version::new(1, 51, 0) && version <= &Version::new(1, 59, 0) { check_lock!(tc_result, "bar", which, behavior.bar, "1.0.0"); check_lock!(tc_result, "baz", which, behavior.baz, None); check_lock!(tc_result, "new-baz-dep", which, behavior.new_baz_dep, None); } // Starting with 1.60, namespaced-features has been stabilized. else { check_lock!(tc_result, "bar", which, behavior.bar, "1.0.2"); check_lock!(tc_result, "baz", which, behavior.baz, "1.0.1"); check_lock!( tc_result, "new-baz-dep", which, behavior.new_baz_dep, "1.0.0" ); } } Err(e) => { if version < &Version::new(1, 49, 0) { // Old versions don't like the dep: syntax. check_err_contains( &mut tc_result, e, "which is neither a dependency nor another feature", ); } else if version >= &Version::new(1, 49, 0) && version < &Version::new(1, 51, 0) { check_err_contains( &mut tc_result, e, "requires the `-Z namespaced-features` flag", ); } else { tc_result.push(format!("unlocked build failed: {}", e)); } } } let which = "locked bar 1.0.0"; lock_bar_to(version, 100); match run_cargo() { Ok(behavior) => { check_lock!(tc_result, "bar", which, behavior.bar, "1.0.0"); check_lock!(tc_result, "baz", which, behavior.baz, None); check_lock!(tc_result, "new-baz-dep", which, behavior.new_baz_dep, None); } Err(e) => { tc_result.push(format!("bar 1.0.0 locked build failed: {}", e)); } } let which = "locked bar 1.0.1"; lock_bar_to(version, 101); match run_cargo() { Ok(behavior) => { check_lock!(tc_result, "bar", which, behavior.bar, "1.0.1"); check_lock!(tc_result, "baz", which, behavior.baz, None); check_lock!(tc_result, "new-baz-dep", which, behavior.new_baz_dep, None); } Err(e) => { if version < &Version::new(1, 49, 0) { // Old versions don't like the dep: syntax. check_err_contains( &mut tc_result, e, "which is neither a dependency nor another feature", ); } else if version >= &Version::new(1, 49, 0) && version < &Version::new(1, 51, 0) { check_err_contains( &mut tc_result, e, "requires the `-Z namespaced-features` flag", ); } else { // When version >= 1.51 and <= 1.59, // 1.0.1 can't be used without -Znamespaced-features // It gets filtered out of the index. check_err_contains( &mut tc_result, e, "candidate versions found which didn't match: 1.0.2, 1.0.0", ); } } } let which = "locked bar 1.0.2"; lock_bar_to(version, 102); match run_cargo() { Ok(behavior) => { if version <= &Version::new(1, 59, 0) { check_lock!(tc_result, "bar", which, behavior.bar, "1.0.2"); check_lock!(tc_result, "baz", which, behavior.baz, "1.0.1"); check_lock!(tc_result, "new-baz-dep", which, behavior.new_baz_dep, None); } // Starting with 1.60, namespaced-features has been stabilized. else { check_lock!(tc_result, "bar", which, behavior.bar, "1.0.2"); check_lock!(tc_result, "baz", which, behavior.baz, "1.0.1"); check_lock!( tc_result, "new-baz-dep", which, behavior.new_baz_dep, "1.0.0" ); } } Err(e) => { if version < &Version::new(1, 49, 0) { // Old versions don't like the dep: syntax. check_err_contains( &mut tc_result, e, "which is neither a dependency nor another feature", ); } else if version >= &Version::new(1, 49, 0) && version < &Version::new(1, 51, 0) { check_err_contains( &mut tc_result, e, "requires the `-Z namespaced-features` flag", ); } else { // When version >= 1.51 and <= 1.59, // baz can't lock to 1.0.1, it requires -Znamespaced-features check_err_contains( &mut tc_result, e, "candidate versions found which didn't match: 1.0.0", ); } } } unexpected_results.push(tc_result); } // Generate a report. let mut has_err = false; for ((tc_vers, tc_name), errs) in toolchains.iter().zip(unexpected_results) { if errs.is_empty() { continue; } eprintln!("error: toolchain {} (version {}):", tc_name, tc_vers); for err in errs { eprintln!(" {}", err); } has_err = true; } if has_err { panic!("at least one toolchain did not run as expected"); } } #[cargo_test] #[ignore = "must be run manually, requires old cargo installations"] fn index_cache_rebuild() { // Checks that the index cache gets rebuilt. // // 1.48 will not cache entries with features with the same name as a // dependency. If the cache does not get rebuilt, then running with // `-Znamespaced-features` would prevent the new cargo from seeing those // entries. The index cache version was changed to prevent this from // happening, and switching between versions should work correctly // (although it will thrash the cash, that's better than not working // correctly. let registry = registry::init(); Package::new("baz", "1.0.0").publish(); Package::new("bar", "1.0.0").publish(); Package::new("bar", "1.0.1") .add_dep(Dependency::new("baz", "1.0").optional(true)) .feature("baz", &["dep:baz"]) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .file( ".cargo/config.toml", &format!( r#" [source.crates-io] replace-with = 'dummy-registry' [source.dummy-registry] registry = '{}' "#, registry.index_url() ), ) .build(); // This version of Cargo errors on index entries that have overlapping // feature names, so 1.0.1 will be missing. execs() .with_process_builder(tc_process("cargo", "1.48.0")) .arg("check") .cwd(p.root()) .with_stderr_data(str![[r#" [UPDATING] `[ROOT]/registry` index [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `[ROOT]/registry`) [CHECKING] bar v1.0.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] dev [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); fs::remove_file(p.root().join("Cargo.lock")).unwrap(); // This should rebuild the cache and use 1.0.1. p.cargo("check") .with_stderr_data(str![[r#" [WARNING] no edition set: defaulting to the 2015 edition while the latest is [..] [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.1 (registry `dummy-registry`) [CHECKING] bar v1.0.1 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); fs::remove_file(p.root().join("Cargo.lock")).unwrap(); // Verify 1.48 can still resolve, and is at 1.0.0. execs() .with_process_builder(tc_process("cargo", "1.48.0")) .arg("tree") .cwd(p.root()) .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar v1.0.0 "#]]) .run(); } #[cargo_test] #[ignore = "must be run manually, requires old cargo installations"] fn avoids_split_debuginfo_collision() { // Test needs two different toolchains. // If the default toolchain is stable, then it won't work. if default_toolchain_is_stable() { return; } // Checks for a bug where .o files were being incorrectly shared between // different toolchains using incremental and split-debuginfo on macOS. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [profile.dev] split-debuginfo = "unpacked" "#, ) .file("src/main.rs", "fn main() {}") .build(); execs() .with_process_builder(tc_process("cargo", "stable")) .arg("build") .env("CARGO_INCREMENTAL", "1") .cwd(p.root()) .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build") .env("CARGO_INCREMENTAL", "1") .with_stderr_data(str![[r#" [WARNING] no edition set: defaulting to the 2015 edition while the latest is [..] [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); execs() .with_process_builder(tc_process("cargo", "stable")) .arg("build") .env("CARGO_INCREMENTAL", "1") .cwd(p.root()) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/open_namespaces.rs000064400000000000000000000245611046102023000177230ustar 00000000000000use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; #[cargo_test] fn within_namespace_requires_feature() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo::bar" version = "0.0.1" edition = "2015" "#, ) .file("src/lib.rs", "") .build(); p.cargo("read-manifest") .masquerade_as_nightly_cargo(&["open-namespaces"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `open-namespaces` is required The package requires the Cargo feature called `open-namespaces`, but that feature is not stabilized in this version of Cargo ([..]). Consider adding `cargo-features = ["open-namespaces"]` to the top of Cargo.toml (above the [package] table) to tell Cargo you are opting in to use this unstable feature. See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#open-namespaces for more information about the status of this feature. "#]]) .run(); } #[cargo_test] fn implicit_lib_within_namespace() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["open-namespaces"] [package] name = "foo::bar" version = "0.0.1" edition = "2015" "#, ) .file("src/lib.rs", "") .build(); p.cargo("read-manifest") .masquerade_as_nightly_cargo(&["open-namespaces"]) .with_stdout_data( str![[r#" { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#foo::bar@0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo::bar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo::bar", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } ], "version": "0.0.1" } "#]] .is_json(), ) .with_stderr_data("") .run(); } #[cargo_test] fn implicit_bin_within_namespace() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["open-namespaces"] [package] name = "foo::bar" version = "0.0.1" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("read-manifest") .masquerade_as_nightly_cargo(&["open-namespaces"]) .with_stdout_data( str![[r#" { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#foo::bar@0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo::bar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "foo::bar", "src_path": "[ROOT]/foo/src/main.rs", "test": true } ], "version": "0.0.1" } "#]] .is_json(), ) .with_stderr_data("") .run(); } #[cargo_test] fn explicit_bin_within_namespace() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["open-namespaces"] [package] name = "foo::bar" version = "0.0.1" edition = "2015" [[bin]] name = "foo-bar" "#, ) .file("src/lib.rs", "") .file("src/bin/foo-bar/main.rs", "fn main() {}") .build(); p.cargo("read-manifest") .masquerade_as_nightly_cargo(&["open-namespaces"]) .with_stdout_data( str![[r#" { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#foo::bar@0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo::bar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo::bar", "src_path": "[ROOT]/foo/src/lib.rs", "test": true }, { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2015", "kind": [ "bin" ], "name": "foo-bar", "src_path": "[ROOT]/foo/src/bin/foo-bar/main.rs", "test": true } ], "version": "0.0.1" } "#]] .is_json(), ) .with_stderr_data("") .run(); } #[cargo_test] #[cfg(unix)] fn namespaced_script_name() { let p = cargo_test_support::project() .file( "foo::bar.rs", r#"--- cargo-features = ["open-namespaces"] package.edition = "2021" --- fn main() {} "#, ) .build(); p.cargo("read-manifest -Zscript --manifest-path foo::bar.rs") .masquerade_as_nightly_cargo(&["script", "open-namespaces"]) .with_stdout_data( str![[r#" { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2021", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#foo::bar@0.0.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/foo::bar.rs", "metadata": null, "name": "foo::bar", "publish": [], "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2021", "kind": [ "bin" ], "name": "foo::bar", "src_path": "[ROOT]/home/.cargo/target/[HASH]/foo::bar.rs", "test": true } ], "version": "0.0.0" } "#]] .is_json(), ) .with_stderr_data("") .run(); } #[cargo_test] fn generate_pkgid_with_namespace() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["open-namespaces"] [package] name = "foo::bar" version = "0.0.1" edition = "2015" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile") .masquerade_as_nightly_cargo(&["open-namespaces"]) .run(); p.cargo("pkgid") .masquerade_as_nightly_cargo(&["open-namespaces"]) .with_stdout_data(str![[r#" path+[ROOTURL]/foo#foo::bar@0.0.1 "#]]) .with_stderr_data("") .run(); } #[cargo_test] fn update_spec_accepts_namespaced_name() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["open-namespaces"] [package] name = "foo::bar" version = "0.0.1" edition = "2015" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile") .masquerade_as_nightly_cargo(&["open-namespaces"]) .run(); p.cargo("update foo::bar") .masquerade_as_nightly_cargo(&["open-namespaces"]) .with_stdout_data(str![""]) .with_stderr_data(str![[r#" [LOCKING] 0 packages to latest compatible versions "#]]) .run(); } #[cargo_test] fn update_spec_accepts_namespaced_pkgid() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["open-namespaces"] [package] name = "foo::bar" version = "0.0.1" edition = "2015" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile") .masquerade_as_nightly_cargo(&["open-namespaces"]) .run(); p.cargo(&format!("update path+{}#foo::bar@0.0.1", p.url())) .masquerade_as_nightly_cargo(&["open-namespaces"]) .with_stdout_data(str![""]) .with_stderr_data(str![[r#" [LOCKING] 0 packages to latest compatible versions "#]]) .run(); } #[cargo_test] #[cfg(unix)] // until we get proper packaging support fn publish_namespaced() { use cargo_test_support::registry::RegistryBuilder; let registry = RegistryBuilder::new().http_api().http_index().build(); let p = project() .file( "Cargo.toml", r#" cargo-features = ["open-namespaces"] [package] name = "foo::bar" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/lib.rs", "fn main() {}") .build(); p.cargo("publish") .masquerade_as_nightly_cargo(&["script", "open-namespaces"]) .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo::bar v0.0.1 ([ROOT]/foo) [ERROR] failed to prepare local package for uploading Caused by: cannot publish with `open-namespaces` "#]]) .run(); } cargo-0.86.0/tests/testsuite/owner.rs000064400000000000000000000114171046102023000157110ustar 00000000000000//! Tests for the `cargo owner` command. use std::fs; use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry::{self, api_path}; use cargo_test_support::str; fn setup(name: &str, content: Option<&str>) { let dir = api_path().join(format!("api/v1/crates/{}", name)); dir.mkdir_p(); if let Some(body) = content { fs::write(dir.join("owners"), body).unwrap(); } } #[cargo_test] fn simple_list() { let registry = registry::init(); let content = r#"{ "users": [ { "id": 70, "login": "github:rust-lang:core", "name": "Core" }, { "id": 123, "login": "octocat" } ] }"#; setup("foo", Some(content)); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("owner -l") .replace_crates_io(registry.index_url()) .with_stdout_data(str![[r#" github:rust-lang:core (Core) octocat "#]]) .run(); } #[cargo_test] fn simple_add() { let registry = registry::init(); setup("foo", None); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("owner -a username") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] failed to invite owners to crate `foo` on registry at [ROOTURL]/api Caused by: EOF while parsing a value at line 1 column 0 "#]]) .run(); } #[cargo_test] fn simple_add_with_asymmetric() { let registry = registry::RegistryBuilder::new() .http_api() .token(cargo_test_support::registry::Token::rfc_key()) .build(); setup("foo", None); let p = project() .file( "Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); // The http_api server will check that the authorization is correct. // If the authorization was not sent then we would get an unauthorized error. p.cargo("owner -a username") .arg("-Zasymmetric-token") .masquerade_as_nightly_cargo(&["asymmetric-token"]) .replace_crates_io(registry.index_url()) .with_status(0) .run(); } #[cargo_test] fn simple_remove() { let registry = registry::init(); setup("foo", None); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("owner -r username") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [OWNER] removing ["username"] from crate foo [ERROR] failed to remove owners from crate `foo` on registry at [ROOTURL]/api Caused by: EOF while parsing a value at line 1 column 0 "#]]) .run(); } #[cargo_test] fn simple_remove_with_asymmetric() { let registry = registry::RegistryBuilder::new() .http_api() .token(cargo_test_support::registry::Token::rfc_key()) .build(); setup("foo", None); let p = project() .file( "Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); // The http_api server will check that the authorization is correct. // If the authorization was not sent then we would get an unauthorized error. p.cargo("owner -r username") .arg("-Zasymmetric-token") .replace_crates_io(registry.index_url()) .masquerade_as_nightly_cargo(&["asymmetric-token"]) .with_status(0) .run(); } cargo-0.86.0/tests/testsuite/package.rs000064400000000000000000006003111046102023000161470ustar 00000000000000//! Tests for the `cargo package` command. use std::fs::{self, read_to_string, File}; use std::path::Path; use cargo_test_support::prelude::*; use cargo_test_support::publish::validate_crate_contents; use cargo_test_support::registry::{self, Package}; use cargo_test_support::{ basic_manifest, cargo_process, git, paths, project, rustc_host, str, symlink_supported, t, Project, ProjectBuilder, }; use flate2::read::GzDecoder; use tar::Archive; #[cargo_test] fn simple() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] exclude = ["*.txt"] license = "MIT" description = "foo" "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .file("src/bar.txt", "") // should be ignored when packaging .build(); p.cargo("package") .with_stderr_data(str![[r#" [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.root().join("target/package/foo-0.0.1.crate").is_file()); p.cargo("package -l") .with_stdout_data(str![[r#" Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); p.cargo("package") .with_stderr_data(str![[r#" [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs", "Cargo.lock", ], (), ); } #[cargo_test] fn metadata_warning() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("package") .with_stderr_data(str![[r#" [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("package") .with_stderr_data(str![[r#" [WARNING] manifest has no description, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" repository = "bar" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("package") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn package_verbose() { let root = paths::root().join("all"); let repo = git::repo(&root) .file("Cargo.toml", &basic_manifest("foo", "0.0.1")) .file("src/main.rs", "fn main() {}") .file("a/a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/a/src/lib.rs", "") .build(); cargo_process("build").cwd(repo.root()).run(); println!("package main repo"); cargo_process("package -v --no-verify") .cwd(repo.root()) .with_stderr_data(str![[r#" [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/all) [ARCHIVING] .cargo_vcs_info.json [ARCHIVING] Cargo.lock [ARCHIVING] Cargo.toml [ARCHIVING] Cargo.toml.orig [ARCHIVING] src/main.rs [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) "#]]) .run(); let f = File::open(&repo.root().join("target/package/foo-0.0.1.crate")).unwrap(); let vcs_contents = format!( r#"{{ "git": {{ "sha1": "{}" }}, "path_in_vcs": "" }}"#, repo.revparse_head() ); validate_crate_contents( f, "foo-0.0.1.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs", ".cargo_vcs_info.json", ], [(".cargo_vcs_info.json", &vcs_contents)], ); println!("package sub-repo"); cargo_process("package -v --no-verify") .cwd(repo.root().join("a/a")) .with_stderr_data(str![[r#" [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] a v0.0.1 ([ROOT]/all/a/a) [ARCHIVING] .cargo_vcs_info.json [ARCHIVING] Cargo.lock [ARCHIVING] Cargo.toml [ARCHIVING] Cargo.toml.orig [ARCHIVING] src/lib.rs [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) "#]]) .run(); let f = File::open(&repo.root().join("a/a/target/package/a-0.0.1.crate")).unwrap(); let vcs_contents = format!( r#"{{ "git": {{ "sha1": "{}" }}, "path_in_vcs": "a/a" }}"#, repo.revparse_head() ); validate_crate_contents( f, "a-0.0.1.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/lib.rs", ".cargo_vcs_info.json", ], [(".cargo_vcs_info.json", &vcs_contents)], ); } #[cargo_test] fn package_verification() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("build").run(); p.cargo("package") .with_stderr_data(str![[r#" [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn vcs_file_collision() { let p = project().build(); let _ = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "foo" description = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" documentation = "foo" homepage = "foo" repository = "foo" exclude = ["*.no-existe"] "#, ) .file( "src/main.rs", r#" fn main() {} "#, ) .file(".cargo_vcs_info.json", "foo") .build(); p.cargo("package") .arg("--no-verify") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid inclusion of reserved file name .cargo_vcs_info.json in package source "#]]) .run(); } #[cargo_test] fn orig_file_collision() { let p = project().build(); let _ = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "foo" description = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" documentation = "foo" homepage = "foo" repository = "foo" exclude = ["*.no-existe"] "#, ) .file( "src/main.rs", r#" fn main() {} "#, ) .file("Cargo.toml.orig", "oops") .build(); p.cargo("package") .arg("--no-verify") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid inclusion of reserved file name Cargo.toml.orig in package source "#]]) .run(); } #[cargo_test] fn path_dependency_no_version() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [dependencies.bar] path = "bar" "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "") .build(); p.cargo("package") .with_status(101) .with_stderr_data(str![[r#" [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [ERROR] all dependencies must have a version specified when packaging. dependency `bar` does not specify a version Note: The packaged dependency will use the version from crates.io, the `path` specification will be removed from the dependency declaration. "#]]) .run(); } #[cargo_test] fn git_dependency_no_version() { registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [dependencies.foo] git = "git://path/to/nowhere" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("package") .with_status(101) .with_stderr_data(str![[r#" [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [ERROR] all dependencies must have a version specified when packaging. dependency `foo` does not specify a version Note: The packaged dependency will use the version from crates.io, the `git` specification will be removed from the dependency declaration. "#]]) .run(); } #[cargo_test] fn exclude() { let root = paths::root().join("exclude"); let repo = git::repo(&root) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] exclude = [ "*.txt", # file in root "file_root_1", # NO_CHANGE (ignored) "/file_root_2", # CHANGING (packaged -> ignored) "file_root_3/", # NO_CHANGE (packaged) "file_root_4/*", # NO_CHANGE (packaged) "file_root_5/**", # NO_CHANGE (packaged) # file in sub-dir "file_deep_1", # CHANGING (packaged -> ignored) "/file_deep_2", # NO_CHANGE (packaged) "file_deep_3/", # NO_CHANGE (packaged) "file_deep_4/*", # NO_CHANGE (packaged) "file_deep_5/**", # NO_CHANGE (packaged) # dir in root "dir_root_1", # CHANGING (packaged -> ignored) "/dir_root_2", # CHANGING (packaged -> ignored) "dir_root_3/", # CHANGING (packaged -> ignored) "dir_root_4/*", # NO_CHANGE (ignored) "dir_root_5/**", # NO_CHANGE (ignored) # dir in sub-dir "dir_deep_1", # CHANGING (packaged -> ignored) "/dir_deep_2", # NO_CHANGE "dir_deep_3/", # CHANGING (packaged -> ignored) "dir_deep_4/*", # CHANGING (packaged -> ignored) "dir_deep_5/**", # CHANGING (packaged -> ignored) ] "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .file("bar.txt", "") .file("src/bar.txt", "") // File in root. .file("file_root_1", "") .file("file_root_2", "") .file("file_root_3", "") .file("file_root_4", "") .file("file_root_5", "") // File in sub-dir. .file("some_dir/file_deep_1", "") .file("some_dir/file_deep_2", "") .file("some_dir/file_deep_3", "") .file("some_dir/file_deep_4", "") .file("some_dir/file_deep_5", "") // Dir in root. .file("dir_root_1/some_dir/file", "") .file("dir_root_2/some_dir/file", "") .file("dir_root_3/some_dir/file", "") .file("dir_root_4/some_dir/file", "") .file("dir_root_5/some_dir/file", "") // Dir in sub-dir. .file("some_dir/dir_deep_1/some_dir/file", "") .file("some_dir/dir_deep_2/some_dir/file", "") .file("some_dir/dir_deep_3/some_dir/file", "") .file("some_dir/dir_deep_4/some_dir/file", "") .file("some_dir/dir_deep_5/some_dir/file", "") .build(); cargo_process("package --no-verify -v") .cwd(repo.root()) .with_stdout_data("") .with_stderr_data(str![[r#" [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/exclude) [ARCHIVING] .cargo_vcs_info.json [ARCHIVING] Cargo.lock [ARCHIVING] Cargo.toml [ARCHIVING] Cargo.toml.orig [ARCHIVING] file_root_3 [ARCHIVING] file_root_4 [ARCHIVING] file_root_5 [ARCHIVING] some_dir/dir_deep_2/some_dir/file [ARCHIVING] some_dir/dir_deep_4/some_dir/file [ARCHIVING] some_dir/dir_deep_5/some_dir/file [ARCHIVING] some_dir/file_deep_2 [ARCHIVING] some_dir/file_deep_3 [ARCHIVING] some_dir/file_deep_4 [ARCHIVING] some_dir/file_deep_5 [ARCHIVING] src/main.rs [PACKAGED] 15 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) "#]]) .run(); assert!(repo.root().join("target/package/foo-0.0.1.crate").is_file()); cargo_process("package -l") .cwd(repo.root()) .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig file_root_3 file_root_4 file_root_5 some_dir/dir_deep_2/some_dir/file some_dir/dir_deep_4/some_dir/file some_dir/dir_deep_5/some_dir/file some_dir/file_deep_2 some_dir/file_deep_3 some_dir/file_deep_4 some_dir/file_deep_5 src/main.rs "#]]) .run(); } #[cargo_test] fn include() { let root = paths::root().join("include"); let repo = git::repo(&root) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] exclude = ["*.txt"] include = ["foo.txt", "**/*.rs", "Cargo.toml", ".dotfile"] "#, ) .file("foo.txt", "") .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .file(".dotfile", "") // Should be ignored when packaging. .file("src/bar.txt", "") .build(); cargo_process("package --no-verify -v") .cwd(repo.root()) .with_stderr_data(str![[r#" [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [WARNING] both package.include and package.exclude are specified; the exclude list will be ignored [PACKAGING] foo v0.0.1 ([ROOT]/include) [ARCHIVING] .cargo_vcs_info.json [ARCHIVING] .dotfile [ARCHIVING] Cargo.lock [ARCHIVING] Cargo.toml [ARCHIVING] Cargo.toml.orig [ARCHIVING] foo.txt [ARCHIVING] src/main.rs [PACKAGED] 7 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) "#]]) .run(); } #[cargo_test] fn package_lib_with_bin() { let p = project() .file("src/main.rs", "extern crate foo; fn main() {}") .file("src/lib.rs", "") .build(); p.cargo("package -v").run(); } #[cargo_test] fn package_git_submodule() { let project = git::new("foo", |project| { project .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = ["foo@example.com"] license = "MIT" description = "foo" repository = "foo" "#, ) .file("src/lib.rs", "pub fn foo() {}") }); let library = git::new("bar", |library| { library.no_manifest().file("Makefile", "all:") }); let repository = git2::Repository::open(&project.root()).unwrap(); let url = library.root().to_url().to_string(); git::add_submodule(&repository, &url, Path::new("bar")); git::commit(&repository); let repository = git2::Repository::open(&project.root().join("bar")).unwrap(); repository .reset( &repository.revparse_single("HEAD").unwrap(), git2::ResetType::Hard, None, ) .unwrap(); project .cargo("package --no-verify -v") .with_stderr_data(str![[r#" ... [ARCHIVING] bar/Makefile ... "#]]) .run(); } #[cargo_test] /// Tests if a symlink to a git submodule is properly handled. /// /// This test requires you to be able to make symlinks. /// For windows, this may require you to enable developer mode. fn package_symlink_to_submodule() { #[cfg(unix)] use std::os::unix::fs::symlink; #[cfg(windows)] use std::os::windows::fs::symlink_dir as symlink; if !symlink_supported() { return; } let project = git::new("foo", |project| { project.file("src/lib.rs", "pub fn foo() {}") }); let library = git::new("submodule", |library| { library.no_manifest().file("Makefile", "all:") }); let repository = git2::Repository::open(&project.root()).unwrap(); let url = library.root().to_url().to_string(); git::add_submodule(&repository, &url, Path::new("submodule")); t!(symlink( &project.root().join("submodule"), &project.root().join("submodule-link") )); git::add(&repository); git::commit(&repository); let repository = git2::Repository::open(&project.root().join("submodule")).unwrap(); repository .reset( &repository.revparse_single("HEAD").unwrap(), git2::ResetType::Hard, None, ) .unwrap(); project .cargo("package --no-verify -v") .with_stderr_contains("[ARCHIVING] submodule/Makefile") .with_stderr_does_not_contain("[ARCHIVING] submodule-link/.git/config") .run(); } #[cargo_test] fn no_duplicates_from_modified_tracked_files() { let p = git::new("all", |p| p.file("src/main.rs", "fn main() {}")); p.change_file("src/main.rs", r#"fn main() { println!("A change!"); }"#); p.cargo("build").run(); p.cargo("package --list --allow-dirty") .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); } #[cargo_test] fn ignore_nested() { let cargo_toml = r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" homepage = "https://example.com/" "#; let main_rs = r#" fn main() { println!("hello"); } "#; let p = project() .file("Cargo.toml", cargo_toml) .file("src/main.rs", main_rs) // If a project happens to contain a copy of itself, we should // ignore it. .file("a_dir/foo/Cargo.toml", cargo_toml) .file("a_dir/foo/src/main.rs", main_rs) .build(); p.cargo("package") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.root().join("target/package/foo-0.0.1.crate").is_file()); p.cargo("package -l") .with_stdout_data(str![[r#" Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); p.cargo("package") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], (), ); } // Windows doesn't allow these characters in filenames. #[cfg(unix)] #[cargo_test] fn package_weird_characters() { let p = project() .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .file("src/:foo", "") .build(); p.cargo("package") .with_status(101) .with_stderr_data(str![[r#" [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [ERROR] cannot package a filename with a special character `:`: src/:foo "#]]) .run(); } #[cargo_test] fn repackage_on_source_change() { let p = project() .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); p.cargo("package").run(); // Add another source file p.change_file("src/foo.rs", r#"fn main() { println!("foo"); }"#); // Check that cargo rebuilds the tarball p.cargo("package") .with_stderr_data(str![[r#" [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Check that the tarball contains the added file let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs", "src/foo.rs", ], (), ); } #[cargo_test] /// Tests if a broken symlink is properly handled when packaging. /// /// This test requires you to be able to make symlinks. /// For windows, this may require you to enable developer mode. fn broken_symlink() { #[cfg(unix)] use std::os::unix::fs::symlink; #[cfg(windows)] use std::os::windows::fs::symlink_dir as symlink; if !symlink_supported() { return; } let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = 'foo' documentation = 'foo' homepage = 'foo' repository = 'foo' "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); t!(symlink("nowhere", &p.root().join("src/foo.rs"))); p.cargo("package -v") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] failed to prepare local package for uploading Caused by: failed to open for archiving: `[ROOT]/foo/src/foo.rs` Caused by: [NOT_FOUND] "#]]) .run(); } #[cargo_test] /// Tests if a broken but excluded symlink is ignored. /// See issue rust-lang/cargo#10917 /// /// This test requires you to be able to make symlinks. /// For windows, this may require you to enable developer mode. fn broken_but_excluded_symlink() { #[cfg(unix)] use std::os::unix::fs::symlink; #[cfg(windows)] use std::os::windows::fs::symlink_dir as symlink; if !symlink_supported() { return; } let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = 'foo' documentation = 'foo' homepage = 'foo' repository = 'foo' exclude = ["src/foo.rs"] "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); t!(symlink("nowhere", &p.root().join("src/foo.rs"))); p.cargo("package -v --list") // `src/foo.rs` is excluded. .with_stdout_data(str![[r#" Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); } #[cargo_test] #[cfg(not(windows))] // https://github.com/libgit2/libgit2/issues/6250 /// Test that /dir and /dir/ matches symlinks to directories. fn gitignore_symlink_dir() { if !symlink_supported() { return; } let (p, _repo) = git::new_repo("foo", |p| { p.file("src/main.rs", r#"fn main() { println!("hello"); }"#) .symlink_dir("src", "src1") .symlink_dir("src", "src2") .symlink_dir("src", "src3") .symlink_dir("src", "src4") .file(".gitignore", "/src1\n/src2/\nsrc3\nsrc4/") }); p.cargo("package -l --no-metadata") .with_stderr_data("") .with_stdout_data(str![[r#" .cargo_vcs_info.json .gitignore Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); } #[cargo_test] #[cfg(not(windows))] // https://github.com/libgit2/libgit2/issues/6250 /// Test that /dir and /dir/ matches symlinks to directories in dirty working directory. fn gitignore_symlink_dir_dirty() { if !symlink_supported() { return; } let (p, _repo) = git::new_repo("foo", |p| { p.file("src/main.rs", r#"fn main() { println!("hello"); }"#) .file(".gitignore", "/src1\n/src2/\nsrc3\nsrc4/") }); p.symlink("src", "src1"); p.symlink("src", "src2"); p.symlink("src", "src3"); p.symlink("src", "src4"); p.cargo("package -l --no-metadata") .with_stderr_data("") .with_stdout_data(str![[r#" .cargo_vcs_info.json .gitignore Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); p.cargo("package -l --no-metadata --allow-dirty") .with_stderr_data("") .with_stdout_data(str![[r#" .cargo_vcs_info.json .gitignore Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); } #[cargo_test] /// Tests if a symlink to a directory is properly included. /// /// This test requires you to be able to make symlinks. /// For windows, this may require you to enable developer mode. fn package_symlink_to_dir() { if !symlink_supported() { return; } project() .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .file("bla/Makefile", "all:") .symlink_dir("bla", "foo") .build() .cargo("package -v") .with_stderr_data(str![[r#" ... [ARCHIVING] foo/Makefile ... "#]]) .run(); } #[cargo_test] /// Tests if a symlink to ancestor causes filesystem loop error. /// /// This test requires you to be able to make symlinks. /// For windows, this may require you to enable developer mode. fn filesystem_loop() { if !symlink_supported() { return; } project() .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .symlink_dir("a/b", "a/b/c/d/foo") .build() .cargo("package -v") .with_stderr_data(str![[r#" ... [WARNING] File system loop found: [ROOT]/foo/a/b/c/d/foo points to an ancestor [ROOT]/foo/a/b ... "#]]) .run(); } #[cargo_test] fn do_not_package_if_repository_is_dirty() { let p = project().build(); // Create a Git repository containing a minimal Rust project. let _ = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); // Modify Cargo.toml without committing the change. p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" # change "#, ); p.cargo("package") .with_status(101) .with_stderr_data(str![[r#" [ERROR] 1 files in the working directory contain changes that were not yet committed into git: Cargo.toml to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag "#]]) .run(); // cd to `src` and cargo report relative paths. p.cargo("package") .cwd(p.root().join("src")) .with_status(101) .with_stderr_data(str![[r#" [ERROR] 1 files in the working directory contain changes that were not yet committed into git: ../Cargo.toml to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag "#]]) .run(); } #[cargo_test] fn dirty_ignored() { // Cargo warns about an ignored file that will be published. let (p, repo) = git::new_repo("foo", |p| { p.file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" description = "foo" license = "foo" documentation = "foo" include = ["src", "build"] "#, ) .file("src/lib.rs", "") .file(".gitignore", "build") }); // Example of adding a file that is confusingly ignored by an overzealous // gitignore rule. p.change_file("src/build/mod.rs", ""); p.cargo("package --list") .with_status(101) .with_stderr_data(str![[r#" [ERROR] 1 files in the working directory contain changes that were not yet committed into git: src/build/mod.rs to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag "#]]) .run(); // Add the ignored file and make sure it is included. let mut index = t!(repo.index()); t!(index.add_path(Path::new("src/build/mod.rs"))); t!(index.write()); git::commit(&repo); p.cargo("package --list") .with_stderr_data("") .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig src/build/mod.rs src/lib.rs "#]]) .run(); } #[cargo_test] fn vcs_status_check_for_each_workspace_member() { // Cargo checks VCS status separately for each workspace member. // This ensure one file changed in a package won't affect the other. // Since the dirty bit in .cargo_vcs_info.json is just for advisory purpose, // We may change the meaning of it in the future. let (p, repo) = git::new_repo("foo", |p| { p.file( "Cargo.toml", r#" [workspace] members = ["isengard", "mordor"] "#, ) .file("hobbit", "...") .file( "isengard/Cargo.toml", r#" [package] name = "isengard" edition = "2015" homepage = "saruman" description = "saruman" license = "MIT" "#, ) .file("isengard/src/lib.rs", "") .file( "mordor/Cargo.toml", r#" [package] name = "mordor" edition = "2015" homepage = "sauron" description = "sauron" license = "MIT" "#, ) .file("mordor/src/lib.rs", "") }); git::commit(&repo); p.change_file( "Cargo.toml", r#" [workspace] members = ["isengard", "mordor"] [workspace.package] edition = "2021" "#, ); // Dirty file outside won't affect packaging. p.change_file("hobbit", "changed!"); p.change_file("mordor/src/lib.rs", "changed!"); p.change_file("mordor/src/main.rs", "fn main() {}"); // Ensure dirty files be reported only for one affected package. p.cargo("package --workspace --no-verify") .with_status(101) .with_stderr_data(str![[r#" [PACKAGING] isengard v0.0.0 ([ROOT]/foo/isengard) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [ERROR] 2 files in the working directory contain changes that were not yet committed into git: mordor/src/lib.rs mordor/src/main.rs to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag "#]]) .run(); // Ensure only dirty package be recorded as dirty. p.cargo("package --workspace --no-verify --allow-dirty") .with_stderr_data(str![[r#" [PACKAGING] isengard v0.0.0 ([ROOT]/foo/isengard) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] mordor v0.0.0 ([ROOT]/foo/mordor) [PACKAGED] 6 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) "#]]) .run(); let f = File::open(&p.root().join("target/package/isengard-0.0.0.crate")).unwrap(); validate_crate_contents( f, "isengard-0.0.0.crate", &[ ".cargo_vcs_info.json", "Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "Cargo.lock", ], [( ".cargo_vcs_info.json", // No change within `isengard/`, so not dirty at all. str![[r#" { "git": { "sha1": "[..]" }, "path_in_vcs": "isengard" } "#]] .is_json(), )], ); let f = File::open(&p.root().join("target/package/mordor-0.0.0.crate")).unwrap(); validate_crate_contents( f, "mordor-0.0.0.crate", &[ ".cargo_vcs_info.json", "Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "src/main.rs", "Cargo.lock", ], [( ".cargo_vcs_info.json", // Dirty bit is recorded. str![[r#" { "git": { "dirty": true, "sha1": "[..]" }, "path_in_vcs": "mordor" } "#]] .is_json(), )], ); } #[cargo_test] fn dirty_file_outside_pkg_root_considered_dirty() { if !symlink_supported() { return; } let main_outside_pkg_root = paths::root().join("main.rs"); let (p, repo) = git::new_repo("foo", |p| { p.file( "Cargo.toml", r#" [workspace] members = ["isengard"] resolver = "2" [workspace.package] edition = "2015" "#, ) .file("lib.rs", r#"compile_error!("you shall not pass")"#) .file("LICENSE", "before") .file("README.md", "before") .file( "isengard/Cargo.toml", r#" [package] name = "isengard" edition.workspace = true homepage = "saruman" description = "saruman" license-file = "../LICENSE" "#, ) .symlink("lib.rs", "isengard/src/lib.rs") .symlink("README.md", "isengard/README.md") .file(&main_outside_pkg_root, "fn main() {}") .symlink(&main_outside_pkg_root, "isengard/src/main.rs") }); git::commit(&repo); // Changing files outside pkg root under situations below should be treated // as dirty. `cargo package` is expected to fail on VCS stastus check. // // * Changes in files outside package root that source files symlink to p.change_file("README.md", "after"); p.change_file("lib.rs", "pub fn after() {}"); // * Changes in files outside pkg root that `license-file`/`readme` point to p.change_file("LICENSE", "after"); // * When workspace inheritance is involved and changed p.change_file( "Cargo.toml", r#" [workspace] members = ["isengard"] resolver = "2" [workspace.package] edition = "2021" "#, ); // Changes in files outside git workdir won't affect vcs status check p.change_file( &main_outside_pkg_root, r#"fn main() { eprintln!("after"); }"#, ); // Ensure dirty files be reported. p.cargo("package --workspace --no-verify") .with_status(101) .with_stderr_data(str![[r#" [ERROR] 2 files in the working directory contain changes that were not yet committed into git: LICENSE README.md to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag "#]]) .run(); p.cargo("package --workspace --no-verify --allow-dirty") .with_stderr_data(str![[r#" [PACKAGING] isengard v0.0.0 ([ROOT]/foo/isengard) [PACKAGED] 8 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) "#]]) .run(); let cargo_toml = str![[r##" ... [package] edition = "2021" ... "##]]; let f = File::open(&p.root().join("target/package/isengard-0.0.0.crate")).unwrap(); validate_crate_contents( f, "isengard-0.0.0.crate", &[ ".cargo_vcs_info.json", "Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "src/main.rs", "Cargo.lock", "LICENSE", "README.md", ], [ ("src/lib.rs", str!["pub fn after() {}"]), ("src/main.rs", str![r#"fn main() { eprintln!("after"); }"#]), ("README.md", str!["after"]), ("LICENSE", str!["after"]), ("Cargo.toml", cargo_toml), ], ); } #[cargo_test] fn issue_13695_allow_dirty_vcs_info() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" description = "foo" license = "foo" documentation = "foo" "#, ) .file("src/lib.rs", "") .build(); let repo = git::init(&p.root()); // Initial commit, with no files added. git::commit(&repo); // Allowing a dirty worktree results in the vcs file still being included. p.cargo("package --allow-dirty").run(); let f = File::open(&p.root().join("target/package/foo-0.1.0.crate")).unwrap(); validate_crate_contents( f, "foo-0.1.0.crate", &[ ".cargo_vcs_info.json", "Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "Cargo.lock", ], [( ".cargo_vcs_info.json", str![[r#" { "git": { "dirty": true, "sha1": "[..]" }, "path_in_vcs": "" } "#]] .is_json(), )], ); // Listing provides a consistent result. p.cargo("package --list --allow-dirty") .with_stderr_data("") .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig src/lib.rs "#]]) .run(); } #[cargo_test] fn issue_13695_allowing_dirty_vcs_info_but_clean() { let p = project().build(); let _ = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" description = "foo" license = "foo" documentation = "foo" "#, ) .file("src/lib.rs", "") .build(); // Allowing a dirty worktree despite it being clean. p.cargo("package --allow-dirty").run(); let f = File::open(&p.root().join("target/package/foo-0.1.0.crate")).unwrap(); validate_crate_contents( f, "foo-0.1.0.crate", &[ ".cargo_vcs_info.json", "Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "Cargo.lock", ], [( ".cargo_vcs_info.json", str![[r#" { "git": { "sha1": "[..]" }, "path_in_vcs": "" } "#]] .is_json(), )], ); } #[cargo_test] fn issue_14354_allowing_dirty_bare_commit() { let p = project().build(); // Init a bare commit git repo let _ = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" description = "foo" license = "foo" documentation = "foo" "#, ) .file("src/lib.rs", ""); p.cargo("package --allow-dirty").run(); let f = File::open(&p.root().join("target/package/foo-0.1.0.crate")).unwrap(); validate_crate_contents( f, "foo-0.1.0.crate", &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "Cargo.lock"], (), ); } #[cargo_test] fn generated_manifest() { registry::alt_init(); Package::new("abc", "1.0.0").publish(); Package::new("def", "1.0.0").alternative(true).publish(); Package::new("ghi", "1.0.0").publish(); Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] exclude = ["*.txt"] license = "MIT" description = "foo" [package.metadata] foo = 'bar' [workspace] [dependencies] bar = { path = "bar", version = "0.1" } def = { version = "1.0", registry = "alternative" } ghi = "1.0" abc = "1.0" "#, ) .file("src/main.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "") .build(); p.cargo("package --no-verify").run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); let rewritten_toml = str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = false exclude = ["*.txt"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" readme = false license = "MIT" [package.metadata] foo = "bar" [[bin]] name = "foo" path = "src/main.rs" [dependencies.abc] version = "1.0" [dependencies.bar] version = "0.1" [dependencies.def] version = "1.0" registry-index = "[ROOTURL]/alternative-registry" [dependencies.ghi] version = "1.0" "##]]; validate_crate_contents( f, "foo-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], [("Cargo.toml", rewritten_toml)], ); } #[cargo_test] fn ignore_workspace_specifier() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [workspace] [dependencies] bar = { path = "bar", version = "0.1" } "#, ) .file("src/main.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = ".." "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("package --no-verify").cwd("bar").run(); let f = File::open(&p.root().join("target/package/bar-0.1.0.crate")).unwrap(); let rewritten_toml = str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "bar" version = "0.1.0" authors = [] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false readme = false [lib] name = "bar" path = "src/lib.rs" "##]]; validate_crate_contents( f, "bar-0.1.0.crate", &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "Cargo.lock"], [("Cargo.toml", rewritten_toml)], ); } #[cargo_test] fn package_two_kinds_of_deps() { Package::new("other", "1.0.0").publish(); Package::new("other1", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] other = "1.0" other1 = { version = "1.0" } "#, ) .file("src/main.rs", "") .build(); p.cargo("package --no-verify").run(); } #[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")] fn package_public_dep() { Package::new("bar", "1.0.0").publish(); Package::new("baz", "1.0.0").publish(); let p = project() .file( "Cargo.toml", &format! { r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = {{ version = "1.0.0", public = true }} [target.{host}.dependencies] baz = {{ version = "1.0.0", public = true }} "#, host = rustc_host() }, ) .file("src/main.rs", "fn main() {}") .build(); let rewritten_toml = str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false readme = false [[bin]] name = "foo" path = "src/main.rs" [dependencies.bar] version = "1.0.0" [target.[HOST_TARGET].dependencies.baz] version = "1.0.0" "##]]; verify(&p, "package", rewritten_toml); let rewritten_toml = str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false readme = false [[bin]] name = "foo" path = "src/main.rs" [dependencies.bar] version = "1.0.0" public = true [target.[HOST_TARGET].dependencies.baz] version = "1.0.0" public = true "##]]; verify(&p, "package -Zpublic-dependency", rewritten_toml); fn verify(p: &cargo_test_support::Project, cmd: &str, rewritten_toml: impl IntoData) { p.cargo(cmd) .masquerade_as_nightly_cargo(&["public-dependency"]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &["Cargo.toml", "Cargo.toml.orig", "Cargo.lock", "src/main.rs"], [("Cargo.toml", rewritten_toml)], ); } } #[cargo_test] fn test_edition() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["edition"] [package] name = "foo" version = "0.0.1" authors = [] edition = "2018" "#, ) .file("src/lib.rs", r#" "#) .build(); p.cargo("check -v") .with_stderr_data(str![[r#" ... [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]--edition=2018 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn edition_with_metadata() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "2018" [package.metadata.docs.rs] features = ["foobar"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("package").run(); } #[cargo_test] fn test_edition_malformed() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "chicken" "#, ) .file("src/lib.rs", r#" "#) .build(); p.cargo("check -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: failed to parse the `edition` key Caused by: supported edition values are `2015`, `2018`, `2021`, or `2024`, but `chicken` is unknown "#]]) .run(); } #[cargo_test] fn test_edition_from_the_future() { let p = project() .file( "Cargo.toml", r#"[package] edition = "2038" name = "foo" version = "99.99.99" authors = [] "#, ) .file("src/main.rs", r#""#) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: failed to parse the `edition` key Caused by: this version of Cargo is older than the `2038` edition, and only supports `2015`, `2018`, `2021`, and `2024` editions. "#]]) .run(); } #[cargo_test] fn do_not_package_if_src_was_modified() { let p = project() .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .file("dir/foo.txt", "") .file("bar.txt", "") .file( "build.rs", r#" use std::fs; fn main() { fs::write("src/generated.txt", "Hello, world of generated files." ).expect("failed to create file"); fs::remove_file("dir/foo.txt").expect("failed to remove file"); fs::remove_dir("dir").expect("failed to remove dir"); fs::write("bar.txt", "updated content").expect("failed to update"); fs::create_dir("new-dir").expect("failed to create dir"); } "#, ) .build(); p.cargo("package") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] failed to verify package tarball Caused by: Source directory was modified by build.rs during cargo publish. Build scripts should not modify anything outside of OUT_DIR. Changed: [ROOT]/foo/target/package/foo-0.0.1/bar.txt Added: [ROOT]/foo/target/package/foo-0.0.1/new-dir [ROOT]/foo/target/package/foo-0.0.1/src/generated.txt Removed: [ROOT]/foo/target/package/foo-0.0.1/dir [ROOT]/foo/target/package/foo-0.0.1/dir/foo.txt To proceed despite this, pass the `--no-verify` flag. "#]]) .run(); p.cargo("package --no-verify").run(); } #[cargo_test] fn package_with_select_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [features] required = [] optional = [] "#, ) .file( "src/main.rs", "#[cfg(not(feature = \"required\"))] compile_error!(\"This crate requires `required` feature!\"); fn main() {}", ) .build(); p.cargo("package --features required").run(); } #[cargo_test] fn package_with_all_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [features] required = [] optional = [] "#, ) .file( "src/main.rs", "#[cfg(not(feature = \"required\"))] compile_error!(\"This crate requires `required` feature!\"); fn main() {}", ) .build(); p.cargo("package --all-features").run(); } #[cargo_test] fn package_no_default_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [features] default = ["required"] required = [] "#, ) .file( "src/main.rs", "#[cfg(not(feature = \"required\"))] compile_error!(\"This crate requires `required` feature!\"); fn main() {}", ) .build(); p.cargo("package --no-default-features") .with_stderr_data(str![[r#" ... [ERROR] This crate requires `required` feature! ... "#]]) .with_status(101) .run(); } #[cargo_test] fn include_cargo_toml_implicit() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" include = ["src/lib.rs"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("package --list") .with_stdout_data(str![[r#" Cargo.lock Cargo.toml Cargo.toml.orig src/lib.rs "#]]) .run(); } fn include_exclude_test(include: &str, exclude: &str, files: &[&str], expected: &str) { let mut pb = project().file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" include = {} exclude = {} "#, include, exclude ), ); for file in files { pb = pb.file(file, ""); } let p = pb.build(); p.cargo("package --list") .with_stderr_data("") .with_stdout_data(expected) .run(); p.root().rm_rf(); } #[cargo_test] fn package_include_ignore_only() { // Test with a gitignore pattern that fails to parse with glob. // This is a somewhat nonsense pattern, but is an example of something git // allows and glob does not. assert!(glob::Pattern::new("src/abc**").is_err()); include_exclude_test( r#"["Cargo.toml", "src/abc**", "src/lib.rs"]"#, "[]", &["src/lib.rs", "src/abc1.rs", "src/abc2.rs", "src/abc/mod.rs"], "Cargo.lock\n\ Cargo.toml\n\ Cargo.toml.orig\n\ src/abc/mod.rs\n\ src/abc1.rs\n\ src/abc2.rs\n\ src/lib.rs\n\ ", ) } #[cargo_test] fn gitignore_patterns() { include_exclude_test( r#"["Cargo.toml", "foo"]"#, // include "[]", &["src/lib.rs", "foo", "a/foo", "a/b/foo", "x/foo/y", "bar"], "Cargo.lock\n\ Cargo.toml\n\ Cargo.toml.orig\n\ a/b/foo\n\ a/foo\n\ foo\n\ x/foo/y\n\ ", ); include_exclude_test( r#"["Cargo.toml", "/foo"]"#, // include "[]", &["src/lib.rs", "foo", "a/foo", "a/b/foo", "x/foo/y", "bar"], "Cargo.lock\n\ Cargo.toml\n\ Cargo.toml.orig\n\ foo\n\ ", ); include_exclude_test( "[]", r#"["foo/"]"#, // exclude &["src/lib.rs", "foo", "a/foo", "x/foo/y", "bar"], "Cargo.lock\n\ Cargo.toml\n\ Cargo.toml.orig\n\ a/foo\n\ bar\n\ foo\n\ src/lib.rs\n\ ", ); include_exclude_test( "[]", r#"["*.txt", "[ab]", "[x-z]"]"#, // exclude &[ "src/lib.rs", "foo.txt", "bar/foo.txt", "other", "a", "b", "c", "x", "y", "z", ], "Cargo.lock\n\ Cargo.toml\n\ Cargo.toml.orig\n\ c\n\ other\n\ src/lib.rs\n\ ", ); include_exclude_test( r#"["Cargo.toml", "**/foo/bar"]"#, // include "[]", &["src/lib.rs", "a/foo/bar", "foo", "bar"], "Cargo.lock\n\ Cargo.toml\n\ Cargo.toml.orig\n\ a/foo/bar\n\ ", ); include_exclude_test( r#"["Cargo.toml", "foo/**"]"#, // include "[]", &["src/lib.rs", "a/foo/bar", "foo/x/y/z"], "Cargo.lock\n\ Cargo.toml\n\ Cargo.toml.orig\n\ foo/x/y/z\n\ ", ); include_exclude_test( r#"["Cargo.toml", "a/**/b"]"#, // include "[]", &["src/lib.rs", "a/b", "a/x/b", "a/x/y/b"], "Cargo.lock\n\ Cargo.toml\n\ Cargo.toml.orig\n\ a/b\n\ a/x/b\n\ a/x/y/b\n\ ", ); } #[cargo_test] fn gitignore_negate() { include_exclude_test( r#"["Cargo.toml", "*.rs", "!foo.rs", "\\!important"]"#, // include "[]", &["src/lib.rs", "foo.rs", "!important"], "!important\n\ Cargo.lock\n\ Cargo.toml\n\ Cargo.toml.orig\n\ src/lib.rs\n\ ", ); // NOTE: This is unusual compared to git. Git treats `src/` as a // short-circuit which means rules like `!src/foo.rs` would never run. // However, because Cargo only works by iterating over *files*, it doesn't // short-circuit. include_exclude_test( r#"["Cargo.toml", "src/", "!src/foo.rs"]"#, // include "[]", &["src/lib.rs", "src/foo.rs"], "Cargo.lock\n\ Cargo.toml\n\ Cargo.toml.orig\n\ src/lib.rs\n\ ", ); include_exclude_test( r#"["Cargo.toml", "src/*.rs", "!foo.rs"]"#, // include "[]", &["src/lib.rs", "foo.rs", "src/foo.rs", "src/bar/foo.rs"], "Cargo.lock\n\ Cargo.toml\n\ Cargo.toml.orig\n\ src/lib.rs\n\ ", ); include_exclude_test( "[]", r#"["*.rs", "!foo.rs", "\\!important"]"#, // exclude &["src/lib.rs", "foo.rs", "!important"], "Cargo.lock\n\ Cargo.toml\n\ Cargo.toml.orig\n\ foo.rs\n\ ", ); } #[cargo_test] fn exclude_dot_files_and_directories_by_default() { include_exclude_test( "[]", "[]", &["src/lib.rs", ".dotfile", ".dotdir/file"], "Cargo.lock\n\ Cargo.toml\n\ Cargo.toml.orig\n\ src/lib.rs\n\ ", ); include_exclude_test( r#"["Cargo.toml", "src/lib.rs", ".dotfile", ".dotdir/file"]"#, "[]", &["src/lib.rs", ".dotfile", ".dotdir/file"], ".dotdir/file\n\ .dotfile\n\ Cargo.lock\n\ Cargo.toml\n\ Cargo.toml.orig\n\ src/lib.rs\n\ ", ); } #[cargo_test] fn empty_readme_path() { // fail if `readme` is empty. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" readme = "" license = "MIT" description = "foo" homepage = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("package --no-verify") .with_status(101) .with_stderr_data(str![[r#" [ERROR] readme `` does not appear to exist (relative to `[ROOT]/foo`). Please update the readme setting in the manifest at `[ROOT]/foo/Cargo.toml`. "#]]) .run(); } #[cargo_test] fn invalid_readme_path() { // fail if `readme` path is invalid. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" readme = "DOES-NOT-EXIST" license = "MIT" description = "foo" homepage = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("package --no-verify") .with_status(101) .with_stderr_data(str![[r#" [ERROR] readme `DOES-NOT-EXIST` does not appear to exist (relative to `[ROOT]/foo`). Please update the readme setting in the manifest at `[ROOT]/foo/Cargo.toml`. "#]]) .run(); } #[cargo_test] fn readme_or_license_file_is_dir() { // Test error when `readme` or `license-file` is a directory, not a file. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" readme = "./src" license-file = "./src" description = "foo" homepage = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("package --no-verify") .with_status(101) .with_stderr_data(str![[r#" [ERROR] license-file `./src` does not appear to exist (relative to `[ROOT]/foo`). Please update the license-file setting in the manifest at `[ROOT]/foo/Cargo.toml`. readme `./src` does not appear to exist (relative to `[ROOT]/foo`). Please update the readme setting in the manifest at `[ROOT]/foo/Cargo.toml`. "#]]) .run(); } #[cargo_test] fn empty_license_file_path() { // fail if license-file is empty. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" license-file = "" description = "foo" homepage = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("package --no-verify") .with_status(101) .with_stderr_data(str![[r#" [WARNING] manifest has no license or license-file. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [ERROR] license-file `` does not appear to exist (relative to `[ROOT]/foo`). Please update the license-file setting in the manifest at `[ROOT]/foo/Cargo.toml`. "#]]) .run(); } #[cargo_test] fn invalid_license_file_path() { // Test warning when license-file points to a non-existent file. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" license-file = "does-not-exist" description = "foo" homepage = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("package --no-verify") .with_status(101) .with_stderr_data(str![[r#" [ERROR] license-file `does-not-exist` does not appear to exist (relative to `[ROOT]/foo`). Please update the license-file setting in the manifest at `[ROOT]/foo/Cargo.toml`. "#]]) .run(); } #[cargo_test] fn license_file_implicit_include() { // license-file should be automatically included even if not listed. let p = git::new("foo", |p| { p.file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" license-file = "subdir/LICENSE" description = "foo" homepage = "foo" include = ["src"] "#, ) .file("src/lib.rs", "") .file("subdir/LICENSE", "license text") }); p.cargo("package --list") .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig src/lib.rs subdir/LICENSE "#]]) .with_stderr_data("") .run(); p.cargo("package --no-verify -v") .with_stderr_data(str![[r#" [PACKAGING] foo v1.0.0 ([ROOT]/foo) [ARCHIVING] .cargo_vcs_info.json [ARCHIVING] Cargo.lock [ARCHIVING] Cargo.toml [ARCHIVING] Cargo.toml.orig [ARCHIVING] src/lib.rs [ARCHIVING] subdir/LICENSE [PACKAGED] 6 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-1.0.0.crate")).unwrap(); validate_crate_contents( f, "foo-1.0.0.crate", &[ ".cargo_vcs_info.json", "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "subdir/LICENSE", "src/lib.rs", ], [("subdir/LICENSE", "license text")], ); } #[cargo_test] fn relative_license_included() { // license-file path outside of package will copy into root. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" license-file = "../LICENSE" description = "foo" homepage = "foo" "#, ) .file("src/lib.rs", "") .file("../LICENSE", "license text") .build(); p.cargo("package --list") .with_stdout_data(str![[r#" Cargo.lock Cargo.toml Cargo.toml.orig LICENSE src/lib.rs "#]]) .with_stderr_data("") .run(); p.cargo("package") .with_stderr_data(str![[r#" [PACKAGING] foo v1.0.0 ([ROOT]/foo) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v1.0.0 ([ROOT]/foo) [COMPILING] foo v1.0.0 ([ROOT]/foo/target/package/foo-1.0.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-1.0.0.crate")).unwrap(); validate_crate_contents( f, "foo-1.0.0.crate", &[ "Cargo.toml", "Cargo.toml.orig", "LICENSE", "src/lib.rs", "Cargo.lock", ], [("LICENSE", "license text")], ); let manifest = std::fs::read_to_string(p.root().join("target/package/foo-1.0.0/Cargo.toml")).unwrap(); assert!(manifest.contains("license-file = \"LICENSE\"")); let orig = std::fs::read_to_string(p.root().join("target/package/foo-1.0.0/Cargo.toml.orig")).unwrap(); assert!(orig.contains("license-file = \"../LICENSE\"")); } #[cargo_test] fn relative_license_include_collision() { // Can't copy a relative license-file if there is a file with that name already. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2015" license-file = "../LICENSE" description = "foo" homepage = "foo" "#, ) .file("src/lib.rs", "") .file("../LICENSE", "outer license") .file("LICENSE", "inner license") .build(); p.cargo("package --list") .with_stdout_data(str![[r#" Cargo.lock Cargo.toml Cargo.toml.orig LICENSE src/lib.rs "#]]) .with_stderr_data(str![[r#" [WARNING] license-file `../LICENSE` appears to be a path outside of the package, but there is already a file named `LICENSE` in the root of the package. The archived crate will contain the copy in the root of the package. Update the license-file to point to the path relative to the root of the package to remove this warning. "#]]) .run(); p.cargo("package").with_stderr_data(str![[r#" [WARNING] license-file `../LICENSE` appears to be a path outside of the package, but there is already a file named `LICENSE` in the root of the package. The archived crate will contain the copy in the root of the package. Update the license-file to point to the path relative to the root of the package to remove this warning. [PACKAGING] foo v1.0.0 ([ROOT]/foo) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v1.0.0 ([ROOT]/foo) [COMPILING] foo v1.0.0 ([ROOT]/foo/target/package/foo-1.0.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); let f = File::open(&p.root().join("target/package/foo-1.0.0.crate")).unwrap(); validate_crate_contents( f, "foo-1.0.0.crate", &[ "Cargo.toml", "Cargo.toml.orig", "LICENSE", "src/lib.rs", "Cargo.lock", ], [("LICENSE", "inner license")], ); let manifest = read_to_string(p.root().join("target/package/foo-1.0.0/Cargo.toml")).unwrap(); assert!(manifest.contains("license-file = \"LICENSE\"")); let orig = read_to_string(p.root().join("target/package/foo-1.0.0/Cargo.toml.orig")).unwrap(); assert!(orig.contains("license-file = \"../LICENSE\"")); } #[cargo_test] #[cfg(not(windows))] // Don't want to create invalid files on Windows. fn package_restricted_windows() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" license = "MIT" description = "foo" homepage = "foo" "#, ) .file("src/lib.rs", "pub mod con;\npub mod aux;") .file("src/con.rs", "pub fn f() {}") .file("src/aux/mod.rs", "pub fn f() {}") .build(); p.cargo("package") // use unordered here because the order of the warning is different on each platform. .with_stderr_data( str![[r#" [WARNING] file src/con.rs is a reserved Windows filename, it will not work on Windows platforms [WARNING] file src/aux/mod.rs is a reserved Windows filename, it will not work on Windows platforms [PACKAGING] foo v0.1.0 ([ROOT]/foo) [PACKAGED] 6 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.1.0 ([ROOT]/foo) [COMPILING] foo v0.1.0 ([ROOT]/foo/target/package/foo-0.1.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn finds_git_in_parent() { // Test where `Cargo.toml` is not in the root of the git repo. let repo_path = paths::root().join("repo"); fs::create_dir(&repo_path).unwrap(); let p = project() .at("repo/foo") .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/lib.rs", "") .build(); let repo = git::init(&repo_path); git::add(&repo); git::commit(&repo); p.change_file("ignoreme", ""); p.change_file("ignoreme2", ""); p.cargo("package --list --allow-dirty") .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig ignoreme ignoreme2 src/lib.rs "#]]) .run(); p.change_file(".gitignore", "ignoreme"); p.cargo("package --list --allow-dirty") .with_stdout_data(str![[r#" .cargo_vcs_info.json .gitignore Cargo.lock Cargo.toml Cargo.toml.orig ignoreme2 src/lib.rs "#]]) .run(); fs::write(repo_path.join(".gitignore"), "ignoreme2").unwrap(); p.cargo("package --list --allow-dirty") .with_stdout_data(str![[r#" .cargo_vcs_info.json .gitignore Cargo.lock Cargo.toml Cargo.toml.orig src/lib.rs "#]]) .run(); } #[cargo_test] #[cfg(windows)] fn reserved_windows_name() { // If we are running on a version of Windows that allows these reserved filenames, // skip this test. if paths::windows_reserved_names_are_allowed() { return; } Package::new("bar", "1.0.0") .file("src/lib.rs", "pub mod aux;") .file("src/aux.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [dependencies] bar = "1.0.0" "#, ) .file("src/main.rs", "extern crate bar;\nfn main() { }") .build(); p.cargo("package") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] failed to verify package tarball Caused by: failed to download replaced source registry `crates-io` Caused by: failed to unpack package `bar v1.0.0 (registry `dummy-registry`)` Caused by: failed to unpack entry at `bar-1.0.0/src/aux.rs` Caused by: `bar-1.0.0/src/aux.rs` appears to contain a reserved Windows path, it cannot be extracted on Windows Caused by: failed to unpack `[ROOT]/home/.cargo/registry/src/-[HASH]/bar-1.0.0/src/aux.rs` Caused by: failed to unpack `bar-1.0.0/src/aux.rs` into `[ROOT]/home/.cargo/registry/src/-[HASH]/bar-1.0.0/src/aux.rs` Caused by: [NOT_FOUND] "#]]) .run(); } #[cargo_test] fn list_with_path_and_lock() { // Allow --list even for something that isn't packageable. // Init an empty registry because a versionless path dep will search for // the package on crates.io. registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" license = "MIT" description = "foo" homepage = "foo" [dependencies] bar = {path="bar"} "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "") .build(); p.cargo("package --list") .with_stdout_data(str![[r#" Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); p.cargo("package") .with_status(101) .with_stderr_data(str![[r#" [ERROR] all dependencies must have a version specified when packaging. dependency `bar` does not specify a version Note: The packaged dependency will use the version from crates.io, the `path` specification will be removed from the dependency declaration. "#]]) .run(); } #[cargo_test] fn long_file_names() { // Filenames over 100 characters require a GNU extension tarfile. // See #8453. registry::init(); let long_name = concat!( "012345678901234567890123456789012345678901234567890123456789", "012345678901234567890123456789012345678901234567890123456789", "012345678901234567890123456789012345678901234567890123456789" ); if cfg!(windows) { // Long paths on Windows require a special registry entry that is // disabled by default (even on Windows 10). // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file // If the directory where Cargo runs happens to be more than 80 characters // long, then it will bump into this limit. // // First create a directory to account for various paths Cargo will // be using in the target directory (such as "target/package/foo-0.1.0"). let test_path = paths::root().join("test-dir-probe-long-path-support"); test_path.mkdir_p(); let test_path = test_path.join(long_name); if let Err(e) = File::create(&test_path) { // write to stderr directly to avoid output from being captured // and always display text, even without --nocapture use std::io::Write; writeln!( std::io::stderr(), "\nSkipping long_file_names test, this OS or filesystem does not \ appear to support long file paths: {:?}\n{:?}", e, test_path ) .unwrap(); return; } } let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" license = "MIT" description = "foo" homepage = "foo" [dependencies] "#, ) .file(long_name, "something") .file("src/main.rs", "fn main() {}") .build(); p.cargo("package").run(); p.cargo("package --list").with_stdout_data(str![[r#" 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]).run(); } #[cargo_test] fn reproducible_output() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] exclude = ["*.txt"] license = "MIT" description = "foo" "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); p.cargo("package").run(); assert!(p.root().join("target/package/foo-0.0.1.crate").is_file()); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); let decoder = GzDecoder::new(f); let mut archive = Archive::new(decoder); for ent in archive.entries().unwrap() { let ent = ent.unwrap(); println!("checking {:?}", ent.path()); let header = ent.header(); assert_eq!(header.mode().unwrap(), 0o644); assert!(header.mtime().unwrap() != 0); assert_eq!(header.username().unwrap().unwrap(), ""); assert_eq!(header.groupname().unwrap().unwrap(), ""); } } #[cargo_test] fn package_with_resolver_and_metadata() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] resolver = '2' [package.metadata.docs.rs] all-features = true "#, ) .file("src/lib.rs", "") .build(); p.cargo("package").run(); } #[cargo_test] fn deleted_git_working_tree() { // When deleting a file, but not staged, cargo should ignore the file. let (p, repo) = git::new_repo("foo", |p| { p.file("src/lib.rs", "").file("src/main.rs", "fn main() {}") }); p.root().join("src/lib.rs").rm_rf(); p.cargo("package --allow-dirty --list") .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); p.cargo("package --allow-dirty").run(); let mut index = t!(repo.index()); t!(index.remove(Path::new("src/lib.rs"), 0)); t!(index.write()); p.cargo("package --allow-dirty --list") .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); p.cargo("package --allow-dirty").run(); } #[cargo_test] fn package_in_workspace_not_found() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "bar" "#, ) .file("bar/src/main.rs", "fn main() {}") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "baz" "#, ) .file("baz/src/main.rs", "fn main() {}") .build(); p.cargo("package -p doesnt-exist") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package ID specification `doesnt-exist` did not match any packages "#]]) .run(); } #[cargo_test] fn in_workspace() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "bar" workspace = ".." "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("package --workspace") .with_stderr_data(str![[r#" [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] bar v0.0.1 ([ROOT]/foo/bar) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] bar v0.0.1 ([ROOT]/foo/bar) [COMPILING] bar v0.0.1 ([ROOT]/foo/target/package/bar-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.root().join("target/package/foo-0.0.1.crate").is_file()); assert!(p.root().join("target/package/bar-0.0.1.crate").is_file()); } #[cargo_test] fn workspace_noconflict_readme() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] "#, ) .file("README.md", "workspace readme") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" repository = "https://github.com/bar/bar" authors = [] license = "MIT" description = "bar" readme = "../README.md" workspace = ".." "#, ) .file("bar/src/main.rs", "fn main() {}") .file("bar/example/README.md", "# example readmdBar") .build(); p.cargo("package") .with_stderr_data(str![[r#" [PACKAGING] bar v0.0.1 ([ROOT]/foo/bar) [PACKAGED] 6 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] bar v0.0.1 ([ROOT]/foo/bar) [COMPILING] bar v0.0.1 ([ROOT]/foo/target/package/bar-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn workspace_conflict_readme() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] "#, ) .file("README.md", "workspace readme") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" repository = "https://github.com/bar/bar" authors = [] license = "MIT" description = "bar" readme = "../README.md" workspace = ".." "#, ) .file("bar/src/main.rs", "fn main() {}") .file("bar/README.md", "# workspace member: Bar") .build(); p.cargo("package").with_stderr_data(str![[r#" [WARNING] readme `../README.md` appears to be a path outside of the package, but there is already a file named `README.md` in the root of the package. The archived crate will contain the copy in the root of the package. Update the readme to point to the path relative to the root of the package to remove this warning. [PACKAGING] bar v0.0.1 ([ROOT]/foo/bar) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] bar v0.0.1 ([ROOT]/foo/bar) [COMPILING] bar v0.0.1 ([ROOT]/foo/target/package/bar-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn workspace_overrides_resolver() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2021" "#, ) .file("bar/src/lib.rs", "") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.0" edition = "2015" "#, ) .file("baz/src/lib.rs", "") .build(); p.cargo("package --no-verify -p bar -p baz").run(); let f = File::open(&p.root().join("target/package/bar-0.1.0.crate")).unwrap(); let rewritten_toml = str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "bar" version = "0.1.0" build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false readme = false resolver = "1" [lib] name = "bar" path = "src/lib.rs" "##]]; validate_crate_contents( f, "bar-0.1.0.crate", &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "Cargo.lock"], [("Cargo.toml", rewritten_toml)], ); // When the crate has the same implicit resolver as the workspace it is not overridden let f = File::open(&p.root().join("target/package/baz-0.1.0.crate")).unwrap(); let rewritten_toml = str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "baz" version = "0.1.0" build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false readme = false [lib] name = "baz" path = "src/lib.rs" "##]]; validate_crate_contents( f, "baz-0.1.0.crate", &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "Cargo.lock"], [("Cargo.toml", rewritten_toml)], ); } fn verify_packaged_status_line( output: cargo_test_support::RawOutput, num_files: usize, uncompressed_size: u64, compressed_size: u64, ) { use cargo::util::human_readable_bytes; let stderr = String::from_utf8(output.stderr).unwrap(); let mut packaged_lines = stderr .lines() .filter(|line| line.trim().starts_with("Packaged")); let packaged_line = packaged_lines .next() .expect("`Packaged` status line should appear in stderr"); assert!( packaged_lines.next().is_none(), "Only one `Packaged` status line should appear in stderr" ); let size_info = packaged_line.trim().trim_start_matches("Packaged").trim(); let uncompressed = human_readable_bytes(uncompressed_size); let compressed = human_readable_bytes(compressed_size); let expected = format!( "{} files, {:.1}{} ({:.1}{} compressed)", num_files, uncompressed.0, uncompressed.1, compressed.0, compressed.1 ); assert_eq!(size_info, expected); } #[cargo_test] fn basic_filesizes() { let cargo_toml_orig_contents = r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] exclude = ["*.txt"] license = "MIT" description = "foo" homepage = "https://example.com/" "#; let main_rs_contents = r#"fn main() { println!("πŸ¦€"); }"#; let cargo_toml_contents = format!( r#"{} [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = false exclude = ["*.txt"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" homepage = "https://example.com/" readme = false license = "MIT" [[bin]] name = "foo" path = "src/main.rs" "#, cargo::core::manifest::MANIFEST_PREAMBLE ); let cargo_lock_contents = r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "foo" version = "0.0.1" "#; let p = project() .file("Cargo.toml", cargo_toml_orig_contents) .file("src/main.rs", main_rs_contents) .file("src/bar.txt", "Ignored text file contents") // should be ignored when packaging .build(); let uncompressed_size = (cargo_toml_orig_contents.len() + main_rs_contents.len() + cargo_toml_contents.len() + cargo_lock_contents.len()) as u64; let output = p.cargo("package").run(); assert!(p.root().join("target/package/foo-0.0.1.crate").is_file()); p.cargo("package -l") .with_stdout_data(str![[r#" Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); p.cargo("package") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); let compressed_size = f.metadata().unwrap().len(); verify_packaged_status_line(output, 4, uncompressed_size, compressed_size); validate_crate_contents( f, "foo-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], [ ("Cargo.lock", cargo_lock_contents), ("Cargo.toml", &cargo_toml_contents), ("Cargo.toml.orig", cargo_toml_orig_contents), ("src/main.rs", main_rs_contents), ], ); } #[cargo_test] fn larger_filesizes() { let cargo_toml_orig_contents = r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "https://example.com/" "#; let lots_of_crabs = std::iter::repeat("πŸ¦€").take(1337).collect::(); let main_rs_contents = format!(r#"fn main() {{ println!("{}"); }}"#, lots_of_crabs); let bar_txt_contents = "This file is relatively uncompressible, to increase the compressed package size beyond 1KiB. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; let cargo_toml_contents = format!( r#"{} [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "https://example.com/" readme = false license = "MIT" [[bin]] name = "foo" path = "src/main.rs" "#, cargo::core::manifest::MANIFEST_PREAMBLE ); let cargo_lock_contents = r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "foo" version = "0.0.1" "#; let p = project() .file("Cargo.toml", cargo_toml_orig_contents) .file("src/main.rs", &main_rs_contents) .file("src/bar.txt", bar_txt_contents) .build(); let uncompressed_size = (cargo_toml_orig_contents.len() + main_rs_contents.len() + cargo_toml_contents.len() + cargo_lock_contents.len() + bar_txt_contents.len()) as u64; let output = p.cargo("package").run(); assert!(p.root().join("target/package/foo-0.0.1.crate").is_file()); p.cargo("package -l") .with_stdout_data(str![[r#" Cargo.lock Cargo.toml Cargo.toml.orig src/bar.txt src/main.rs "#]]) .run(); p.cargo("package") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); let compressed_size = f.metadata().unwrap().len(); verify_packaged_status_line(output, 5, uncompressed_size, compressed_size); validate_crate_contents( f, "foo-0.0.1.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/bar.txt", "src/main.rs", ], [ ("Cargo.lock", cargo_lock_contents), ("Cargo.toml", &cargo_toml_contents), ("Cargo.toml.orig", cargo_toml_orig_contents), ("src/bar.txt", bar_txt_contents), ("src/main.rs", &main_rs_contents), ], ); } #[cargo_test] fn symlink_filesizes() { if !symlink_supported() { return; } let cargo_toml_orig_contents = r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" homepage = "https://example.com/" "#; let lots_of_crabs = std::iter::repeat("πŸ¦€").take(1337).collect::(); let main_rs_contents = format!(r#"fn main() {{ println!("{}"); }}"#, lots_of_crabs); let bar_txt_contents = "This file is relatively uncompressible, to increase the compressed package size beyond 1KiB. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; let cargo_toml_contents = format!( r#"{} [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" homepage = "https://example.com/" readme = false license = "MIT" [[bin]] name = "foo" path = "src/main.rs" "#, cargo::core::manifest::MANIFEST_PREAMBLE ); let cargo_lock_contents = r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "foo" version = "0.0.1" "#; let p = project() .file("Cargo.toml", cargo_toml_orig_contents) .file("src/main.rs", &main_rs_contents) .file("bla/bar.txt", bar_txt_contents) .symlink("src/main.rs", "src/main.rs.bak") .symlink_dir("bla", "foo") .build(); let uncompressed_size = (cargo_toml_orig_contents.len() + main_rs_contents.len() * 2 + cargo_toml_contents.len() + cargo_lock_contents.len() + bar_txt_contents.len() * 2) as u64; let output = p.cargo("package").run(); assert!(p.root().join("target/package/foo-0.0.1.crate").is_file()); p.cargo("package -l") .with_stdout_data(str![[r#" Cargo.lock Cargo.toml Cargo.toml.orig bla/bar.txt foo/bar.txt src/main.rs src/main.rs.bak "#]]) .run(); p.cargo("package") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 7 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); let compressed_size = f.metadata().unwrap().len(); verify_packaged_status_line(output, 7, uncompressed_size, compressed_size); validate_crate_contents( f, "foo-0.0.1.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "bla/bar.txt", "foo/bar.txt", "src/main.rs", "src/main.rs.bak", ], [ ("Cargo.lock", cargo_lock_contents), ("Cargo.toml", &cargo_toml_contents), ("Cargo.toml.orig", cargo_toml_orig_contents), ("bla/bar.txt", bar_txt_contents), ("foo/bar.txt", bar_txt_contents), ("src/main.rs", &main_rs_contents), ("src/main.rs.bak", &main_rs_contents), ], ); } #[cargo_test] #[cfg(windows)] // windows is the platform that is most consistently configured for case insensitive filesystems fn normalize_case() { let p = project() .file("Build.rs", r#"fn main() { println!("hello"); }"#) .file("src/Main.rs", r#"fn main() { println!("hello"); }"#) .file("src/lib.rs", "") .file("src/bar.txt", "") // should be ignored when packaging .file("Examples/ExampleFoo.rs", "") .file("Tests/ExplicitPath.rs", "") .build(); // Workaround `project()` making a `Cargo.toml` on our behalf std::fs::remove_file(p.root().join("Cargo.toml")).unwrap(); std::fs::write( p.root().join("cargo.toml"), r#" [package] name = "foo" version = "0.0.1" edition = "2018" authors = [] exclude = ["*.txt"] license = "MIT" description = "foo" [[test]] name = "explicitpath" path = "tests/explicitpath.rs" "#, ) .unwrap(); p.cargo("package").with_stderr_data(str![[r#" [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [WARNING] ignoring `package.build` as `build.rs` is not included in the published package [WARNING] ignoring binary `foo` as `src/main.rs` is not included in the published package [WARNING] ignoring example `ExampleFoo` as `examples/ExampleFoo.rs` is not included in the published package [WARNING] ignoring test `ExplicitPath` as `tests/ExplicitPath.rs` is not included in the published package [WARNING] ignoring test `explicitpath` as `tests/explicitpath.rs` is not included in the published package [PACKAGED] 8 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); assert!(p.root().join("target/package/foo-0.0.1.crate").is_file()); p.cargo("package -l") .with_stdout_data(str![[r#" Build.rs Cargo.lock Cargo.toml Cargo.toml.orig Examples/ExampleFoo.rs Tests/ExplicitPath.rs src/Main.rs src/lib.rs "#]]) .run(); p.cargo("package").with_stderr_data(str![[r#" [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [WARNING] ignoring `package.build` as `build.rs` is not included in the published package [WARNING] ignoring binary `foo` as `src/main.rs` is not included in the published package [WARNING] ignoring example `ExampleFoo` as `examples/ExampleFoo.rs` is not included in the published package [WARNING] ignoring test `ExplicitPath` as `tests/ExplicitPath.rs` is not included in the published package [WARNING] ignoring test `explicitpath` as `tests/explicitpath.rs` is not included in the published package [PACKAGED] 8 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "Build.rs", "src/Main.rs", "src/lib.rs", "Examples/ExampleFoo.rs", "Tests/ExplicitPath.rs", ], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "foo" version = "0.0.1" authors = [] build = false exclude = ["*.txt"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" readme = false license = "MIT" [lib] name = "foo" path = "src/lib.rs" "##]], )], ); } #[cargo_test] #[cfg(target_os = "linux")] // linux is generally configured to be case sensitive fn mixed_case() { let manifest = r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] exclude = ["*.txt"] license = "MIT" description = "foo" "#; let p = project() .file("Cargo.toml", manifest) .file("cargo.toml", manifest) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .file("src/bar.txt", "") // should be ignored when packaging .build(); p.cargo("package") .with_stderr_data(str![[r#" [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.root().join("target/package/foo-0.0.1.crate").is_file()); p.cargo("package -l") .with_stdout_data(str![[r#" Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); p.cargo("package") .with_stderr_data(str![[r#" [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], (), ); } #[cargo_test] fn versionless_package() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" description = "foo" edition = "2015" "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); p.cargo("package") .with_stderr_data(str![[r#" [WARNING] manifest has no license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.0 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.0 ([ROOT]/foo) [COMPILING] foo v0.0.0 ([ROOT]/foo/target/package/foo-0.0.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.0.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.0.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], (), ); } #[cargo_test] fn include_files_called_target_project() { // https://github.com/rust-lang/cargo/issues/12790 // files and folders called "target" should be included, unless they're the actual target directory let p = init_and_add_inner_target(project()) .file("target/foo.txt", "") .build(); p.cargo("package -l") .with_stdout_data(str![[r#" Cargo.lock Cargo.toml Cargo.toml.orig data/not_target data/target derp/not_target/foo.txt derp/target/foo.txt src/main.rs "#]]) .run(); } #[cargo_test] fn include_files_called_target_git() { // https://github.com/rust-lang/cargo/issues/12790 // files and folders called "target" should be included, unless they're the actual target directory let (p, repo) = git::new_repo("foo", |p| init_and_add_inner_target(p)); // add target folder but not committed. _ = fs::create_dir(p.build_dir()).unwrap(); _ = fs::write(p.build_dir().join("foo.txt"), "").unwrap(); p.cargo("package -l") .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig data/not_target data/target derp/not_target/foo.txt derp/target/foo.txt src/main.rs "#]]) .run(); // if target is committed, it should be included. git::add(&repo); git::commit(&repo); p.cargo("package -l") .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig data/not_target data/target derp/not_target/foo.txt derp/target/foo.txt src/main.rs target/foo.txt "#]]) .run(); // Untracked files shouldn't be included, if they are also ignored. _ = fs::write(repo.workdir().unwrap().join(".gitignore"), "target/").unwrap(); git::add(&repo); git::commit(&repo); _ = fs::write(p.build_dir().join("untracked.txt"), "").unwrap(); p.cargo("package -l") .with_stdout_data(str![[r#" .cargo_vcs_info.json .gitignore Cargo.lock Cargo.toml Cargo.toml.orig data/not_target data/target derp/not_target/foo.txt derp/target/foo.txt src/main.rs target/foo.txt "#]]) .run(); } fn init_and_add_inner_target(p: ProjectBuilder) -> ProjectBuilder { p.file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) // file called target, should be included .file("data/target", "") .file("data/not_target", "") // folder called target, should be included .file("derp/target/foo.txt", "") .file("derp/not_target/foo.txt", "") } #[cargo_test] fn build_script_outside_pkg_root() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" authors = [] build = "../t_custom_build/custom_build.rs" "#, ) .file("src/main.rs", "fn main() {}") .build(); // custom_build.rs does not exist p.cargo("package -l") .with_status(101) .with_stderr_data(str![[r#" [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [ERROR] the source file of build script doesn't appear to exist. This may cause issue during packaging, as modules resolution and resources included via macros are often relative to the path of source files. Please update the `build` setting in the manifest at `[ROOT]/foo/Cargo.toml` and point to a path inside the root of the package. "#]]) .run(); // custom_build.rs outside the package root let custom_build_root = paths::root().join("t_custom_build"); _ = fs::create_dir(&custom_build_root).unwrap(); _ = fs::write(&custom_build_root.join("custom_build.rs"), "fn main() {}"); p.cargo("package -l") .with_status(101) .with_stderr_data(str![[r#" [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [ERROR] the source file of build script doesn't appear to be a path inside of the package. It is at `[ROOT]/t_custom_build/custom_build.rs`, whereas the root the package is `[ROOT]/foo`. This may cause issue during packaging, as modules resolution and resources included via macros are often relative to the path of source files. Please update the `build` setting in the manifest at `[ROOT]/foo/Cargo.toml` and point to a path inside the root of the package. "#]]) .run(); } #[cargo_test] fn symlink_manifest_path() { // Test `cargo install --manifest-path` pointing through a symlink. if !symlink_supported() { return; } let p = git::new("foo", |p| { p.file("Cargo.toml", &basic_manifest("foo", "1.0.0")) .file("src/main.rs", "fn main() {}") // Triggers discover_git_and_list_files for detecting changed files. .file("build.rs", "fn main() {}") }); #[cfg(unix)] use std::os::unix::fs::symlink; #[cfg(windows)] use std::os::windows::fs::symlink_dir as symlink; let foo_symlink = paths::root().join("foo-symlink"); t!(symlink(p.root(), &foo_symlink)); cargo_process("package --no-verify --manifest-path") .arg(foo_symlink.join("Cargo.toml")) .with_stderr_data(str![[r#" [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v1.0.0 ([ROOT]/foo-symlink) [PACKAGED] 6 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) "#]]) .run(); } #[cargo_test] #[cfg(windows)] fn normalize_paths() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" description = "foo" documentation = "docs.rs/foo" authors = [] readme = ".\\docs\\README.md" license-file = ".\\docs\\LICENSE" build = ".\\src\\build.rs" [lib] path = ".\\src\\lib.rs" [[bin]] name = "foo" path = ".\\src\\bin\\foo\\main.rs" [[example]] name = "example_foo" path = ".\\examples\\example_foo.rs" [[test]] name = "test_foo" path = ".\\tests\\test_foo.rs" [[bench]] name = "bench_foo" path = ".\\benches\\bench_foo.rs" "#, ) .file("src/lib.rs", "") .file("docs/README.md", "") .file("docs/LICENSE", "") .file("src/build.rs", "fn main() {}") .file("src/bin/foo/main.rs", "fn main() {}") .file("examples/example_foo.rs", "fn main() {}") .file("tests/test_foo.rs", "fn main() {}") .file("benches/bench_foo.rs", "fn main() {}") .build(); p.cargo("package") .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 11 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "docs/README.md", "docs/LICENSE", "src/build.rs", "src/bin/foo/main.rs", "examples/example_foo.rs", "tests/test_foo.rs", "benches/bench_foo.rs", ], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = "src/build.rs" autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = "docs/README.md" license-file = "docs/LICENSE" [lib] name = "foo" path = "src/lib.rs" [[bin]] name = "foo" path = "src/bin/foo/main.rs" [[example]] name = "example_foo" path = "examples/example_foo.rs" [[test]] name = "test_foo" path = "tests/test_foo.rs" [[bench]] name = "bench_foo" path = "benches/bench_foo.rs" "##]], )], ); } #[cargo_test] fn discovery_inferred_build_rs_included() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/lib.rs", "build.rs"] "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); p.cargo("package") .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &[ "Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "build.rs", "Cargo.lock", ], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = "build.rs" include = [ "src/lib.rs", "build.rs", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "foo" path = "src/lib.rs" "##]], )], ); } #[cargo_test] fn discovery_inferred_build_rs_excluded() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/lib.rs"] "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); p.cargo("package") .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [WARNING] ignoring `package.build` as `build.rs` is not included in the published package [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "Cargo.lock"], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = false include = ["src/lib.rs"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "foo" path = "src/lib.rs" "##]], )], ); } #[cargo_test] fn discovery_explicit_build_rs_included() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/lib.rs", "build.rs"] build = "build.rs" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); p.cargo("package") .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &[ "Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "build.rs", "Cargo.lock", ], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = "build.rs" include = [ "src/lib.rs", "build.rs", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "foo" path = "src/lib.rs" "##]], )], ); } #[cargo_test] fn discovery_explicit_build_rs_excluded() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/lib.rs"] build = "build.rs" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); p.cargo("package") .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [WARNING] ignoring `package.build` as `build.rs` is not included in the published package [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "Cargo.lock"], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = false include = ["src/lib.rs"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "foo" path = "src/lib.rs" "##]], )], ); } #[cargo_test] fn discovery_inferred_lib_included() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/main.rs", "src/lib.rs"] "#, ) .file("src/main.rs", "fn main() {}") .file("src/lib.rs", "") .build(); p.cargo("package") .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs", "src/lib.rs", ], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = false include = [ "src/main.rs", "src/lib.rs", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "foo" path = "src/lib.rs" [[bin]] name = "foo" path = "src/main.rs" "##]], )], ); } #[cargo_test] fn discovery_inferred_lib_excluded() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/main.rs"] "#, ) .file("src/main.rs", "fn main() {}") .file("src/lib.rs", "") .build(); p.cargo("package") .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [WARNING] ignoring library `foo` as `src/lib.rs` is not included in the published package [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = false include = ["src/main.rs"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [[bin]] name = "foo" path = "src/main.rs" "##]], )], ); } #[cargo_test] fn discovery_explicit_lib_included() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/main.rs", "src/lib.rs"] [lib] path = "src/lib.rs" "#, ) .file("src/main.rs", "fn main() {}") .file("src/lib.rs", "") .build(); p.cargo("package") .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs", "src/lib.rs", ], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = false include = [ "src/main.rs", "src/lib.rs", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "foo" path = "src/lib.rs" [[bin]] name = "foo" path = "src/main.rs" "##]], )], ); } #[cargo_test] fn discovery_explicit_lib_excluded() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/main.rs"] [lib] path = "src/lib.rs" "#, ) .file("src/main.rs", "fn main() {}") .file("src/lib.rs", "") .build(); p.cargo("package") .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [WARNING] ignoring library `foo` as `src/lib.rs` is not included in the published package [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = false include = ["src/main.rs"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [[bin]] name = "foo" path = "src/main.rs" "##]], )], ); } #[cargo_test] fn discovery_inferred_other_included() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/lib.rs", "src/bin/foo/main.rs", "examples/example_foo.rs", "tests/test_foo.rs", "benches/bench_foo.rs"] "#, ) .file("src/lib.rs", "") .file("src/bin/foo/main.rs", "fn main() {}") .file("examples/example_foo.rs", "fn main() {}") .file("tests/test_foo.rs", "fn main() {}") .file("benches/bench_foo.rs", "fn main() {}") .build(); p.cargo("package") .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 8 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "src/bin/foo/main.rs", "examples/example_foo.rs", "tests/test_foo.rs", "benches/bench_foo.rs", ], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = false include = [ "src/lib.rs", "src/bin/foo/main.rs", "examples/example_foo.rs", "tests/test_foo.rs", "benches/bench_foo.rs", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "foo" path = "src/lib.rs" [[bin]] name = "foo" path = "src/bin/foo/main.rs" [[example]] name = "example_foo" path = "examples/example_foo.rs" [[test]] name = "test_foo" path = "tests/test_foo.rs" [[bench]] name = "bench_foo" path = "benches/bench_foo.rs" "##]], )], ); } #[cargo_test] fn discovery_inferred_other_excluded() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/lib.rs"] "#, ) .file("src/lib.rs", "") .file("src/bin/foo/main.rs", "fn main() {}") .file("examples/example_foo.rs", "fn main() {}") .file("tests/test_foo.rs", "fn main() {}") .file("benches/bench_foo.rs", "fn main() {}") .build(); p.cargo("package") .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [WARNING] ignoring binary `foo` as `src/bin/foo/main.rs` is not included in the published package [WARNING] ignoring example `example_foo` as `examples/example_foo.rs` is not included in the published package [WARNING] ignoring test `test_foo` as `tests/test_foo.rs` is not included in the published package [WARNING] ignoring benchmark `bench_foo` as `benches/bench_foo.rs` is not included in the published package [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/lib.rs"], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = false include = ["src/lib.rs"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "foo" path = "src/lib.rs" "##]], )], ); } #[cargo_test] fn discovery_explicit_other_included() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/lib.rs", "src/bin/foo/main.rs", "examples/example_foo.rs", "tests/test_foo.rs", "benches/bench_foo.rs"] [[bin]] name = "foo" [[example]] name = "example_foo" [[test]] name = "test_foo" [[bench]] name = "bench_foo" "#, ) .file("src/lib.rs", "") .file("src/bin/foo/main.rs", "fn main() {}") .file("examples/example_foo.rs", "fn main() {}") .file("tests/test_foo.rs", "fn main() {}") .file("benches/bench_foo.rs", "fn main() {}") .build(); p.cargo("package") .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 8 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "src/bin/foo/main.rs", "examples/example_foo.rs", "tests/test_foo.rs", "benches/bench_foo.rs", ], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = false include = [ "src/lib.rs", "src/bin/foo/main.rs", "examples/example_foo.rs", "tests/test_foo.rs", "benches/bench_foo.rs", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "foo" path = "src/lib.rs" [[bin]] name = "foo" path = "src/bin/foo/main.rs" [[example]] name = "example_foo" path = "examples/example_foo.rs" [[test]] name = "test_foo" path = "tests/test_foo.rs" [[bench]] name = "bench_foo" path = "benches/bench_foo.rs" "##]], )], ); } #[cargo_test] fn discovery_explicit_other_excluded() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/lib.rs"] [[main]] name = "foo" [[example]] name = "example_foo" [[test]] name = "test_foo" [[bench]] name = "bench_foo" "#, ) .file("src/lib.rs", "") .file("src/bin/foo/main.rs", "fn main() {}") .file("examples/example_foo.rs", "fn main() {}") .file("tests/test_foo.rs", "fn main() {}") .file("benches/bench_foo.rs", "fn main() {}") .build(); p.cargo("package") .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [WARNING] ignoring binary `foo` as `src/bin/foo/main.rs` is not included in the published package [WARNING] ignoring example `example_foo` as `examples/example_foo.rs` is not included in the published package [WARNING] ignoring test `test_foo` as `tests/test_foo.rs` is not included in the published package [WARNING] ignoring benchmark `bench_foo` as `benches/bench_foo.rs` is not included in the published package [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/lib.rs"], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.0.1" authors = [] build = false include = ["src/lib.rs"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "foo" path = "src/lib.rs" "##]], )], ); } #[cargo_test] fn deterministic_build_targets() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2021" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] [[example]] name = "c" [[example]] name = "b" [[example]] name = "a" "#, ) .file("src/lib.rs", "") .file("examples/z.rs", "fn main() {}") .file("examples/y.rs", "fn main() {}") .file("examples/x.rs", "fn main() {}") .file("examples/c.rs", "fn main() {}") .file("examples/b.rs", "fn main() {}") .file("examples/a.rs", "fn main() {}") .build(); p.cargo("package") .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 10 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "examples/a.rs", "examples/b.rs", "examples/c.rs", "examples/x.rs", "examples/y.rs", "examples/z.rs", ], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "foo" version = "0.0.1" authors = [] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "foo" path = "src/lib.rs" [[example]] name = "a" path = "examples/a.rs" [[example]] name = "b" path = "examples/b.rs" [[example]] name = "c" path = "examples/c.rs" [[example]] name = "x" path = "examples/x.rs" [[example]] name = "y" path = "examples/y.rs" [[example]] name = "z" path = "examples/z.rs" "##]], )], ); } // A workspace with three projects that depend on one another (level1 -> level2 -> level3). // level1 is a binary package, to test lockfile generation. fn workspace_with_local_deps_project() -> Project { project() .file( "Cargo.toml", r#" [workspace] members = ["level1", "level2", "level3"] [workspace.dependencies] level2 = { path = "level2", version = "0.0.1" } "# ) .file( "level1/Cargo.toml", r#" [package] name = "level1" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level1" repository = "bar" [dependencies] # Let one dependency also specify features, for the added test coverage when generating package files. level2 = { workspace = true, features = ["foo"] } "#, ) .file("level1/src/main.rs", "fn main() {}") .file( "level2/Cargo.toml", r#" [package] name = "level2" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level2" repository = "bar" [features] foo = [] [dependencies] level3 = { path = "../level3", version = "0.0.1" } "# ) .file("level2/src/lib.rs", "") .file( "level3/Cargo.toml", r#" [package] name = "level3" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level3" repository = "bar" "#, ) .file("level3/src/lib.rs", "") .build() } #[cargo_test] fn workspace_with_local_deps() { let crates_io = registry::init(); let p = workspace_with_local_deps_project(); p.cargo("package") .replace_crates_io(crates_io.index_url()) .with_status(101) .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] level3 v0.0.1 ([ROOT]/foo/level3) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] level2 v0.0.1 ([ROOT]/foo/level2) [UPDATING] crates.io index [ERROR] failed to prepare local package for uploading Caused by: no matching package named `level3` found location searched: crates.io index required by package `level2 v0.0.1 ([ROOT]/foo/level2)` "#]]) .run(); } #[cargo_test] fn workspace_with_local_deps_nightly() { let crates_io = registry::init(); let p = workspace_with_local_deps_project(); p.cargo("package -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .replace_crates_io(crates_io.index_url()) .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] level3 v0.0.1 ([ROOT]/foo/level3) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] level2 v0.0.1 ([ROOT]/foo/level2) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] level1 v0.0.1 ([ROOT]/foo/level1) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] level3 v0.0.1 ([ROOT]/foo/level3) [COMPILING] level3 v0.0.1 ([ROOT]/foo/target/package/level3-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] level2 v0.0.1 ([ROOT]/foo/level2) [UNPACKING] level3 v0.0.1 (registry `[ROOT]/foo/target/package/tmp-registry`) [COMPILING] level3 v0.0.1 [COMPILING] level2 v0.0.1 ([ROOT]/foo/target/package/level2-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] level1 v0.0.1 ([ROOT]/foo/level1) [UNPACKING] level2 v0.0.1 (registry `[ROOT]/foo/target/package/tmp-registry`) [COMPILING] level3 v0.0.1 [COMPILING] level2 v0.0.1 [COMPILING] level1 v0.0.1 ([ROOT]/foo/target/package/level1-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let generated_lock = str![[r##" # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "level1" version = "0.0.1" dependencies = [ "level2", ] [[package]] name = "level2" version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "[..]" dependencies = [ "level3", ] [[package]] name = "level3" version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "[..]" "##]]; let generated_manifest = str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "level1" version = "0.0.1" authors = [] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "level1" readme = false license = "MIT" repository = "bar" [[bin]] name = "level1" path = "src/main.rs" [dependencies.level2] version = "0.0.1" features = ["foo"] "##]]; let mut f = File::open(&p.root().join("target/package/level1-0.0.1.crate")).unwrap(); validate_crate_contents( &mut f, "level1-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], [ ("Cargo.lock", generated_lock), ("Cargo.toml", generated_manifest), ], ); } fn workspace_with_local_deps_packaging_one_fails_project() -> Project { project() .file( "Cargo.toml", r#" [workspace] members = ["level1", "level2"] "#, ) .file( "level1/Cargo.toml", r#" [package] name = "level1" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level1" repository = "bar" [dependencies] level2 = { path = "../level2", version = "0.0.1" } "#, ) .file("level1/src/lib.rs", "") .file( "level2/Cargo.toml", r#" [package] name = "level2" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level2" repository = "bar" "#, ) .file("level2/src/lib.rs", "") .build() } #[cargo_test] fn workspace_with_local_deps_packaging_one_fails() { let crates_io = registry::init(); let p = workspace_with_local_deps_packaging_one_fails_project(); // We can't package just level1, because there's a dependency on level2. p.cargo("package -p level1") .replace_crates_io(crates_io.index_url()) .with_status(101) .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] level1 v0.0.1 ([ROOT]/foo/level1) [UPDATING] crates.io index [ERROR] failed to prepare local package for uploading Caused by: no matching package named `level2` found location searched: crates.io index required by package `level1 v0.0.1 ([ROOT]/foo/level1)` "#]]) .run(); } #[cargo_test] fn workspace_with_local_deps_packaging_one_fails_nightly() { let crates_io = registry::init(); let p = workspace_with_local_deps_packaging_one_fails_project(); // We can't package just level1, because there's a dependency on level2. p.cargo("package -p level1 -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .replace_crates_io(crates_io.index_url()) .with_status(101) .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] level1 v0.0.1 ([ROOT]/foo/level1) [UPDATING] crates.io index [ERROR] failed to prepare local package for uploading Caused by: no matching package named `level2` found location searched: crates.io index required by package `level1 v0.0.1 ([ROOT]/foo/level1)` "#]]) .run(); } // Same as workspace_with_local_deps_packaging_one_fails except that we're // packaging a bin. This fails during lock-file generation instead of during verification. #[cargo_test] fn workspace_with_local_deps_packaging_one_bin_fails() { let crates_io = registry::init(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["level1", "level2"] "#, ) .file( "level1/Cargo.toml", r#" [package] name = "level1" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level1" repository = "bar" [dependencies] level2 = { path = "../level2", version = "0.0.1" } "#, ) .file("level1/src/main.rs", "fn main() {}") .file( "level2/Cargo.toml", r#" [package] name = "level2" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level2" repository = "bar" "#, ) .file("level2/src/lib.rs", "") .build(); // We can't package just level1, because there's a dependency on level2. p.cargo("package -p level1 -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .replace_crates_io(crates_io.index_url()) .with_status(101) .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] level1 v0.0.1 ([ROOT]/foo/level1) [UPDATING] crates.io index [ERROR] failed to prepare local package for uploading Caused by: no matching package named `level2` found location searched: crates.io index required by package `level1 v0.0.1 ([ROOT]/foo/level1)` "#]]) .run(); } // Here we don't package the whole workspace, but it succeeds because we package a // dependency-closed subset. #[cargo_test] fn workspace_with_local_deps_packaging_one_with_needed_deps() { let crates_io = registry::init(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["level1", "level2", "level3"] "#, ) .file( "level1/Cargo.toml", r#" [package] name = "level1" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level1" repository = "bar" [dependencies] level2 = { path = "../level2", version = "0.0.1" } "#, ) .file("level1/src/main.rs", "fn main() {}") .file( "level2/Cargo.toml", r#" [package] name = "level2" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level2" repository = "bar" [dependencies] level3 = { path = "../level3", version = "0.0.1" } "#, ) .file("level2/src/lib.rs", "") .file( "level3/Cargo.toml", r#" [package] name = "level3" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level3" repository = "bar" "#, ) .file("level3/src/lib.rs", "") .build(); p.cargo("package -p level2 -p level3 -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .replace_crates_io(crates_io.index_url()) .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] level3 v0.0.1 ([ROOT]/foo/level3) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] level2 v0.0.1 ([ROOT]/foo/level2) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] level3 v0.0.1 ([ROOT]/foo/level3) [COMPILING] level3 v0.0.1 ([ROOT]/foo/target/package/level3-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] level2 v0.0.1 ([ROOT]/foo/level2) [UNPACKING] level3 v0.0.1 (registry `[ROOT]/foo/target/package/tmp-registry`) [COMPILING] level3 v0.0.1 [COMPILING] level2 v0.0.1 ([ROOT]/foo/target/package/level2-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } // package --list in a workspace lists all the files in all the packages. // The output is not very good, though. See https://github.com/rust-lang/cargo/issues/13953 #[cargo_test] fn workspace_with_local_deps_list() { let crates_io = registry::init(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["level1", "level2"] "#, ) .file( "level1/Cargo.toml", r#" [package] name = "level1" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level1" repository = "bar" [dependencies] level2 = { path = "../level2", version = "0.0.1" } "#, ) .file("level1/src/main.rs", "fn main() {}") .file( "level2/Cargo.toml", r#" [package] name = "level2" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level2" repository = "bar" "#, ) .file("level2/src/lib.rs", "") .build(); p.cargo("package --list") .replace_crates_io(crates_io.index_url()) .with_stdout_data(str![[r#" Cargo.lock Cargo.toml Cargo.toml.orig src/lib.rs Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .with_stderr_data("") .run(); } #[cargo_test] fn workspace_with_local_deps_index_mismatch() { let alt_reg = registry::RegistryBuilder::new() .http_api() .http_index() .alternative() .build(); // We're publishing to an alternate index, but the manifests don't specify it. // The intra-workspace deps won't be found. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["level1", "level2"] "#, ) .file( "level1/Cargo.toml", r#" [package] name = "level1" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level1" repository = "bar" [dependencies] level2 = { path = "../level2", version = "0.0.1" } "#, ) .file("level1/src/main.rs", "fn main() {}") .file( "level2/Cargo.toml", r#" [package] name = "level2" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level2" repository = "bar" "#, ) .file("level2/src/lib.rs", "") .build(); p.cargo(&format!( "package --index {} -Zpackage-workspace", alt_reg.index_url() )) .masquerade_as_nightly_cargo(&["package-workspace"]) .with_status(101) .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] level2 v0.0.1 ([ROOT]/foo/level2) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] level1 v0.0.1 ([ROOT]/foo/level1) [UPDATING] crates.io index [ERROR] failed to prepare local package for uploading Caused by: no matching package named `level2` found location searched: crates.io index required by package `level1 v0.0.1 ([ROOT]/foo/level1)` "#]]) .run(); } #[cargo_test] fn workspace_with_local_deps_alternative_index() { let alt_reg = registry::RegistryBuilder::new() .http_api() .http_index() .alternative() .build(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["level1", "level2"] "#, ) .file( "level1/Cargo.toml", r#" [package] name = "level1" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level1" repository = "bar" [dependencies] level2 = { path = "../level2", version = "0.0.1", registry = "alternative" } "#, ) .file("level1/src/main.rs", "fn main() {}") .file( "level2/Cargo.toml", r#" [package] name = "level2" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level2" repository = "bar" "#, ) .file("level2/src/lib.rs", "") .build(); p.cargo(&format!( "package --index {} -Zpackage-workspace", alt_reg.index_url() )) .masquerade_as_nightly_cargo(&["package-workspace"]) .with_stdout_data("") .with_stderr_data(str![[r#" [PACKAGING] level2 v0.0.1 ([ROOT]/foo/level2) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] level1 v0.0.1 ([ROOT]/foo/level1) [UPDATING] `alternative` index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] level2 v0.0.1 ([ROOT]/foo/level2) [COMPILING] level2 v0.0.1 ([ROOT]/foo/target/package/level2-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] level1 v0.0.1 ([ROOT]/foo/level1) [UPDATING] `alternative` index [UNPACKING] level2 v0.0.1 (registry `[ROOT]/foo/target/package/tmp-registry`) [COMPILING] level2 v0.0.1 (registry `alternative`) [COMPILING] level1 v0.0.1 ([ROOT]/foo/target/package/level1-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let index = alt_reg.index_url(); let generated_lock = format!( r#"# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "level1" version = "0.0.1" dependencies = [ "level2", ] [[package]] name = "level2" version = "0.0.1" source = "{index}" checksum = "[..]" "# ); let mut f = File::open(&p.root().join("target/package/level1-0.0.1.crate")).unwrap(); validate_crate_contents( &mut f, "level1-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], [("Cargo.lock", generated_lock)], ); } fn workspace_with_local_dep_already_published_project() -> Project { Package::new("dep", "0.1.0").publish(); project() .file( "Cargo.toml", r#" [workspace] members = ["dep", "main"] "#, ) .file( "main/Cargo.toml", r#" [package] name = "main" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "main" repository = "bar" [dependencies] dep = { path = "../dep", version = "0.1.0" } "#, ) .file("main/src/main.rs", "fn main() {}") .file( "dep/Cargo.toml", r#" [package] name = "dep" version = "0.1.0" edition = "2015" authors = [] license = "MIT" description = "dep" repository = "bar" "#, ) .file("dep/src/lib.rs", "") .build() } #[cargo_test] fn workspace_with_local_dep_already_published() { let reg = registry::init(); let p = workspace_with_local_dep_already_published_project(); p.cargo("package") .replace_crates_io(reg.index_url()) .with_stderr_data( str![[r#" [PACKAGING] dep v0.1.0 ([ROOT]/foo/dep) [PACKAGING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] dep v0.1.0 ([ROOT]/foo/dep) [COMPILING] dep v0.1.0 ([ROOT]/foo/target/package/dep-0.1.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] main v0.0.1 ([ROOT]/foo/main) [DOWNLOADING] crates ... [DOWNLOADED] dep v0.1.0 [COMPILING] dep v0.1.0 [COMPILING] main v0.0.1 ([ROOT]/foo/target/package/main-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) "#]] .unordered(), ) .run(); } #[cargo_test] fn workspace_with_local_dep_already_published_nightly() { let reg = registry::init(); let p = workspace_with_local_dep_already_published_project(); p.cargo("package -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .replace_crates_io(reg.index_url()) .with_stderr_data( str![[r#" [PACKAGING] dep v0.1.0 ([ROOT]/foo/dep) [PACKAGING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] dep v0.1.0 ([ROOT]/foo/dep) [COMPILING] dep v0.1.0 ([ROOT]/foo/target/package/dep-0.1.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] main v0.0.1 ([ROOT]/foo/main) [UNPACKING] dep v0.1.0 (registry `[ROOT]/foo/target/package/tmp-registry`) [COMPILING] dep v0.1.0 [COMPILING] main v0.0.1 ([ROOT]/foo/target/package/main-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn workspace_with_local_and_remote_deps() { let reg = registry::init(); Package::new("dep", "0.0.1").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["dep", "main"] "#, ) .file( "main/Cargo.toml", r#" [package] name = "main" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "main" repository = "bar" [dependencies] dep = { path = "../dep", version = "0.1.0" } old_dep = { package = "dep", version = "0.0.1" } "#, ) .file("main/src/main.rs", "fn main() {}") .file( "dep/Cargo.toml", r#" [package] name = "dep" version = "0.1.0" edition = "2015" authors = [] license = "MIT" description = "dep" repository = "bar" "#, ) .file("dep/src/lib.rs", "") .build(); p.cargo("package -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .replace_crates_io(reg.index_url()) .with_stderr_data( str![[r#" [PACKAGING] dep v0.1.0 ([ROOT]/foo/dep) [PACKAGING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] dep v0.1.0 ([ROOT]/foo/dep) [COMPILING] dep v0.1.0 ([ROOT]/foo/target/package/dep-0.1.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] main v0.0.1 ([ROOT]/foo/main) [DOWNLOADING] crates ... [UNPACKING] dep v0.1.0 (registry `[ROOT]/foo/target/package/tmp-registry`) [DOWNLOADED] dep v0.0.1 [COMPILING] dep v0.0.1 [COMPILING] dep v0.1.0 [COMPILING] main v0.0.1 ([ROOT]/foo/target/package/main-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) "#]] .unordered(), ) .run(); } #[cargo_test] fn registry_not_in_publish_list() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" publish = [ "test" ] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("package --registry alternative -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] `foo` cannot be packaged. The registry `alternative` is not listed in the `package.publish` value in Cargo.toml. "#]]) .run(); } #[cargo_test] fn registry_inferred_from_unique_option() { let _registry = registry::RegistryBuilder::new() .http_api() .http_index() .alternative() .build(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["dep", "main"] "#, ) .file( "main/Cargo.toml", r#" [package] name = "main" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "main" repository = "bar" publish = ["alternative"] [dependencies] dep = { path = "../dep", version = "0.1.0", registry = "alternative" } "#, ) .file("main/src/main.rs", "fn main() {}") .file( "dep/Cargo.toml", r#" [package] name = "dep" version = "0.1.0" edition = "2015" authors = [] license = "MIT" description = "dep" repository = "bar" publish = ["alternative"] "#, ) .file("dep/src/lib.rs", "") .build(); p.cargo("package -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .with_stderr_data(str![[r#" [PACKAGING] dep v0.1.0 ([ROOT]/foo/dep) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] `alternative` index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] dep v0.1.0 ([ROOT]/foo/dep) [COMPILING] dep v0.1.0 ([ROOT]/foo/target/package/dep-0.1.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] `alternative` index [UNPACKING] dep v0.1.0 (registry `[ROOT]/foo/target/package/tmp-registry`) [COMPILING] dep v0.1.0 (registry `alternative`) [COMPILING] main v0.0.1 ([ROOT]/foo/target/package/main-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn registry_not_inferred_because_of_conflict() { let alt_reg = registry::RegistryBuilder::new() .http_api() .http_index() .alternative() .build(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["dep", "main"] "#, ) .file( "main/Cargo.toml", r#" [package] name = "main" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "main" repository = "bar" publish = ["alternative"] [dependencies] dep = { path = "../dep", version = "0.1.0", registry = "alternative" } "#, ) .file("main/src/main.rs", "fn main() {}") .file( "dep/Cargo.toml", r#" [package] name = "dep" version = "0.1.0" edition = "2015" authors = [] license = "MIT" description = "dep" repository = "bar" publish = ["alternative2"] "#, ) .file("dep/src/lib.rs", "") .build(); p.cargo("package -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] conflicts between `package.publish` fields in the selected packages "#]]) .run(); p.cargo("package -Zpackage-workspace --registry=alternative") .masquerade_as_nightly_cargo(&["package-workspace"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] `dep` cannot be packaged. The registry `alternative` is not listed in the `package.publish` value in Cargo.toml. "#]]) .run(); p.cargo(&format!( "package --index {} -Zpackage-workspace", alt_reg.index_url() )) .masquerade_as_nightly_cargo(&["package-workspace"]) .with_stderr_data(str![[r#" [PACKAGING] dep v0.1.0 ([ROOT]/foo/dep) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] `alternative` index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] dep v0.1.0 ([ROOT]/foo/dep) [COMPILING] dep v0.1.0 ([ROOT]/foo/target/package/dep-0.1.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] `alternative` index [UNPACKING] dep v0.1.0 (registry `[ROOT]/foo/target/package/tmp-registry`) [COMPILING] dep v0.1.0 (registry `alternative`) [COMPILING] main v0.0.1 ([ROOT]/foo/target/package/main-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn registry_inference_ignores_unpublishable() { let _alt_reg = registry::RegistryBuilder::new() .http_api() .http_index() .alternative() .build(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["dep", "main"] "#, ) .file( "main/Cargo.toml", r#" [package] name = "main" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "main" repository = "bar" publish = false [dependencies] dep = { path = "../dep", version = "0.1.0", registry = "alternative" } "#, ) .file("main/src/main.rs", "fn main() {}") .file( "dep/Cargo.toml", r#" [package] name = "dep" version = "0.1.0" edition = "2015" authors = [] license = "MIT" description = "dep" repository = "bar" publish = ["alternative"] "#, ) .file("dep/src/lib.rs", "") .build(); p.cargo("package -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .with_stderr_data(str![[r#" [PACKAGING] dep v0.1.0 ([ROOT]/foo/dep) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] `alternative` index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] dep v0.1.0 ([ROOT]/foo/dep) [COMPILING] dep v0.1.0 ([ROOT]/foo/target/package/dep-0.1.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] `alternative` index [UNPACKING] dep v0.1.0 (registry `[ROOT]/foo/target/package/tmp-registry`) [COMPILING] dep v0.1.0 (registry `alternative`) [COMPILING] main v0.0.1 ([ROOT]/foo/target/package/main-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("package -Zpackage-workspace --registry=alternative") .masquerade_as_nightly_cargo(&["package-workspace"]) .with_stderr_data(str![[r#" [PACKAGING] dep v0.1.0 ([ROOT]/foo/dep) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] `alternative` index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] dep v0.1.0 ([ROOT]/foo/dep) [COMPILING] dep v0.1.0 ([ROOT]/foo/target/package/dep-0.1.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] `alternative` index [COMPILING] dep v0.1.0 (registry `alternative`) [COMPILING] main v0.0.1 ([ROOT]/foo/target/package/main-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn registry_not_inferred_because_of_multiple_options() { let _alt_reg = registry::RegistryBuilder::new() .http_api() .http_index() .alternative() .build(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["dep", "main"] "#, ) .file( "main/Cargo.toml", r#" [package] name = "main" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "main" repository = "bar" publish = ["alternative", "alternative2"] [dependencies] dep = { path = "../dep", version = "0.1.0", registry = "alternative" } "#, ) .file("main/src/main.rs", "fn main() {}") .file( "dep/Cargo.toml", r#" [package] name = "dep" version = "0.1.0" edition = "2015" authors = [] license = "MIT" description = "dep" repository = "bar" publish = ["alternative", "alternative2"] "#, ) .file("dep/src/lib.rs", "") .build(); p.cargo("package -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] --registry is required to disambiguate between "alternative" or "alternative2" registries "#]]) .run(); p.cargo("package -Zpackage-workspace --registry=alternative") .masquerade_as_nightly_cargo(&["package-workspace"]) .with_stderr_data(str![[r#" [PACKAGING] dep v0.1.0 ([ROOT]/foo/dep) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] `alternative` index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] dep v0.1.0 ([ROOT]/foo/dep) [COMPILING] dep v0.1.0 ([ROOT]/foo/target/package/dep-0.1.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] `alternative` index [UNPACKING] dep v0.1.0 (registry `[ROOT]/foo/target/package/tmp-registry`) [COMPILING] dep v0.1.0 (registry `alternative`) [COMPILING] main v0.0.1 ([ROOT]/foo/target/package/main-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn registry_not_inferred_because_of_mismatch() { let _alt_reg = registry::RegistryBuilder::new() .http_api() .http_index() .alternative() .build(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["dep", "main"] "#, ) .file( "main/Cargo.toml", r#" [package] name = "main" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "main" repository = "bar" publish = ["alternative"] [dependencies] dep = { path = "../dep", version = "0.1.0", registry = "alternative" } "#, ) .file("main/src/main.rs", "fn main() {}") // No `publish` field means "any registry", but the presence of this package // will stop us from inferring a registry. .file( "dep/Cargo.toml", r#" [package] name = "dep" version = "0.1.0" edition = "2015" authors = [] license = "MIT" description = "dep" repository = "bar" "#, ) .file("dep/src/lib.rs", "") .build(); p.cargo("package -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] --registry is required because not all `package.publish` settings agree "#]]) .run(); p.cargo("package -Zpackage-workspace --registry=alternative") .masquerade_as_nightly_cargo(&["package-workspace"]) .with_stderr_data(str![[r#" [PACKAGING] dep v0.1.0 ([ROOT]/foo/dep) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] `alternative` index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] dep v0.1.0 ([ROOT]/foo/dep) [COMPILING] dep v0.1.0 ([ROOT]/foo/target/package/dep-0.1.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] `alternative` index [UNPACKING] dep v0.1.0 (registry `[ROOT]/foo/target/package/tmp-registry`) [COMPILING] dep v0.1.0 (registry `alternative`) [COMPILING] main v0.0.1 ([ROOT]/foo/target/package/main-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn unpublishable_dependency() { let _alt_reg = registry::RegistryBuilder::new() .http_api() .http_index() .alternative() .build(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["dep", "main"] "#, ) .file( "main/Cargo.toml", r#" [package] name = "main" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "main" repository = "bar" [dependencies] dep = { path = "../dep", version = "0.1.0", registry = "alternative" } "#, ) .file("main/src/main.rs", "fn main() {}") .file( "dep/Cargo.toml", r#" [package] name = "dep" version = "0.1.0" edition = "2015" authors = [] license = "MIT" description = "dep" repository = "bar" publish = false "#, ) .file("dep/src/lib.rs", "") .build(); p.cargo("package -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .with_status(101) .with_stderr_data(str![[r#" [PACKAGING] dep v0.1.0 ([ROOT]/foo/dep) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] main v0.0.1 ([ROOT]/foo/main) [UPDATING] `alternative` index [ERROR] failed to prepare local package for uploading Caused by: no matching package named `dep` found location searched: `alternative` index required by package `main v0.0.1 ([ROOT]/foo/main)` "#]]) .run(); } #[cargo_test] fn in_package_workspace_with_members_with_features_old() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["li"] "#, ) .file("src/main.rs", "fn main() {}") .file( "li/Cargo.toml", r#" [package] name = "li" version = "0.0.1" edition = "2015" rust-version = "1.69" description = "li" license = "MIT" "#, ) .file("li/src/main.rs", "fn main() {}") .build(); p.cargo("package -p li --no-verify") .with_stderr_data(str![[r#" [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] li v0.0.1 ([ROOT]/foo/li) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) "#]]) .run(); } #[cargo_test] #[cfg(unix)] fn simple_with_fifo() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") .build(); std::process::Command::new("mkfifo") .current_dir(p.root()) .arg(p.root().join("blocks-when-read")) .status() .expect("a FIFO can be created"); // Avoid actual blocking even in case of failure, assuming that what it lists here // would also be read eventually. p.cargo("package -l") .with_stdout_data(str![[r#" Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); } #[cargo_test] fn git_core_symlinks_false() { if !symlink_supported() { return; } let git_project = git::new("bar", |p| { p.file( "Cargo.toml", r#" [package] name = "bar" description = "bar" license = "MIT" edition = "2021" documentation = "foo" "#, ) .file("src/lib.rs", "//! This is a module") .symlink("src/lib.rs", "symlink-lib.rs") .symlink_dir("src", "symlink-dir") }); let url = git_project.root().to_url().to_string(); let p = project().build(); let root = p.root(); // Remove the default project layout, // so we can git-fetch from git_project under the same directory fs::remove_dir_all(&root).unwrap(); fs::create_dir_all(&root).unwrap(); let repo = git::init(&root); let mut cfg = repo.config().unwrap(); cfg.set_bool("core.symlinks", false).unwrap(); // let's fetch from git_project so it respects our core.symlinks=false config. repo.remote_anonymous(&url) .unwrap() .fetch(&["HEAD"], None, None) .unwrap(); let rev = repo .find_reference("FETCH_HEAD") .unwrap() .peel_to_commit() .unwrap(); repo.reset(rev.as_object(), git2::ResetType::Hard, None) .unwrap(); p.cargo("package --allow-dirty") .with_stderr_data(str![[r#" [WARNING] found symbolic links that may be checked out as regular files for git repo at `[ROOT]/foo/` This might cause the `.crate` file to include incorrect or incomplete files [NOTE] to avoid this, set the Git config `core.symlinks` to `true` ... [PACKAGING] bar v0.0.0 ([ROOT]/foo) [PACKAGED] 7 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] bar v0.0.0 ([ROOT]/foo) [COMPILING] bar v0.0.0 ([ROOT]/foo/target/package/bar-0.0.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/bar-0.0.0.crate")).unwrap(); validate_crate_contents( f, "bar-0.0.0.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/lib.rs", // We're missing symlink-dir/lib.rs in the `.crate` file. "symlink-dir", "symlink-lib.rs", ".cargo_vcs_info.json", ], [ // And their contents are incorrect. ("symlink-dir", str!["[ROOT]/bar/src"]), ("symlink-lib.rs", str!["[ROOT]/bar/src/lib.rs"]), ], ); } cargo-0.86.0/tests/testsuite/package_features.rs000064400000000000000000000463351046102023000200570ustar 00000000000000//! Tests for feature selection on the command-line. use std::fmt::Write; use cargo_test_support::prelude::*; use cargo_test_support::registry::{Dependency, Package}; use cargo_test_support::{basic_manifest, project, str}; use super::features2::switch_to_resolver_2; #[cargo_test] fn virtual_no_default_features() { // --no-default-features in root of virtual workspace. Package::new("dep1", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" [dependencies] dep1 = {version = "1.0", optional = true} [features] default = ["dep1"] "#, ) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2015" [features] default = ["f1"] f1 = [] "#, ) .file( "b/src/lib.rs", r#" #[cfg(feature = "f1")] compile_error!{"expected f1 off"} "#, ) .build(); p.cargo("check --no-default-features") .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] a v0.1.0 ([ROOT]/foo/a) [CHECKING] b v0.1.0 ([ROOT]/foo/b) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); p.cargo("check --features foo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] none of the selected packages contains this feature: foo selected packages: a, b [HELP] there is a similarly named feature: f1 "#]]) .run(); p.cargo("check --features a/dep1,b/f1,b/f2,f2") .with_status(101) .with_stderr_data(str![[r#" [ERROR] none of the selected packages contains these features: b/f2, f2 selected packages: a, b [HELP] there is a similarly named feature: f1 "#]]) .run(); p.cargo("check --features a/dep,b/f1,b/f2,f2") .with_status(101) .with_stderr_data(str![[r#" [ERROR] none of the selected packages contains these features: a/dep, b/f2, f2 selected packages: a, b [HELP] there are similarly named features: a/dep1, f1 "#]]) .run(); p.cargo("check --features a/dep,a/dep1") .with_status(101) .with_stderr_data(str![[r#" [ERROR] none of the selected packages contains this feature: a/dep selected packages: a, b [HELP] there is a similarly named feature: b/f1 "#]]) .run(); p.cargo("check -p b --features=dep1") .with_status(101) .with_stderr_data(str![[r#" [ERROR] the package 'b' does not contain this feature: dep1 [HELP] package with the missing feature: a "#]]) .run(); } #[cargo_test] fn virtual_typo_member_feature() { project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" resolver = "2" [features] deny-warnings = [] "#, ) .file("src/lib.rs", "") .build() .cargo("check --features a/deny-warning") .with_status(101) .with_stderr_data(str![[r#" [ERROR] the package 'a' does not contain this feature: a/deny-warning [HELP] there is a similarly named feature: a/deny-warnings "#]]) .run(); } #[cargo_test] fn virtual_features() { // --features in root of virtual workspace. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" [features] f1 = [] "#, ) .file( "a/src/lib.rs", r#" #[cfg(not(feature = "f1"))] compile_error!{"f1 is missing"} "#, ) .file("b/Cargo.toml", &basic_manifest("b", "0.1.0")) .file("b/src/lib.rs", "") .build(); p.cargo("check --features f1") .with_stderr_data( str![[r#" [CHECKING] a v0.1.0 ([ROOT]/foo/a) [CHECKING] b v0.1.0 ([ROOT]/foo/b) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn virtual_with_specific() { // -p flags with --features in root of virtual. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" [features] f1 = [] f2 = [] "#, ) .file( "a/src/lib.rs", r#" #[cfg(not(feature = "f1"))] compile_error!{"f1 is missing"} #[cfg(not(feature = "f2"))] compile_error!{"f2 is missing"} "#, ) .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2015" [features] f2 = [] f3 = [] "#, ) .file( "b/src/lib.rs", r#" #[cfg(not(feature = "f2"))] compile_error!{"f2 is missing"} #[cfg(not(feature = "f3"))] compile_error!{"f3 is missing"} "#, ) .build(); p.cargo("check -p a -p b --features f1,f2,f3") .with_stderr_data( str![[r#" [CHECKING] a v0.1.0 ([ROOT]/foo/a) [CHECKING] b v0.1.0 ([ROOT]/foo/b) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn other_member_from_current() { // -p for another member while in the current directory. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path="bar", features=["f3"] } [features] f1 = ["bar/f4"] "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [features] f1 = [] f2 = [] f3 = [] f4 = [] "#, ) .file("bar/src/lib.rs", "") .file( "bar/src/main.rs", r#" fn main() { if cfg!(feature = "f1") { print!("f1"); } if cfg!(feature = "f2") { print!("f2"); } if cfg!(feature = "f3") { print!("f3"); } if cfg!(feature = "f4") { print!("f4"); } println!(); } "#, ) .build(); // Old behavior. p.cargo("run -p bar --features f1") .with_stdout_data(str![[r#" f3f4 "#]]) .run(); p.cargo("run -p bar --features f1,f2") .with_status(101) .with_stderr_data(str![[r#" [ERROR] Package `foo v0.1.0 ([ROOT]/foo)` does not have the feature `f2` "#]]) .run(); p.cargo("run -p bar --features bar/f1") .with_stdout_data(str![[r#" f1f3 "#]]) .run(); // New behavior. switch_to_resolver_2(&p); p.cargo("run -p bar --features f1") .with_stdout_data(str![[r#" f1 "#]]) .run(); p.cargo("run -p bar --features f1,f2") .with_stdout_data(str![[r#" f1f2 "#]]) .run(); p.cargo("run -p bar --features bar/f1") .with_stdout_data(str![[r#" f1 "#]]) .run(); } #[cargo_test] fn feature_default_resolver() { let p = project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" [features] test = [] "#, ) .file( "src/main.rs", r#" fn main() { if cfg!(feature = "test") { println!("feature set"); } } "#, ) .build(); p.cargo("check --features testt") .with_status(101) .with_stderr_data(str![[r#" [ERROR] Package `a v0.1.0 ([ROOT]/foo)` does not have the feature `testt` "#]]) .run(); p.cargo("run --features test") .with_status(0) .with_stdout_data(str![[r#" feature set "#]]) .run(); p.cargo("run --features a/test") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package `a v0.1.0 ([ROOT]/foo)` does not have a dependency named `a` "#]]) .run(); } #[cargo_test] fn virtual_member_slash() { // member slash feature syntax let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" [dependencies] b = {path="../b", optional=true} [features] default = ["f1"] f1 = [] f2 = [] "#, ) .file( "a/src/lib.rs", r#" #[cfg(feature = "f1")] compile_error!{"f1 is set"} #[cfg(feature = "f2")] compile_error!{"f2 is set"} #[cfg(feature = "b")] compile_error!{"b is set"} "#, ) .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2015" [features] bfeat = [] "#, ) .file( "b/src/lib.rs", r#" #[cfg(feature = "bfeat")] compile_error!{"bfeat is set"} "#, ) .build(); p.cargo("check -p a") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] f1 is set ... "#]]) .with_stderr_does_not_contain("[..]f2 is set[..]") .with_stderr_does_not_contain("[..]b is set[..]") .run(); p.cargo("check -p a --features a/f1") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] f1 is set ... "#]]) .with_stderr_does_not_contain("[..]f2 is set[..]") .with_stderr_does_not_contain("[..]b is set[..]") .run(); p.cargo("check -p a --features a/f2") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] f1 is set ... [ERROR] f2 is set ... "#]]) .with_stderr_does_not_contain("[..]b is set[..]") .run(); p.cargo("check -p a --features b/bfeat") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] bfeat is set ... "#]]) .run(); p.cargo("check -p a --no-default-features").run(); p.cargo("check -p a --no-default-features --features b") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] b is set ... "#]]) .run(); } #[cargo_test] fn non_member() { // -p for a non-member Package::new("dep", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" resolver = "2" [dependencies] dep = "1.0" [features] f1 = [] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -p dep --features f1") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot specify features for packages outside of workspace "#]]) .run(); p.cargo("check -p dep --all-features") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot specify features for packages outside of workspace "#]]) .run(); p.cargo("check -p dep --no-default-features") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot specify features for packages outside of workspace "#]]) .run(); p.cargo("check -p dep") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] dep v1.0.0 (registry `dummy-registry`) [CHECKING] dep v1.0.0 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn resolver1_member_features() { // --features member-name/feature-name with resolver="1" let p = project() .file( "Cargo.toml", r#" [workspace] members = ["member1", "member2"] "#, ) .file( "member1/Cargo.toml", r#" [package] name = "member1" version = "0.1.0" edition = "2015" [features] m1-feature = [] "#, ) .file( "member1/src/main.rs", r#" fn main() { if cfg!(feature = "m1-feature") { println!("m1-feature set"); } } "#, ) .file("member2/Cargo.toml", &basic_manifest("member2", "0.1.0")) .file("member2/src/lib.rs", "") .build(); p.cargo("run -p member1 --features member1/m1-feature") .cwd("member2") .with_stdout_data(str![[r#" m1-feature set "#]]) .run(); p.cargo("check -p member1 --features member1/m2-feature") .cwd("member2") .with_status(101) .with_stderr_data(str![[r#" [ERROR] Package `member1 v0.1.0 ([ROOT]/foo/member1)` does not have the feature `m2-feature` "#]]) .run(); } #[cargo_test] fn non_member_feature() { // --features for a non-member Package::new("jazz", "1.0.0").publish(); Package::new("bar", "1.0.0") .add_dep(Dependency::new("jazz", "1.0").optional(true)) .publish(); let make_toml = |resolver, optional| { let mut s = String::new(); write!( s, r#" [package] name = "foo" version = "0.1.0" edition = "2015" resolver = "{}" [dependencies] "#, resolver ) .unwrap(); if optional { s.push_str(r#"bar = { version = "1.0", optional = true } "#); } else { s.push_str(r#"bar = "1.0""#) } s.push('\n'); s }; let p = project() .file("Cargo.toml", &make_toml("1", false)) .file("src/lib.rs", "") .build(); p.cargo("fetch").run(); ///////////////////////// V1 non-optional eprintln!("V1 non-optional"); p.cargo("check -p bar") .with_stderr_data(str![[r#" [CHECKING] bar v1.0.0 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // TODO: This should not be allowed (future warning?) p.cargo("check --features bar/jazz") .with_stderr_data(str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] jazz v1.0.0 (registry `dummy-registry`) [CHECKING] jazz v1.0.0 [CHECKING] bar v1.0.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // TODO: This should not be allowed (future warning?) p.cargo("check -p bar --features bar/jazz -v") .with_stderr_data(str![[r#" [FRESH] jazz v1.0.0 [FRESH] bar v1.0.0 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); ///////////////////////// V1 optional eprintln!("V1 optional"); p.change_file("Cargo.toml", &make_toml("1", true)); // This error isn't great, but is probably unlikely to be common in // practice, so I'm not going to put much effort into improving it. p.cargo("check -p bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package ID specification `bar` did not match any packages Did you mean `foo`? "#]]) .run(); p.cargo("check -p bar --features bar -v") .with_stderr_data(str![[r#" [FRESH] bar v1.0.0 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // TODO: This should not be allowed (future warning?) p.cargo("check -p bar --features bar/jazz -v") .with_stderr_data(str![[r#" [FRESH] jazz v1.0.0 [FRESH] bar v1.0.0 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); ///////////////////////// V2 non-optional eprintln!("V2 non-optional"); p.change_file("Cargo.toml", &make_toml("2", false)); // TODO: This should not be allowed (future warning?) p.cargo("check --features bar/jazz -v") .with_stderr_data(str![[r#" [FRESH] jazz v1.0.0 [FRESH] bar v1.0.0 [FRESH] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check -p bar -v") .with_stderr_data(str![[r#" [FRESH] bar v1.0.0 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check -p bar --features bar/jazz") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot specify features for packages outside of workspace "#]]) .run(); ///////////////////////// V2 optional eprintln!("V2 optional"); p.change_file("Cargo.toml", &make_toml("2", true)); p.cargo("check -p bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package ID specification `bar` did not match any packages Did you mean `foo`? "#]]) .run(); // New --features behavior does not look at cwd. p.cargo("check -p bar --features bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot specify features for packages outside of workspace "#]]) .run(); p.cargo("check -p bar --features bar/jazz") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot specify features for packages outside of workspace "#]]) .run(); p.cargo("check -p bar --features foo/bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot specify features for packages outside of workspace "#]]) .run(); } cargo-0.86.0/tests/testsuite/patch.rs000064400000000000000000002502421046102023000156570ustar 00000000000000//! Tests for `[patch]` table source replacement. use std::fs; use cargo_test_support::git; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::{self, Package}; use cargo_test_support::{basic_manifest, project, str}; #[cargo_test] fn replace() { Package::new("bar", "0.1.0").publish(); Package::new("baz", "0.1.0") .file( "src/lib.rs", "extern crate bar; pub fn baz() { bar::bar(); }", ) .dep("bar", "0.1.0") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" baz = "0.1.0" [patch.crates-io] bar = { path = "bar" } "#, ) .file( "src/lib.rs", " extern crate bar; extern crate baz; pub fn bar() { bar::bar(); baz::baz(); } ", ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] baz v0.1.0 (registry `dummy-registry`) [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] baz v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn from_config() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file( ".cargo/config.toml", r#" [patch.crates-io] bar = { path = 'bar' } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1")) .file("bar/src/lib.rs", r#""#) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.1 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn from_config_relative() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file( "../.cargo/config.toml", r#" [patch.crates-io] bar = { path = 'foo/bar' } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1")) .file("bar/src/lib.rs", r#""#) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.1 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn from_config_precedence() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [patch.crates-io] bar = { path = 'no-such-path' } "#, ) .file( ".cargo/config.toml", r#" [patch.crates-io] bar = { path = 'bar' } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1")) .file("bar/src/lib.rs", r#""#) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.1 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn nonexistent() { Package::new("baz", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [patch.crates-io] bar = { path = "bar" } "#, ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn patch_git() { let bar = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = {{ git = '{}' }} [patch.'{0}'] bar = {{ path = "bar" }} "#, bar.url() ), ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/override` [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn patch_to_git() { let bar = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn bar() {}") .build(); Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1" [patch.crates-io] bar = {{ git = '{}' }} "#, bar.url() ), ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/override` [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.0 ([ROOTURL]/override#[..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn unused() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [patch.crates-io] bar = { path = "bar" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.2.0")) .file("bar/src/lib.rs", "not rust code") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [WARNING] Patch `bar v0.2.0 ([ROOT]/foo/bar)` was not used in the crate graph. Check that the patched package version and available features are compatible with the dependency requirements. If the patch has a different version from what is locked in the Cargo.lock file, run `cargo update` to use the new version. This may also occur with an optional dependency that is not enabled. [LOCKING] 1 package to latest compatible version [ADDING] bar v0.1.0 (available: v0.2.0) [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [CHECKING] bar v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] Patch `bar v0.2.0 ([ROOT]/foo/bar)` was not used in the crate graph. Check that the patched package version and available features are compatible with the dependency requirements. If the patch has a different version from what is locked in the Cargo.lock file, run `cargo update` to use the new version. This may also occur with an optional dependency that is not enabled. [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // unused patch should be in the lock file let lock = p.read_lockfile(); let toml: toml::Table = toml::from_str(&lock).unwrap(); assert_eq!(toml["patch"]["unused"].as_array().unwrap().len(), 1); assert_eq!(toml["patch"]["unused"][0]["name"].as_str(), Some("bar")); assert_eq!( toml["patch"]["unused"][0]["version"].as_str(), Some("0.2.0") ); } #[cargo_test] fn unused_with_mismatch_source_being_patched() { registry::alt_init(); Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [patch.alternative] bar = { path = "bar" } [patch.crates-io] bar = { path = "baz" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.2.0")) .file("bar/src/lib.rs", "not rust code") .file("baz/Cargo.toml", &basic_manifest("bar", "0.3.0")) .file("baz/src/lib.rs", "not rust code") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [WARNING] Patch `bar v0.2.0 ([ROOT]/foo/bar)` was not used in the crate graph. Perhaps you misspelled the source URL being patched. Possible URLs for `[patch.]`: crates-io [WARNING] Patch `bar v0.3.0 ([ROOT]/foo/baz)` was not used in the crate graph. Check that the patched package version and available features are compatible with the dependency requirements. If the patch has a different version from what is locked in the Cargo.lock file, run `cargo update` to use the new version. This may also occur with an optional dependency that is not enabled. [LOCKING] 1 package to latest compatible version [ADDING] bar v0.1.0 (available: v0.3.0) [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [CHECKING] bar v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn prefer_patch_version() { Package::new("bar", "0.1.2").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [patch.crates-io] bar = { path = "bar" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.1 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // there should be no patch.unused in the toml file let lock = p.read_lockfile(); let toml: toml::Table = toml::from_str(&lock).unwrap(); assert!(toml.get("patch").is_none()); } #[cargo_test] fn unused_from_config() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file( ".cargo/config.toml", r#" [patch.crates-io] bar = { path = "bar" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.2.0")) .file("bar/src/lib.rs", "not rust code") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [WARNING] Patch `bar v0.2.0 ([ROOT]/foo/bar)` was not used in the crate graph. Check that the patched package version and available features are compatible with the dependency requirements. If the patch has a different version from what is locked in the Cargo.lock file, run `cargo update` to use the new version. This may also occur with an optional dependency that is not enabled. [LOCKING] 1 package to latest compatible version [ADDING] bar v0.1.0 (available: v0.2.0) [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [CHECKING] bar v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] Patch `bar v0.2.0 ([ROOT]/foo/bar)` was not used in the crate graph. Check that the patched package version and available features are compatible with the dependency requirements. If the patch has a different version from what is locked in the Cargo.lock file, run `cargo update` to use the new version. This may also occur with an optional dependency that is not enabled. [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // unused patch should be in the lock file let lock = p.read_lockfile(); let toml: toml::Table = toml::from_str(&lock).unwrap(); assert_eq!(toml["patch"]["unused"].as_array().unwrap().len(), 1); assert_eq!(toml["patch"]["unused"][0]["name"].as_str(), Some("bar")); assert_eq!( toml["patch"]["unused"][0]["version"].as_str(), Some("0.2.0") ); } #[cargo_test] fn unused_git() { Package::new("bar", "0.1.0").publish(); let foo = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.2.0")) .file("src/lib.rs", "") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1" [patch.crates-io] bar = {{ git = '{}' }} "#, foo.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/override` [UPDATING] `dummy-registry` index [WARNING] Patch `bar v0.2.0 ([ROOTURL]/override#[..])` was not used in the crate graph. Check that the patched package version and available features are compatible with the dependency requirements. If the patch has a different version from what is locked in the Cargo.lock file, run `cargo update` to use the new version. This may also occur with an optional dependency that is not enabled. [LOCKING] 1 package to latest compatible version [ADDING] bar v0.1.0 (available: v0.2.0) [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [CHECKING] bar v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] Patch `bar v0.2.0 ([ROOTURL]/override#[..])` was not used in the crate graph. Check that the patched package version and available features are compatible with the dependency requirements. If the patch has a different version from what is locked in the Cargo.lock file, run `cargo update` to use the new version. This may also occur with an optional dependency that is not enabled. [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn add_patch() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", r#""#) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [CHECKING] bar v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [patch.crates-io] bar = { path = 'bar' } "#, ); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [ADDING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn add_patch_from_config() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", r#""#) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [CHECKING] bar v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file( ".cargo/config.toml", r#" [patch.crates-io] bar = { path = 'bar' } "#, ); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [ADDING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn add_ignored_patch() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1")) .file("bar/src/lib.rs", r#""#) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [CHECKING] bar v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [patch.crates-io] bar = { path = 'bar' } "#, ); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] Patch `bar v0.1.1 ([ROOT]/foo/bar)` was not used in the crate graph. Check that the patched package version and available features are compatible with the dependency requirements. If the patch has a different version from what is locked in the Cargo.lock file, run `cargo update` to use the new version. This may also occur with an optional dependency that is not enabled. [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] Patch `bar v0.1.1 ([ROOT]/foo/bar)` was not used in the crate graph. Check that the patched package version and available features are compatible with the dependency requirements. If the patch has a different version from what is locked in the Cargo.lock file, run `cargo update` to use the new version. This may also occur with an optional dependency that is not enabled. [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("update").run(); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] bar v0.1.1 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn add_patch_with_features() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [patch.crates-io] bar = { path = 'bar', features = ["some_feature"] } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", r#""#) .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] patch for `bar` uses the features mechanism. default-features and features will not take effect because the patch dependency does not support this mechanism [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] patch for `bar` uses the features mechanism. default-features and features will not take effect because the patch dependency does not support this mechanism [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn add_patch_with_setting_default_features() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [patch.crates-io] bar = { path = 'bar', default-features = false, features = ["none_default_feature"] } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", r#""#) .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] patch for `bar` uses the features mechanism. default-features and features will not take effect because the patch dependency does not support this mechanism [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] patch for `bar` uses the features mechanism. default-features and features will not take effect because the patch dependency does not support this mechanism [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn no_warn_ws_patch() { Package::new("c", "0.1.0").publish(); // Don't issue an unused patch warning when the patch isn't used when // partially building a workspace. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b", "c"] [patch.crates-io] c = { path = "c" } "#, ) .file("a/Cargo.toml", &basic_manifest("a", "0.1.0")) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2015" [dependencies] c = "0.1.0" "#, ) .file("b/src/lib.rs", "") .file("c/Cargo.toml", &basic_manifest("c", "0.1.0")) .file("c/src/lib.rs", "") .build(); p.cargo("check -p a") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [CHECKING] a v0.1.0 ([ROOT]/foo/a) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn new_minor() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [patch.crates-io] bar = { path = 'bar' } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1")) .file("bar/src/lib.rs", r#""#) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.1 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn transitive_new_minor() { Package::new("baz", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = { path = 'bar' } [patch.crates-io] baz = { path = 'baz' } "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] baz = '0.1.0' "#, ) .file("bar/src/lib.rs", r#""#) .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.1")) .file("baz/src/lib.rs", r#""#) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [CHECKING] baz v0.1.1 ([ROOT]/foo/baz) [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn new_major() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.2.0" [patch.crates-io] bar = { path = 'bar' } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.2.0")) .file("bar/src/lib.rs", r#""#) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.2.0 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); Package::new("bar", "0.2.0").publish(); p.cargo("update").run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.2.0" "#, ); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [ADDING] bar v0.2.0 [DOWNLOADING] crates ... [DOWNLOADED] bar v0.2.0 (registry `dummy-registry`) [CHECKING] bar v0.2.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn transitive_new_major() { Package::new("baz", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = { path = 'bar' } [patch.crates-io] baz = { path = 'baz' } "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] baz = '0.2.0' "#, ) .file("bar/src/lib.rs", r#""#) .file("baz/Cargo.toml", &basic_manifest("baz", "0.2.0")) .file("baz/src/lib.rs", r#""#) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [CHECKING] baz v0.2.0 ([ROOT]/foo/baz) [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn shared_by_transitive() { Package::new("baz", "0.1.1").publish(); let baz = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("baz", "0.1.2")) .file("src/lib.rs", "") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = " 0.1.0" edition = "2015" [dependencies] bar = {{ path = "bar" }} baz = "0.1" [patch.crates-io] baz = {{ git = "{}", version = "0.1" }} "#, baz.url(), ), ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [dependencies] baz = "0.1.1" "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/override` [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [CHECKING] baz v0.1.2 ([ROOTURL]/override#[..]) [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn remove_patch() { Package::new("foo", "0.1.0").publish(); Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1" [patch.crates-io] foo = { path = 'foo' } bar = { path = 'bar' } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", r#""#) .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/lib.rs", r#""#) .build(); // Generate a lock file where `foo` is unused p.cargo("check").run(); let lock_file1 = p.read_lockfile(); // Remove `foo` and generate a new lock file form the old one p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1" [patch.crates-io] bar = { path = 'bar' } "#, ); p.cargo("check").run(); let lock_file2 = p.read_lockfile(); // Remove the lock file and build from scratch fs::remove_file(p.root().join("Cargo.lock")).unwrap(); p.cargo("check").run(); let lock_file3 = p.read_lockfile(); assert!(lock_file1.contains("foo")); assert_eq!(lock_file2, lock_file3); assert_ne!(lock_file1, lock_file2); } #[cargo_test] fn non_crates_io() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [patch.some-other-source] bar = { path = 'bar' } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", r#""#) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: [patch] entry `some-other-source` should be a URL or registry name Caused by: invalid url `some-other-source`: relative URL without a base "#]]) .run(); } #[cargo_test] fn replace_with_crates_io() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [patch.crates-io] bar = "0.1" "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", r#""#) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to resolve patches for `https://github.com/rust-lang/crates.io-index` Caused by: patch for `bar` in `https://github.com/rust-lang/crates.io-index` points to the same source, but patches must point to different sources "#]]) .run(); } #[cargo_test] fn patch_in_virtual() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo"] [patch.crates-io] bar = { path = "bar" } "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", r#""#) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = "0.1" "#, ) .file("foo/src/lib.rs", r#""#) .build(); p.cargo("check -p foo") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.1.0 ([ROOT]/foo/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check -p foo") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn patch_depends_on_another_patch() { Package::new("bar", "0.1.0") .file("src/lib.rs", "broken code") .publish(); Package::new("baz", "0.1.0") .dep("bar", "0.1") .file("src/lib.rs", "broken code") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.1.0" edition = "2015" [dependencies] bar = "0.1" baz = "0.1" [patch.crates-io] bar = { path = "bar" } baz = { path = "baz" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1")) .file("bar/src/lib.rs", r#""#) .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.1" edition = "2015" authors = [] [dependencies] bar = "0.1" "#, ) .file("baz/src/lib.rs", r#""#) .build(); p.cargo("check").run(); // Nothing should be rebuilt, no registry should be updated. p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn replace_prerelease() { Package::new("baz", "1.1.0-pre.1").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] [patch.crates-io] baz = { path = "./baz" } "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [dependencies] baz = "1.1.0-pre.1" "#, ) .file( "bar/src/main.rs", "extern crate baz; fn main() { baz::baz() }", ) .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "1.1.0-pre.1" edition = "2015" authors = [] [workspace] "#, ) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("check").run(); } #[cargo_test] fn patch_older() { Package::new("baz", "1.0.2").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = 'bar' } baz = "=1.0.1" [patch.crates-io] baz = { path = "./baz" } "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [dependencies] baz = "1.0.0" "#, ) .file("bar/src/lib.rs", "") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "1.0.1" edition = "2015" authors = [] "#, ) .file("baz/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [CHECKING] baz v1.0.1 ([ROOT]/foo/baz) [CHECKING] bar v0.5.0 ([ROOT]/foo/bar) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cycle() { Package::new("a", "1.0.0").publish(); Package::new("b", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] [patch.crates-io] a = {path="a"} b = {path="b"} "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "1.0.0" edition = "2015" [dependencies] b = "1.0" "#, ) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "1.0.0" edition = "2015" [dependencies] a = "1.0" "#, ) .file("b/src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] cyclic package dependency: package `a v1.0.0 ([ROOT]/foo/a)` depends on itself. Cycle: package `a v1.0.0 ([ROOT]/foo/a)` ... which satisfies dependency `a = "^1.0"` of package `b v1.0.0 ([ROOT]/foo/b)` ... which satisfies dependency `b = "^1.0"` of package `a v1.0.0 ([ROOT]/foo/a)` "#]]) .run(); } #[cargo_test] fn multipatch() { Package::new("a", "1.0.0").publish(); Package::new("a", "2.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] a1 = { version = "1", package = "a" } a2 = { version = "2", package = "a" } [patch.crates-io] b1 = { path = "a1", package = "a" } b2 = { path = "a2", package = "a" } "#, ) .file("src/lib.rs", "pub fn foo() { a1::f1(); a2::f2(); }") .file( "a1/Cargo.toml", r#" [package] name = "a" version = "1.0.0" edition = "2015" "#, ) .file("a1/src/lib.rs", "pub fn f1() {}") .file( "a2/Cargo.toml", r#" [package] name = "a" version = "2.0.0" edition = "2015" "#, ) .file("a2/src/lib.rs", "pub fn f2() {}") .build(); p.cargo("check").run(); } #[cargo_test] fn patch_same_version() { let bar = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "") .build(); cargo_test_support::registry::init(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "0.1" [patch.crates-io] bar = {{ path = "bar" }} bar2 = {{ git = '{}', package = 'bar' }} "#, bar.url(), ), ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/override` [ERROR] cannot have two `[patch]` entries which both resolve to `bar v0.1.0` "#]]) .run(); } #[cargo_test] fn two_semver_compatible() { let bar = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.1")) .file("src/lib.rs", "") .build(); cargo_test_support::registry::init(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "0.1" [patch.crates-io] bar = {{ path = "bar" }} bar2 = {{ git = '{}', package = 'bar' }} "#, bar.url(), ), ) .file("src/lib.rs", "pub fn foo() { bar::foo() }") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.2" edition = "2015" "#, ) .file("bar/src/lib.rs", "pub fn foo() {}") .build(); // assert the build succeeds and doesn't panic anywhere, and then afterwards // assert that the build succeeds again without updating anything or // building anything else. p.cargo("check").run(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] Patch `bar v0.1.1 ([ROOTURL]/override#[..])` was not used in the crate graph. Perhaps you misspelled the source URL being patched. Possible URLs for `[patch.]`: [ROOT]/foo/bar [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn multipatch_select_big() { let bar = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "") .build(); cargo_test_support::registry::init(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "*" [patch.crates-io] bar = {{ path = "bar" }} bar2 = {{ git = '{}', package = 'bar' }} "#, bar.url(), ), ) .file("src/lib.rs", "pub fn foo() { bar::foo() }") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.2.0" edition = "2015" "#, ) .file("bar/src/lib.rs", "pub fn foo() {}") .build(); // assert the build succeeds, which is only possible if 0.2.0 is selected // since 0.1.0 is missing the function we need. Afterwards assert that the // build succeeds again without updating anything or building anything else. p.cargo("check").run(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] Patch `bar v0.1.0 ([ROOTURL]/override#[..])` was not used in the crate graph. Perhaps you misspelled the source URL being patched. Possible URLs for `[patch.]`: [ROOT]/foo/bar [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn canonicalize_a_bunch() { let base = git::repo(&paths::root().join("base")) .file("Cargo.toml", &basic_manifest("base", "0.1.0")) .file("src/lib.rs", "") .build(); let intermediate = git::repo(&paths::root().join("intermediate")) .file( "Cargo.toml", &format!( r#" [package] name = "intermediate" version = "0.1.0" edition = "2015" [dependencies] # Note the lack of trailing slash base = {{ git = '{}' }} "#, base.url(), ), ) .file("src/lib.rs", "pub fn f() { base::f() }") .build(); let newbase = git::repo(&paths::root().join("newbase")) .file("Cargo.toml", &basic_manifest("base", "0.1.0")) .file("src/lib.rs", "pub fn f() {}") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] # Note the trailing slashes base = {{ git = '{base}/' }} intermediate = {{ git = '{intermediate}/' }} [patch.'{base}'] # Note the lack of trailing slash base = {{ git = '{newbase}' }} "#, base = base.url(), intermediate = intermediate.url(), newbase = newbase.url(), ), ) .file("src/lib.rs", "pub fn a() { base::f(); intermediate::f() }") .build(); // Once to make sure it actually works p.cargo("check").run(); // Then a few more times for good measure to ensure no weird warnings about // `[patch]` are printed. p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn update_unused_new_version() { // If there is an unused patch entry, and then you update the patch, // make sure `cargo update` will be able to fix the lock file. Package::new("bar", "0.1.5").publish(); // Start with a lock file to 0.1.5, and an "unused" patch because the // version is too old. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "0.1.5" [patch.crates-io] bar = { path = "../bar" } "#, ) .file("src/lib.rs", "") .build(); // Patch is too old. let bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.4")) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [WARNING] Patch `bar v0.1.4 ([ROOT]/bar)` was not used in the crate graph. ... "#]]) .run(); // unused patch should be in the lock file let lock = p.read_lockfile(); let toml: toml::Table = toml::from_str(&lock).unwrap(); assert_eq!(toml["patch"]["unused"].as_array().unwrap().len(), 1); assert_eq!(toml["patch"]["unused"][0]["name"].as_str(), Some("bar")); assert_eq!( toml["patch"]["unused"][0]["version"].as_str(), Some("0.1.4") ); // Oh, OK, let's update to the latest version. bar.change_file("Cargo.toml", &basic_manifest("bar", "0.1.6")); // Create a backup so we can test it with different options. fs::copy(p.root().join("Cargo.lock"), p.root().join("Cargo.lock.bak")).unwrap(); // Try to build again, this should automatically update Cargo.lock. p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [ADDING] bar v0.1.6 ([ROOT]/bar) [CHECKING] bar v0.1.6 ([ROOT]/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // This should not update any registry. p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(!p.read_lockfile().contains("unused")); // Restore the lock file, and see if `update` will work, too. fs::copy(p.root().join("Cargo.lock.bak"), p.root().join("Cargo.lock")).unwrap(); // Try `update `. p.cargo("update bar") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [ADDING] bar v0.1.6 ([ROOT]/bar) [REMOVING] bar v0.1.5 "#]]) .run(); // Try with bare `cargo update`. fs::copy(p.root().join("Cargo.lock.bak"), p.root().join("Cargo.lock")).unwrap(); p.cargo("update") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [ADDING] bar v0.1.6 ([ROOT]/bar) [REMOVING] bar v0.1.5 "#]]) .run(); } #[cargo_test] fn too_many_matches() { // The patch locations has multiple versions that match. registry::alt_init(); Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.1.0").alternative(true).publish(); Package::new("bar", "0.1.1").alternative(true).publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1" [patch.crates-io] bar = { version = "0.1", registry = "alternative" } "#, ) .file("src/lib.rs", "") .build(); // Picks 0.1.1, the most recent version. p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [ERROR] failed to resolve patches for `https://github.com/rust-lang/crates.io-index` Caused by: patch for `bar` in `https://github.com/rust-lang/crates.io-index` failed to resolve Caused by: patch for `bar` in `registry `alternative`` resolved to more than one candidate Found versions: 0.1.0, 0.1.1 Update the patch definition to select only one package. For example, add an `=` version requirement to the patch definition, such as `version = "=0.1.1"`. "#]]) .run(); } #[cargo_test] fn no_matches() { // A patch to a location that does not contain the named package. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1" [patch.crates-io] bar = { path = "bar" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("abc", "0.1.0")) .file("bar/src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to resolve patches for `https://github.com/rust-lang/crates.io-index` Caused by: patch for `bar` in `https://github.com/rust-lang/crates.io-index` failed to resolve Caused by: The patch location `[ROOT]/foo/bar` does not appear to contain any packages matching the name `bar`. "#]]) .run(); } #[cargo_test] fn mismatched_version() { // A patch to a location that has an old version. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1.1" [patch.crates-io] bar = { path = "bar", version = "0.1.1" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to resolve patches for `https://github.com/rust-lang/crates.io-index` Caused by: patch for `bar` in `https://github.com/rust-lang/crates.io-index` failed to resolve Caused by: The patch location `[ROOT]/foo/bar` contains a `bar` package with version `0.1.0`, but the patch definition requires `^0.1.1`. Check that the version in the patch location is what you expect, and update the patch definition to match. "#]]) .run(); } #[cargo_test] fn patch_walks_backwards() { // Starting with a locked patch, change the patch so it points to an older version. Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1" [patch.crates-io] bar = {path="bar"} "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.1 ([ROOT]/foo/bar) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Somehow the user changes the version backwards. p.change_file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNGRADING] bar v0.1.1 ([ROOT]/foo/bar) -> v0.1.0 [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn patch_walks_backwards_restricted() { // This is the same as `patch_walks_backwards`, but the patch contains a // `version` qualifier. This is unusual, just checking a strange edge case. Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1" [patch.crates-io] bar = {path="bar", version="0.1.1"} "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.1 ([ROOT]/foo/bar) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Somehow the user changes the version backwards. p.change_file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to resolve patches for `https://github.com/rust-lang/crates.io-index` Caused by: patch for `bar` in `https://github.com/rust-lang/crates.io-index` failed to resolve Caused by: The patch location `[ROOT]/foo/bar` contains a `bar` package with version `0.1.0`, but the patch definition requires `^0.1.1`. Check that the version in the patch location is what you expect, and update the patch definition to match. "#]]) .run(); } #[cargo_test] fn patched_dep_new_version() { // What happens when a patch is locked, and then one of the patched // dependencies needs to be updated. In this case, the baz requirement // gets updated from 0.1.0 to 0.1.1. Package::new("bar", "0.1.0").dep("baz", "0.1.0").publish(); Package::new("baz", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1" [patch.crates-io] bar = {path="bar"} "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [dependencies] baz = "0.1" "#, ) .file("bar/src/lib.rs", "") .build(); // Lock everything. p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] baz v0.1.0 (registry `dummy-registry`) [CHECKING] baz v0.1.0 [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); Package::new("baz", "0.1.1").publish(); // Just the presence of the new version should not have changed anything. p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Modify the patch so it requires the new version. p.change_file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [dependencies] baz = "0.1.1" "#, ); // Should unlock and update cleanly. p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] baz v0.1.0 -> v0.1.1 [DOWNLOADING] crates ... [DOWNLOADED] baz v0.1.1 (registry `dummy-registry`) [CHECKING] baz v0.1.1 [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn patch_update_doesnt_update_other_sources() { // Very extreme edge case, make sure a patch update doesn't update other // sources. registry::alt_init(); Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.1.0").alternative(true).publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1" bar_alt = { version = "0.1", registry = "alternative", package = "bar" } [patch.crates-io] bar = { path = "bar" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [UPDATING] `alternative` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `alternative`) [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [CHECKING] bar v0.1.0 (registry `alternative`) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); // Publish new versions in both sources. Package::new("bar", "0.1.1").publish(); Package::new("bar", "0.1.1").alternative(true).publish(); // Since it is locked, nothing should change. p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Require new version on crates.io. p.change_file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1")); // This should not update bar_alt. p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] bar v0.1.0 ([ROOT]/foo/bar) -> v0.1.1 [CHECKING] bar v0.1.1 ([ROOT]/foo/bar) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn can_update_with_alt_reg() { // A patch to an alt reg can update. registry::alt_init(); Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.1.0").alternative(true).publish(); Package::new("bar", "0.1.1").alternative(true).publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1" [patch.crates-io] bar = { version = "=0.1.1", registry = "alternative" } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.1 (registry `alternative`) [CHECKING] bar v0.1.1 (registry `alternative`) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); Package::new("bar", "0.1.2").alternative(true).publish(); // Should remain locked. p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // This does nothing, due to `=` requirement. p.cargo("update bar") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [UPDATING] `dummy-registry` index [LOCKING] 0 packages to latest compatible versions [NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest "#]]) .run(); // Bump to 0.1.2. p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1" [patch.crates-io] bar = { version = "=0.1.2", registry = "alternative" } "#, ); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] bar v0.1.1 (registry `alternative`) -> v0.1.2 [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.2 (registry `alternative`) [CHECKING] bar v0.1.2 (registry `alternative`) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn gitoxide_clones_shallow_old_git_patch() { perform_old_git_patch(true) } fn perform_old_git_patch(shallow: bool) { // Example where an old lockfile with an explicit branch="master" in Cargo.toml. Package::new("bar", "1.0.0").publish(); let (bar, bar_repo) = git::new_repo("bar", |p| { p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) .file("src/lib.rs", "") }); let bar_oid = bar_repo.head().unwrap().target().unwrap(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" [patch.crates-io] bar = {{ git = "{}", branch = "master" }} "#, bar.url() ), ) .file( "Cargo.lock", &format!( r#" # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "bar" version = "1.0.0" source = "git+{}#{}" [[package]] name = "foo" version = "0.1.0" dependencies = [ "bar", ] "#, bar.url(), bar_oid ), ) .file("src/lib.rs", "") .build(); bar.change_file("Cargo.toml", &basic_manifest("bar", "2.0.0")); git::add(&bar_repo); git::commit(&bar_repo); // This *should* keep the old lock. let mut cargo = p.cargo("tree"); if shallow { cargo .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-deps") .masquerade_as_nightly_cargo(&[ "unstable features must be available for -Z gitoxide and -Z git", ]); } cargo // .env("CARGO_LOG", "trace") .with_stderr_data( "\ [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 1 package to latest compatible version [ADDING] bar v1.0.0 ([ROOTURL]/bar?branch=master#[..]) ", ) // .with_status(1) .with_stdout_data(format!( "\ foo v0.1.0 ([ROOT]/foo) └── bar v1.0.0 ([ROOTURL]/bar?branch=master#{}) ", &bar_oid.to_string()[..8] )) .run(); } #[cargo_test] fn old_git_patch() { perform_old_git_patch(false) } // From https://github.com/rust-lang/cargo/issues/7463 #[cargo_test] fn patch_eq_conflict_panic() { Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.1.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "=0.1.0" [dev-dependencies] bar = "=0.1.1" [patch.crates-io] bar = {path="bar"} "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("generate-lockfile") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for `bar`. ... required by package `foo v0.1.0 ([ROOT]/foo)` versions that meet the requirements `=0.1.1` are: 0.1.1 all possible versions conflict with previously selected packages. previously selected package `bar v0.1.0` ... which satisfies dependency `bar = "=0.1.0"` of package `foo v0.1.0 ([ROOT]/foo)` failed to select a version for `bar` which could resolve this conflict "#]]) .run(); } // From https://github.com/rust-lang/cargo/issues/11336 #[cargo_test] fn mismatched_version2() { Package::new("qux", "0.1.0-beta.1").publish(); Package::new("qux", "0.1.0-beta.2").publish(); Package::new("bar", "0.1.0") .dep("qux", "=0.1.0-beta.1") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1.0" qux = "0.1.0-beta.2" [patch.crates-io] qux = { path = "qux" } "#, ) .file("src/lib.rs", "") .file( "qux/Cargo.toml", r#" [package] name = "qux" version = "0.1.0-beta.1" edition = "2015" "#, ) .file("qux/src/lib.rs", "") .build(); p.cargo("generate-lockfile") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for `qux`. ... required by package `bar v0.1.0` ... which satisfies dependency `bar = "^0.1.0"` of package `foo v0.1.0 ([ROOT]/foo)` versions that meet the requirements `=0.1.0-beta.1` are: 0.1.0-beta.1 all possible versions conflict with previously selected packages. previously selected package `qux v0.1.0-beta.2` ... which satisfies dependency `qux = "^0.1.0-beta.2"` of package `foo v0.1.0 ([ROOT]/foo)` failed to select a version for `qux` which could resolve this conflict "#]]) .run(); } #[cargo_test] fn mismatched_version_with_prerelease() { Package::new("prerelease-deps", "0.0.1").publish(); // A patch to a location that has an prerelease version let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] prerelease-deps = "0.1.0" [patch.crates-io] prerelease-deps = { path = "./prerelease-deps" } "#, ) .file("src/lib.rs", "") .file( "prerelease-deps/Cargo.toml", &basic_manifest("prerelease-deps", "0.1.1-pre1"), ) .file("prerelease-deps/src/lib.rs", "") .build(); p.cargo("generate-lockfile") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `prerelease-deps = "^0.1.0"` candidate versions found which didn't match: 0.1.1-pre1, 0.0.1 location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.1.0 ([ROOT]/foo)` if you are looking for the prerelease package it needs to be specified explicitly prerelease-deps = { version = "0.1.1-pre1" } perhaps a crate was updated and forgotten to be re-vendored? "#]]) .run(); } #[cargo_test] fn from_config_empty() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ) .file( ".cargo/config.toml", r#" [patch.''] bar = { path = 'bar' } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1")) .file("bar/src/lib.rs", r#""#) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] [patch] entry `` should be a URL or registry name Caused by: invalid url ``: relative URL without a base "#]]) .run(); } #[cargo_test] fn from_manifest_empty() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [patch.''] bar = { path = 'bar' } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1")) .file("bar/src/lib.rs", r#""#) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: [patch] entry `` should be a URL or registry name Caused by: invalid url ``: relative URL without a base "#]]) .run(); } #[cargo_test] fn patched_reexport_stays_locked() { // Patch example where you emulate a semver-incompatible patch via a re-export. // Testing an issue where the lockfile does not stay locked after a new version is published. Package::new("bar", "1.0.0").publish(); Package::new("bar", "2.0.0").publish(); Package::new("bar", "3.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] [package] name = "foo" [dependencies] bar1 = {package="bar", version="1.0.0"} bar2 = {package="bar", version="2.0.0"} [patch.crates-io] bar1 = { package = "bar", path = "bar-1-as-3" } bar2 = { package = "bar", path = "bar-2-as-3" } "#, ) .file("src/lib.rs", "") .file( "bar-1-as-3/Cargo.toml", r#" [package] name = "bar" version = "1.0.999" [dependencies] bar = "3.0.0" "#, ) .file("bar-1-as-3/src/lib.rs", "") .file( "bar-2-as-3/Cargo.toml", r#" [package] name = "bar" version = "2.0.999" [dependencies] bar = "3.0.0" "#, ) .file("bar-2-as-3/src/lib.rs", "") .build(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.0 ([ROOT]/foo) β”œβ”€β”€ bar v1.0.999 ([ROOT]/foo/bar-1-as-3) β”‚ └── bar v3.0.0 └── bar v2.0.999 ([ROOT]/foo/bar-2-as-3) └── bar v3.0.0 "#]]) .run(); std::fs::copy( p.root().join("Cargo.lock"), p.root().join("Cargo.lock.orig"), ) .unwrap(); Package::new("bar", "3.0.1").publish(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.0 ([ROOT]/foo) β”œβ”€β”€ bar v1.0.999 ([ROOT]/foo/bar-1-as-3) β”‚ └── bar v3.0.0 └── bar v2.0.999 ([ROOT]/foo/bar-2-as-3) └── bar v3.0.0 "#]]) .run(); assert_eq!(p.read_file("Cargo.lock"), p.read_file("Cargo.lock.orig")); } #[cargo_test] fn patch_in_real_with_base() { let bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "pub fn hello() {}") .build(); Package::new("bar", "0.5.0").publish(); let p = project() .file( ".cargo/config.toml", &format!( r#" [path-bases] test = '{}' "#, bar.root().parent().unwrap().display() ), ) .file( "Cargo.toml", r#" cargo-features = ["path-bases"] [package] name = "foo" version = "0.5.0" authors = ["wycats@example.com"] edition = "2018" [dependencies] bar = "0.5.0" [patch.crates-io] bar = { base = 'test', path = 'bar' } "#, ) .file("src/lib.rs", "use bar::hello as _;") .build(); p.cargo("tree") .masquerade_as_nightly_cargo(&["path-bases"]) .with_stdout_data(str![[r#" foo v0.5.0 ([ROOT]/foo) └── bar v0.5.0 ([ROOT]/bar) "#]]) .run(); } #[cargo_test] fn patch_in_virtual_with_base() { let bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "pub fn hello() {}") .build(); Package::new("bar", "0.5.0").publish(); let p = project() .file( ".cargo/config.toml", &format!( r#" [path-bases] test = '{}' "#, bar.root().parent().unwrap().display() ), ) .file( "Cargo.toml", r#" cargo-features = ["path-bases"] [workspace] members = ["foo"] [patch.crates-io] bar = { base = 'test', path = 'bar' } "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.5.0" authors = ["wycats@example.com"] edition = "2018" [dependencies] bar = "0.5.0" "#, ) .file("foo/src/lib.rs", "use bar::hello as _;") .build(); p.cargo("tree") .masquerade_as_nightly_cargo(&["path-bases"]) .with_stdout_data(str![[r#" foo v0.5.0 ([ROOT]/foo/foo) └── bar v0.5.0 ([ROOT]/bar) "#]]) .run(); } cargo-0.86.0/tests/testsuite/path.rs000064400000000000000000001342451046102023000155200ustar 00000000000000//! Tests for `path` dependencies. use std::fs; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::{basic_lib_manifest, basic_manifest, main_file, project}; use cargo_test_support::{sleep_ms, t}; #[cargo_test] // I have no idea why this is failing spuriously on Windows; // for more info, see #3466. #[cfg(not(windows))] fn cargo_compile_with_nested_deps_shorthand() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] version = "0.5.0" path = "bar" "#, ) .file("src/main.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"])) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.baz] version = "0.5.0" path = "baz" [lib] name = "bar" "#, ) .file( "bar/src/bar.rs", r#" extern crate baz; pub fn gimme() -> String { baz::gimme() } "#, ) .file("bar/baz/Cargo.toml", &basic_lib_manifest("baz")) .file( "bar/baz/src/baz.rs", r#" pub fn gimme() -> String { "test passed".to_string() } "#, ) .build(); p.cargo("build") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] baz v0.5.0 ([ROOT]/foo/bar/baz) [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" test passed "#]]) .run(); println!("cleaning"); p.cargo("clean -v") .with_stderr_data(str![[r#" [REMOVING] [ROOT]/foo/target [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); println!("building baz"); p.cargo("build -p baz") .with_stderr_data(str![[r#" [COMPILING] baz v0.5.0 ([ROOT]/foo/bar/baz) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); println!("building foo"); p.cargo("build -p foo") .with_stderr_data(str![[r#" [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cargo_compile_with_root_dev_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dev-dependencies.bar] version = "0.5.0" path = "../bar" [[bin]] name = "foo" "#, ) .file("src/main.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"])) .build(); let _p2 = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file( "src/lib.rs", r#" pub fn gimme() -> &'static str { "zoidberg" } "#, ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] foo v0.5.0 ([ROOT]/foo) error[E0463]: can't find crate for `bar` ... "#]]) .run(); } #[cargo_test] fn cargo_compile_with_root_dev_deps_with_testing() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dev-dependencies.bar] version = "0.5.0" path = "../bar" [[bin]] name = "foo" "#, ) .file("src/main.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"])) .build(); let _p2 = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file( "src/lib.rs", r#" pub fn gimme() -> &'static str { "zoidberg" } "#, ) .build(); p.cargo("test") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/bar) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/main.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cargo_compile_with_transitive_dev_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] version = "0.5.0" path = "bar" "#, ) .file("src/main.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"])) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dev-dependencies.baz] git = "git://example.com/path/to/nowhere" [lib] name = "bar" "#, ) .file( "bar/src/bar.rs", r#" pub fn gimme() -> &'static str { "zoidberg" } "#, ) .build(); p.cargo("build") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" zoidberg "#]]) .run(); } #[cargo_test] fn no_rebuild_dependency() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] path = "bar" "#, ) .file("src/main.rs", "extern crate bar; fn main() { bar::bar() }") .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file("bar/src/bar.rs", "pub fn bar() {}") .build(); // First time around we should compile both foo and bar p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.5.0 ([ROOT]/foo/bar) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); sleep_ms(1000); p.change_file( "src/main.rs", r#" extern crate bar; fn main() { bar::bar(); } "#, ); // Don't compile bar, but do recompile foo. p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn deep_dependencies_trigger_rebuild() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] path = "bar" "#, ) .file("src/main.rs", "extern crate bar; fn main() { bar::bar() }") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [lib] name = "bar" [dependencies.baz] path = "../baz" "#, ) .file( "bar/src/bar.rs", "extern crate baz; pub fn bar() { baz::baz() }", ) .file("baz/Cargo.toml", &basic_lib_manifest("baz")) .file("baz/src/baz.rs", "pub fn baz() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [CHECKING] baz v0.5.0 ([ROOT]/foo/baz) [CHECKING] bar v0.5.0 ([ROOT]/foo/bar) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Make sure an update to baz triggers a rebuild of bar // // We base recompilation off mtime, so sleep for at least a second to ensure // that this write will change the mtime. sleep_ms(1000); p.change_file("baz/src/baz.rs", r#"pub fn baz() { println!("hello!"); }"#); sleep_ms(1000); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] baz v0.5.0 ([ROOT]/foo/baz) [CHECKING] bar v0.5.0 ([ROOT]/foo/bar) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Make sure an update to bar doesn't trigger baz sleep_ms(1000); p.change_file( "bar/src/bar.rs", r#" extern crate baz; pub fn bar() { println!("hello!"); baz::baz(); } "#, ); sleep_ms(1000); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] bar v0.5.0 ([ROOT]/foo/bar) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn no_rebuild_two_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] path = "bar" [dependencies.baz] path = "baz" "#, ) .file("src/main.rs", "extern crate bar; fn main() { bar::bar() }") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [lib] name = "bar" [dependencies.baz] path = "../baz" "#, ) .file("bar/src/bar.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_lib_manifest("baz")) .file("baz/src/baz.rs", "pub fn baz() {}") .build(); p.cargo("build") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] baz v0.5.0 ([ROOT]/foo/baz) [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.bin("foo").is_file()); p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.bin("foo").is_file()); } #[cargo_test] fn nested_deps_recompile() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] version = "0.5.0" path = "src/bar" "#, ) .file("src/main.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"])) .file("src/bar/Cargo.toml", &basic_lib_manifest("bar")) .file("src/bar/src/bar.rs", "pub fn gimme() -> i32 { 92 }") .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.5.0 ([ROOT]/foo/src/bar) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); sleep_ms(1000); p.change_file("src/main.rs", r#"fn main() {}"#); // This shouldn't recompile `bar` p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn error_message_for_missing_manifest() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] path = "src/bar" "#, ) .file("src/lib.rs", "") .file("src/bar/not-a-manifest", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to get `bar` as a dependency of package `foo v0.5.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update [ROOT]/foo/src/bar Caused by: failed to read `[ROOT]/foo/src/bar/Cargo.toml` Caused by: [NOT_FOUND] "#]]) .run(); } #[cargo_test] fn path_bases_not_stable() { let bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "") .build(); let p = project() .file( ".cargo/config.toml", &format!( r#" [path-bases] test = '{}' "#, bar.root().parent().unwrap().display() ), ) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" authors = ["wycats@example.com"] [dependencies] bar = { base = 'test', path = 'bar' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data( "\ [ERROR] failed to parse manifest at `[..]/foo/Cargo.toml` Caused by: resolving path dependency bar Caused by: feature `path-bases` is required The package requires the Cargo feature called `path-bases`, but that feature is not stabilized in this version of Cargo ([..]). Consider trying a newer version of Cargo (this may require the nightly release). See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#path-bases for more information about the status of this feature. ", ) .run(); } #[cargo_test] fn path_with_base() { let bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "") .build(); let p = project() .file( ".cargo/config.toml", &format!( r#" [path-bases] test = '{}' "#, bar.root().parent().unwrap().display() ), ) .file( "Cargo.toml", r#" cargo-features = ["path-bases"] [package] name = "foo" version = "0.5.0" authors = ["wycats@example.com"] [dependencies] bar = { base = 'test', path = 'bar' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v") .masquerade_as_nightly_cargo(&["path-bases"]) .run(); } #[cargo_test] fn current_dir_with_base() { let bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "") .build(); let p = project() .file( ".cargo/config.toml", &format!( r#" [path-bases] test = '{}' "#, bar.root().display() ), ) .file( "Cargo.toml", r#" cargo-features = ["path-bases"] [package] name = "foo" version = "0.5.0" authors = ["wycats@example.com"] [dependencies] bar = { base = 'test', path = '.' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v") .masquerade_as_nightly_cargo(&["path-bases"]) .run(); } #[cargo_test] fn parent_dir_with_base() { let bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "") .build(); let p = project() .file( ".cargo/config.toml", &format!( r#" [path-bases] test = '{}/subdir' "#, bar.root().display() ), ) .file( "Cargo.toml", r#" cargo-features = ["path-bases"] [package] name = "foo" version = "0.5.0" authors = ["wycats@example.com"] [dependencies] bar = { base = 'test', path = '..' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v") .masquerade_as_nightly_cargo(&["path-bases"]) .run(); } #[cargo_test] fn inherit_dependency_using_base() { let bar = project() .at("dep_with_base") .file("Cargo.toml", &basic_manifest("dep_with_base", "0.5.0")) .file("src/lib.rs", "") .build(); let p = project() .file( ".cargo/config.toml", &format!( r#" [path-bases] test = '{}' "#, bar.root().parent().unwrap().display() ), ) .file( "Cargo.toml", r#" [package] name = "parent" version = "0.1.0" authors = [] [workspace] members = ["child"] [workspace.dependencies] dep_with_base = { base = 'test', path = 'dep_with_base' } "#, ) .file("src/main.rs", "fn main() {}") .file( "child/Cargo.toml", r#" cargo-features = ["path-bases"] [package] name = "child" version = "0.1.0" authors = [] [dependencies] dep_with_base = { workspace = true } "#, ) .file("child/src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .masquerade_as_nightly_cargo(&["path-bases"]) .run(); } #[cargo_test] fn path_with_relative_base() { project() .at("shared_proj/bar") .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "") .build(); let p = project() .file( "../.cargo/config.toml", r#" [path-bases] test = 'shared_proj' "#, ) .file( "Cargo.toml", r#" cargo-features = ["path-bases"] [package] name = "foo" version = "0.5.0" authors = ["wycats@example.com"] [dependencies] bar = { base = 'test', path = 'bar' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v") .masquerade_as_nightly_cargo(&["path-bases"]) .run(); } #[cargo_test] fn workspace_builtin_base() { project() .at("dep_with_base") .file("Cargo.toml", &basic_manifest("dep_with_base", "0.5.0")) .file("src/lib.rs", "") .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "parent" version = "0.1.0" authors = [] [workspace] members = ["child"] "#, ) .file("src/main.rs", "fn main() {}") .file( "child/Cargo.toml", r#" cargo-features = ["path-bases"] [package] name = "child" version = "0.1.0" authors = [] [dependencies] dep_with_base = { base = 'workspace', path = '../dep_with_base' } "#, ) .file("child/src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .masquerade_as_nightly_cargo(&["path-bases"]) .run(); } #[cargo_test] fn workspace_builtin_base_not_a_workspace() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["path-bases"] [package] name = "foo" version = "0.1.0" authors = [] [dependencies] bar = { base = 'workspace', path = 'bar' } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build") .masquerade_as_nightly_cargo(&["path-bases"]) .with_status(101) .with_stderr_data( "\ [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: resolving path dependency bar Caused by: failed to find a workspace root ", ) .run(); } #[cargo_test] fn shadow_workspace_builtin_base() { let bar = project() .at("dep_with_base") .file("Cargo.toml", &basic_manifest("dep_with_base", "0.5.0")) .file("src/lib.rs", "") .build(); let p = project() .file( ".cargo/config.toml", &format!( r#" [path-bases] workspace = '{}/subdir/anotherdir' "#, bar.root().parent().unwrap().display() ), ) .file( "Cargo.toml", r#" [package] name = "parent" version = "0.1.0" authors = [] [workspace] members = ["child"] "#, ) .file("src/main.rs", "fn main() {}") .file( "child/Cargo.toml", r#" cargo-features = ["path-bases"] [package] name = "child" version = "0.1.0" authors = [] [dependencies] dep_with_base = { base = 'workspace', path = '../../dep_with_base' } "#, ) .file("child/src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .masquerade_as_nightly_cargo(&["path-bases"]) .run(); } #[cargo_test] fn unknown_base() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["path-bases"] [package] name = "foo" version = "0.5.0" authors = ["wycats@example.com"] [dependencies] bar = { base = 'test', path = 'bar' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .masquerade_as_nightly_cargo(&["path-bases"]) .with_status(101) .with_stderr_data( "\ [ERROR] failed to parse manifest at `[..]/foo/Cargo.toml` Caused by: resolving path dependency bar Caused by: path base `test` is undefined. You must add an entry for `test` in the Cargo configuration [path-bases] table. ", ) .run(); } #[cargo_test] fn base_without_path() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["path-bases"] [package] name = "foo" version = "0.5.0" authors = ["wycats@example.com"] [dependencies] bar = { version = '1.0.0', base = 'test' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .masquerade_as_nightly_cargo(&["path-bases"]) .with_status(101) .with_stderr_data( "\ [ERROR] failed to parse manifest at `[..]/foo/Cargo.toml` Caused by: resolving path dependency bar Caused by: `base` can only be used with path dependencies ", ) .run(); } #[cargo_test] fn invalid_base() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["path-bases"] [package] name = "foo" version = "0.5.0" authors = ["wycats@example.com"] [dependencies] bar = { base = '^^not-valid^^', path = 'bar' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .masquerade_as_nightly_cargo(&["path-bases"]) .with_status(101) .with_stderr_data( "\ [ERROR] invalid character `^` in path base name: `^^not-valid^^`, the first character must be a Unicode XID start character (most letters or `_`) --> Cargo.toml:10:23 | 10 | bar = { base = '^^not-valid^^', path = 'bar' } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ", ) .run(); } #[cargo_test] fn invalid_path_with_base() { let p = project() .file( ".cargo/config.toml", r#" [path-bases] test = 'shared_proj' "#, ) .file( "Cargo.toml", r#" cargo-features = ["path-bases"] [package] name = "foo" version = "0.5.0" authors = ["wycats@example.com"] edition = "2015" [dependencies] bar = { base = 'test', path = '"' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .masquerade_as_nightly_cargo(&["path-bases"]) .with_status(101) .with_stderr_data( "\ [ERROR] failed to get `bar` as a dependency of package `foo v0.5.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update [ROOT]/foo/shared_proj/\" Caused by: failed to read `[ROOT]/foo/shared_proj/\"/Cargo.toml` Caused by: [NOT_FOUND] ", ) .run(); } #[cargo_test] fn self_dependency_using_base() { let p = project() .file( ".cargo/config.toml", r#" [path-bases] test = '.' "#, ) .file( "Cargo.toml", r#" cargo-features = ["path-bases"] [package] name = "foo" version = "0.1.0" authors = [] edition = "2015" [dependencies] foo = { base = 'test', path = '.' } "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build") .masquerade_as_nightly_cargo(&["path-bases"]) .with_status(101) .with_stderr_data( "\ [ERROR] cyclic package dependency: package `foo v0.1.0 ([ROOT]/foo)` depends on itself. Cycle: package `foo v0.1.0 ([ROOT]/foo)` ... which satisfies path dependency `foo` of package `foo v0.1.0 ([ROOT]/foo)` ", ) .run(); } #[cargo_test] fn override_relative() { let bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "") .build(); fs::create_dir(&paths::root().join(".cargo")).unwrap(); fs::write( &paths::root().join(".cargo/config.toml"), r#"paths = ["bar"]"#, ) .unwrap(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] path = '{}' "#, bar.root().display() ), ) .file("src/lib.rs", "") .build(); p.cargo("check -v").run(); } #[cargo_test] fn override_self() { let bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("src/lib.rs", "") .build(); let p = project(); let root = p.root(); let p = p .file( ".cargo/config.toml", &format!("paths = ['{}']", root.display()), ) .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] path = '{}' "#, bar.root().display() ), ) .file("src/lib.rs", "") .file("src/main.rs", "fn main() {}") .build(); p.cargo("check").run(); } #[cargo_test] fn override_path_dep() { let bar = project() .at("bar") .file( "p1/Cargo.toml", r#" [package] name = "p1" version = "0.5.0" edition = "2015" authors = [] [dependencies.p2] path = "../p2" "#, ) .file("p1/src/lib.rs", "") .file("p2/Cargo.toml", &basic_manifest("p2", "0.5.0")) .file("p2/src/lib.rs", "") .build(); let p = project() .file( ".cargo/config.toml", &format!( "paths = ['{}', '{}']", bar.root().join("p1").display(), bar.root().join("p2").display() ), ) .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.p2] path = '{}' "#, bar.root().join("p2").display() ), ) .file("src/lib.rs", "") .build(); p.cargo("check -v").run(); } #[cargo_test] fn path_dep_build_cmd() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] [dependencies.bar] version = "0.5.0" path = "bar" "#, ) .file("src/main.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"])) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = ["wycats@example.com"] build = "build.rs" [lib] name = "bar" path = "src/bar.rs" "#, ) .file( "bar/build.rs", r#" use std::fs; fn main() { fs::copy("src/bar.rs.in", "src/bar.rs").unwrap(); } "#, ) .file("bar/src/bar.rs.in", "pub fn gimme() -> i32 { 0 }") .build(); p.root().join("bar").move_into_the_past(); p.cargo("build") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" 0 "#]]) .run(); // Touching bar.rs.in should cause the `build` command to run again. p.change_file("bar/src/bar.rs.in", "pub fn gimme() -> i32 { 1 }"); p.cargo("build") .with_stderr_data(str![[r#" [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" 1 "#]]) .run(); } #[cargo_test] fn dev_deps_no_rebuild_lib() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dev-dependencies.bar] path = "bar" [lib] name = "foo" doctest = false "#, ) .file( "src/lib.rs", r#" #[cfg(test)] #[allow(unused_extern_crates)] extern crate bar; #[cfg(not(test))] pub fn foo() { env!("FOO"); } "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.5.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("build") .env("FOO", "bar") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn custom_target_no_rebuild() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = { path = "a" } [workspace] members = ["a", "b"] "#, ) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("a", "0.5.0")) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = { path = "../a" } "#, ) .file("b/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] a v0.5.0 ([ROOT]/foo/a) [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); t!(fs::rename( p.root().join("target"), p.root().join("target_moved") )); p.cargo("check --manifest-path=b/Cargo.toml") .env("CARGO_TARGET_DIR", "target_moved") .with_stderr_data(str![[r#" [CHECKING] b v0.5.0 ([ROOT]/foo/b) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn override_and_depend() { let p = project() .no_manifest() .file( "a/a1/Cargo.toml", r#" [package] name = "a1" version = "0.5.0" edition = "2015" authors = [] [dependencies] a2 = { path = "../a2" } "#, ) .file("a/a1/src/lib.rs", "") .file("a/a2/Cargo.toml", &basic_manifest("a2", "0.5.0")) .file("a/a2/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.5.0" edition = "2015" authors = [] [dependencies] a1 = { path = "../a/a1" } a2 = { path = "../a/a2" } "#, ) .file("b/src/lib.rs", "") .file("b/.cargo/config.toml", r#"paths = ["../a"]"#) .build(); p.cargo("check") .cwd("b") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [CHECKING] a2 v0.5.0 ([ROOT]/foo/a) [CHECKING] a1 v0.5.0 ([ROOT]/foo/a) [CHECKING] b v0.5.0 ([ROOT]/foo/b) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn missing_path_dependency() { let p = project() .file("Cargo.toml", &basic_manifest("a", "0.5.0")) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#"paths = ["../whoa-this-does-not-exist"]"#, ) .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to update path override `[ROOT]/whoa-this-does-not-exist` (defined in `[ROOT]/foo/.cargo/config.toml`) Caused by: failed to read directory `[ROOT]/whoa-this-does-not-exist` Caused by: [NOT_FOUND] "#]]) .run(); } #[cargo_test] fn invalid_path_dep_in_workspace_with_lockfile() { Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "top" version = "0.5.0" edition = "2015" authors = [] [workspace] [dependencies] foo = { path = "foo" } "#, ) .file("src/lib.rs", "") .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("foo/src/lib.rs", "") .build(); // Generate a lock file p.cargo("check").run(); // Change the dependency on `bar` to an invalid path p.change_file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] bar = { path = "" } "#, ); // Make sure we get a nice error. In the past this actually stack // overflowed! p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no matching package found searched package name: `bar` perhaps you meant: foo location searched: [ROOT]/foo/foo required by package `foo v0.5.0 ([ROOT]/foo/foo)` "#]]) .run(); } #[cargo_test] fn workspace_produces_rlib() { let p = project() .file( "Cargo.toml", r#" [package] name = "top" version = "0.5.0" edition = "2015" authors = [] [workspace] [dependencies] foo = { path = "foo" } "#, ) .file("src/lib.rs", "") .file("foo/Cargo.toml", &basic_manifest("foo", "0.5.0")) .file("foo/src/lib.rs", "") .build(); p.cargo("build").run(); assert!(p.root().join("target/debug/libtop.rlib").is_file()); assert!(!p.root().join("target/debug/libfoo.rlib").is_file()); } #[cargo_test] fn deep_path_error() { // Test for an error loading a path deep in the dependency graph. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] a = {path="a"} "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" [dependencies] b = {path="../b"} "#, ) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2015" [dependencies] c = {path="../c"} "#, ) .file("b/src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to get `c` as a dependency of package `b v0.1.0 ([ROOT]/foo/b)` ... which satisfies path dependency `b` of package `a v0.1.0 ([ROOT]/foo/a)` ... which satisfies path dependency `a` of package `foo v0.1.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `c` Caused by: Unable to update [ROOT]/foo/c Caused by: failed to read `[ROOT]/foo/c/Cargo.toml` Caused by: [NOT_FOUND] "#]]) .run(); } #[cargo_test] fn catch_tricky_cycle() { let p = project() .file( "Cargo.toml", r#" [package] name = "message" version = "0.1.0" edition = "2015" [dev-dependencies] test = { path = "test" } "#, ) .file("src/lib.rs", "") .file( "tangle/Cargo.toml", r#" [package] name = "tangle" version = "0.1.0" edition = "2015" [dependencies] message = { path = ".." } snapshot = { path = "../snapshot" } "#, ) .file("tangle/src/lib.rs", "") .file( "snapshot/Cargo.toml", r#" [package] name = "snapshot" version = "0.1.0" edition = "2015" [dependencies] ledger = { path = "../ledger" } "#, ) .file("snapshot/src/lib.rs", "") .file( "ledger/Cargo.toml", r#" [package] name = "ledger" version = "0.1.0" edition = "2015" [dependencies] tangle = { path = "../tangle" } "#, ) .file("ledger/src/lib.rs", "") .file( "test/Cargo.toml", r#" [package] name = "test" version = "0.1.0" edition = "2015" [dependencies] snapshot = { path = "../snapshot" } "#, ) .file("test/src/lib.rs", "") .build(); p.cargo("test") .with_stderr_data(str![[r#" [ERROR] cyclic package dependency: package `ledger v0.1.0 ([ROOT]/foo/ledger)` depends on itself. Cycle: package `ledger v0.1.0 ([ROOT]/foo/ledger)` ... "#]]) .with_status(101) .run(); } #[cargo_test] fn same_name_version_changed() { // Illustrates having two path packages with the same name, but different versions. // Verifies it works correctly when one of the versions is changed. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" edition = "2021" [dependencies] foo2 = { path = "foo2", package = "foo" } "#, ) .file("src/lib.rs", "") .file( "foo2/Cargo.toml", r#" [package] name = "foo" version = "2.0.0" edition = "2021" "#, ) .file("foo2/src/lib.rs", "") .build(); p.cargo("tree") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version "#]]) .with_stdout_data(str![[r#" foo v1.0.0 ([ROOT]/foo) └── foo v2.0.0 ([ROOT]/foo/foo2) "#]]) .run(); p.change_file( "foo2/Cargo.toml", r#" [package] name = "foo" version = "2.0.1" edition = "2021" "#, ); p.cargo("tree") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [ADDING] foo v2.0.1 ([ROOT]/foo/foo2) "#]]) .with_stdout_data(str![[r#" foo v1.0.0 ([ROOT]/foo) └── foo v2.0.1 ([ROOT]/foo/foo2) "#]]) .run(); } cargo-0.86.0/tests/testsuite/paths.rs000064400000000000000000000160121046102023000156720ustar 00000000000000//! Tests for `paths` overrides. use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::{basic_manifest, project}; #[cargo_test] fn broken_path_override_warns() { Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.2.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a1" } "#, ) .file("src/lib.rs", "") .file( "a1/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1" "#, ) .file("a1/src/lib.rs", "") .file( "a2/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.2" "#, ) .file("a2/src/lib.rs", "") .file(".cargo/config.toml", r#"paths = ["a2"]"#) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [WARNING] path override for crate `a` has altered the original list of dependencies; the dependency on `bar` was either added or modified to not match the previously resolved version This is currently allowed but is known to produce buggy behavior with spurious recompiles and changes to the crate graph. Path overrides unfortunately were never intended to support this feature, so for now this message is just a warning. In the future, however, this message will become a hard error. To change the dependency graph via an override it's recommended to use the `[patch]` feature of Cargo instead of the path override feature. This is documented online at the url below for more information. https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html [DOWNLOADING] crates ... [DOWNLOADED] bar v0.2.0 (registry `dummy-registry`) [CHECKING] bar v0.2.0 [CHECKING] a v0.0.1 ([ROOT]/foo/a2) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn override_to_path_dep() { Package::new("bar", "0.1.0").dep("baz", "0.1").publish(); Package::new("baz", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" authors = [] [dependencies] baz = { path = "baz" } "#, ) .file("bar/src/lib.rs", "") .file("bar/baz/Cargo.toml", &basic_manifest("baz", "0.0.1")) .file("bar/baz/src/lib.rs", "") .file(".cargo/config.toml", r#"paths = ["bar"]"#) .build(); p.cargo("check").run(); } #[cargo_test] fn paths_ok_with_optional() { Package::new("baz", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = { path = "bar" } "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] baz = { version = "0.1", optional = true } "#, ) .file("bar/src/lib.rs", "") .file( "bar2/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] baz = { version = "0.1", optional = true } "#, ) .file("bar2/src/lib.rs", "") .file(".cargo/config.toml", r#"paths = ["bar2"]"#) .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.1.0 ([ROOT]/foo/bar2) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn paths_add_optional_bad() { Package::new("baz", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2021" authors = [] [dependencies] bar = { path = "bar" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "") .file( "bar2/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2021" authors = [] [dependencies] baz = { version = "0.1", optional = true } "#, ) .file("bar2/src/lib.rs", "") .file(".cargo/config.toml", r#"paths = ["bar2"]"#) .build(); p.cargo("check") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [WARNING] path override for crate `bar` has altered the original list of dependencies; the dependency on `baz` was either added or modified to not match the previously resolved version This is currently allowed but is known to produce buggy behavior with spurious recompiles and changes to the crate graph. Path overrides unfortunately were never intended to support this feature, so for now this message is just a warning. In the future, however, this message will become a hard error. To change the dependency graph via an override it's recommended to use the `[patch]` feature of Cargo instead of the path override feature. This is documented online at the url below for more information. https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html [CHECKING] bar v0.1.0 ([ROOT]/foo/bar2) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/pgo.rs000064400000000000000000000063071046102023000153460ustar 00000000000000//! Test if PGO works. use std::path::PathBuf; use std::process::Command; use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; fn llvm_profdata() -> Option { let output = Command::new("rustc") .arg("--print=target-libdir") .output() .expect("rustc to run"); assert!(output.status.success()); let mut libdir = PathBuf::from(String::from_utf8(output.stdout).unwrap()); assert!(libdir.pop()); let mut bin = libdir.join("bin").join("llvm-profdata"); bin.exists().then(|| bin.clone()).or_else(|| { bin.set_extension("exe"); bin.exists().then_some(bin) }) } // Rustc build may be without profiling support. // Mark it as nightly so it won't run on rust-lang/rust CI. #[cfg_attr( target_os = "linux", cargo_test(nightly, reason = "rust-lang/rust#133675") )] // macOS may emit different LLVM PGO warnings. // Windows LLVM has different requirements. #[cfg_attr(not(target_os = "linux"), cargo_test, ignore = "linux only")] fn pgo_works() { let Some(llvm_profdata) = llvm_profdata() else { return; }; let p = project() .file( "Cargo.toml", r#" [package] name = "foo" edition = "2021" "#, ) .file( "src/main.rs", r#" fn fibonacci(n: u64) -> u64 { match n { 0 => 0, 1 => 1, _ => fibonacci(n - 1) + fibonacci(n - 2), } } fn main() { for i in [15, 20, 25] { let _ = fibonacci(i); } } "#, ) .build(); let target_dir = p.build_dir(); let release_bin = target_dir.join("release").join("foo"); let pgo_data_dir = target_dir.join("pgo-data"); let profdata_path = target_dir.join("merged.profdata"); // Build the instrumented binary p.cargo("build --release") .env( "RUSTFLAGS", format!("-Cprofile-generate={}", pgo_data_dir.display()), ) .run(); // Run the instrumented binary cargo_test_support::execs() .with_process_builder(cargo_test_support::process(release_bin)) .run(); cargo_test_support::process(llvm_profdata) .arg("merge") .arg("-o") .arg(&profdata_path) .arg(pgo_data_dir) .status() .unwrap(); // Use merged profdata during optimization. // // -Cllvm-args=-pgo-warn-missing-function is essential. // If there are LLVM warnings, there might be something wrong. p.cargo("build --release -v") .env( "RUSTFLAGS", format!( "-Cprofile-use={} -Cllvm-args=-pgo-warn-missing-function", profdata_path.display() ), ) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.0 ([ROOT]/foo) [RUNNING] `rustc [..]-Cprofile-use=[ROOT]/foo/target/merged.profdata -Cllvm-args=-pgo-warn-missing-function` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/pkgid.rs000064400000000000000000000236541046102023000156630ustar 00000000000000//! Tests for the `cargo pkgid` command. use cargo_test_support::basic_lib_manifest; use cargo_test_support::compare::assert_e2e; use cargo_test_support::git; use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry::Package; use cargo_test_support::str; #[cargo_test] fn local() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] [package] name = "foo" version = "0.1.0" edition = "2018" "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2018" "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("generate-lockfile").run(); p.cargo("pkgid foo") .with_stdout_data(str![[r#" path+[ROOTURL]/foo#0.1.0 "#]]) .run(); // Bad file URL. p.cargo("pkgid ./Cargo.toml") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid package ID specification: `./Cargo.toml` Caused by: package ID specification `./Cargo.toml` looks like a file path, maybe try [ROOTURL]/foo/Cargo.toml "#]]) .run(); // Bad file URL with similar name. p.cargo("pkgid './bar'") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid package ID specification: `./bar` Did you mean `bar`? Caused by: package ID specification `./bar` looks like a file path, maybe try [ROOTURL]/foo/bar "#]]) .run(); } #[cargo_test] fn registry() { Package::new("crates-io", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] crates-io = "0.1.0" "#, ) .file("src/main.rs", "fn main() {}") .file("cratesio", "") .build(); p.cargo("generate-lockfile").run(); p.cargo("pkgid crates-io") .with_stdout_data(str![[r#" registry+https://github.com/rust-lang/crates.io-index#crates-io@0.1.0 "#]]) .run(); // Bad URL. p.cargo("pkgid https://example.com/crates-io") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package ID specification `https://example.com/crates-io` did not match any packages Did you mean one of these? crates-io@0.1.0 "#]]) .run(); // Bad name. p.cargo("pkgid crates_io") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package ID specification `crates_io` did not match any packages Did you mean `crates-io`? "#]]) .run(); } #[cargo_test] fn multiple_versions() { Package::new("two-ver", "0.1.0").publish(); Package::new("two-ver", "0.2.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] two-ver = "0.1.0" two-ver2 = { package = "two-ver", version = "0.2.0" } "#, ) .file("src/lib.rs", "") .file("cratesio", "") .build(); p.cargo("generate-lockfile").run(); p.cargo("pkgid two-ver:0.2.0") .with_stdout_data(str![[r#" registry+https://github.com/rust-lang/crates.io-index#two-ver@0.2.0 "#]]) .run(); // Incomplete version. p.cargo("pkgid two-ver@0") .with_status(101) .with_stderr_data(str![[r#" [ERROR] There are multiple `two-ver` packages in your project, and the specification `two-ver@0` is ambiguous. Please re-run this command with one of the following specifications: two-ver@0.1.0 two-ver@0.2.0 "#]]) .run(); // Incomplete version. p.cargo("pkgid two-ver@0.2") .with_stdout_data(str![[r#" registry+https://github.com/rust-lang/crates.io-index#two-ver@0.2.0 "#]]) .run(); // Ambiguous. p.cargo("pkgid two-ver") .with_status(101) .with_stderr_data(str![[r#" [ERROR] There are multiple `two-ver` packages in your project, and the specification `two-ver` is ambiguous. Please re-run this command with one of the following specifications: two-ver@0.1.0 two-ver@0.2.0 "#]]) .run(); // Bad version. p.cargo("pkgid two-ver:0.3.0") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package ID specification `two-ver@0.3.0` did not match any packages Did you mean one of these? two-ver@0.1.0 two-ver@0.2.0 "#]]) .run(); } // Not for `cargo pkgid` but the `PackageIdSpec` format #[cargo_test] fn multiple_git_same_version() { // Test what happens if different packages refer to the same git repo with // different refs, and the package version is the same. let (xyz_project, xyz_repo) = git::new_repo("xyz", |project| { project .file("Cargo.toml", &basic_lib_manifest("xyz")) .file("src/lib.rs", "fn example() {}") }); let rev1 = xyz_repo.revparse_single("HEAD").unwrap().id(); xyz_project.change_file("src/lib.rs", "pub fn example() {}"); git::add(&xyz_repo); let rev2 = git::commit(&xyz_repo); // Both rev1 and rev2 point to version 0.1.0. let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = {{ path = "bar" }} xyz = {{ git = "{}", rev = "{}" }} "#, xyz_project.url(), rev1 ), ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", &format!( r#" [package] name = "bar" version = "0.1.0" [dependencies] xyz = {{ git = "{}", rev = "{}" }} "#, xyz_project.url(), rev2 ), ) .file("bar/src/lib.rs", "") .build(); p.cargo("check").run(); p.cargo("tree") .with_stdout_data(&format!( "\ foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ bar v0.1.0 ([ROOT]/foo/bar) β”‚ └── xyz v0.5.0 ([ROOTURL]/xyz?rev={}#{}) └── xyz v0.5.0 ([ROOTURL]/xyz?rev={}#{}) ", rev2, &rev2.to_string()[..8], rev1, &rev1.to_string()[..8] )) .run(); // FIXME: This fails since xyz is ambiguous, but the // possible pkgids are also ambiguous. p.cargo("pkgid xyz") .with_status(101) .with_stderr_data(str![[r#" [ERROR] There are multiple `xyz` packages in your project, and the specification `xyz` is ambiguous. Please re-run this command with one of the following specifications: git+[ROOTURL]/xyz?rev=[..]#0.5.0 git+[ROOTURL]/xyz?rev=[..]#0.5.0 "#]]) .run(); // TODO, what should the `-p` value be here? //p.cargo("update -p") } // Keep Package ID format in sync among // // * Package ID specifications // * machine-readable message via `--message-format=json` // * `cargo metadata` output #[cargo_test] fn pkgid_json_message_metadata_consistency() { let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "fn unused() {}") .file("build.rs", "fn main() {}") .build(); p.cargo("generate-lockfile").run(); let output = p.cargo("pkgid").arg("foo").run(); let pkgid = String::from_utf8(output.stdout).unwrap(); let pkgid = pkgid.trim(); assert_e2e().eq(pkgid, str!["path+[ROOTURL]/foo#0.5.0"]); p.cargo("check --message-format=json") .with_stdout_data( str![[r#" [ { "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.5.0", "reason": "compiler-artifact", "...": "{...}" }, { "package_id": "path+[ROOTURL]/foo#0.5.0", "reason": "build-script-executed", "...": "{...}" }, { "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.5.0", "reason": "compiler-message", "...": "{...}" }, { "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.5.0", "reason": "compiler-artifact", "...": "{...}" }, { "reason": "build-finished", "success": true } ] "#]] .is_json() .against_jsonlines(), ) .run(); p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [ "wycats@example.com" ], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#0.5.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "foo", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": "{...}", "version": "0.5.0" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo#0.5.0" } ], "root": "path+[ROOTURL]/foo#0.5.0" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_members": [ "path+[ROOTURL]/foo#0.5.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); } cargo-0.86.0/tests/testsuite/precise_pre_release.rs000064400000000000000000000145671046102023000205700ustar 00000000000000//! Tests for selecting pre-release versions with `update --precise`. use cargo_test_support::prelude::*; use cargo_test_support::{project, str}; #[cargo_test] fn requires_nightly_cargo() { cargo_test_support::registry::init(); for version in ["0.1.1", "0.1.2-pre.0"] { cargo_test_support::registry::Package::new("my-dependency", version).publish(); } let p = project() .file( "Cargo.toml", r#" [package] name = "package" [dependencies] my-dependency = "0.1.1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("update my-dependency --precise 0.1.2-pre.0") .with_status(101) // This error is suffering from #12579 but still demonstrates that updating to // a pre-release does not work on stable .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `my-dependency = "^0.1.1"` candidate versions found which didn't match: 0.1.2-pre.0 location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `package v0.0.0 ([ROOT]/foo)` if you are looking for the prerelease package it needs to be specified explicitly my-dependency = { version = "0.1.2-pre.0" } perhaps a crate was updated and forgotten to be re-vendored? "#]]) .run(); } #[cargo_test] fn update_pre_release() { cargo_test_support::registry::init(); for version in ["0.1.1", "0.1.2-pre.0"] { cargo_test_support::registry::Package::new("my-dependency", version).publish(); } let p = project() .file( "Cargo.toml", r#" [package] name = "package" [dependencies] my-dependency = "0.1.1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("update my-dependency --precise 0.1.2-pre.0 -Zunstable-options") .masquerade_as_nightly_cargo(&["precise-pre-release"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] my-dependency v0.1.1 -> v0.1.2-pre.0 "#]]) .run(); let lockfile = p.read_lockfile(); assert!(lockfile.contains("\nname = \"my-dependency\"\nversion = \"0.1.2-pre.0\"")); } #[cargo_test] fn pre_release_should_unmatched() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-dependency", "0.1.2").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "package" [dependencies] my-dependency = "0.1.2" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); let lockfile = p.read_lockfile(); assert!(lockfile.contains("\nname = \"my-dependency\"\nversion = \"0.1.2\"")); // 0.1.2-pre.0 < 0.1.2 so it doesn't match cargo_test_support::registry::Package::new("my-dependency", "0.1.2-pre.0").publish(); p.cargo("update -p my-dependency --precise 0.1.2-pre.0 -Zunstable-options") .masquerade_as_nightly_cargo(&["precise-pre-release"]) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `my-dependency = "^0.1.2"` candidate versions found which didn't match: 0.1.2-pre.0 location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `package v0.0.0 ([ROOT]/foo)` if you are looking for the prerelease package it needs to be specified explicitly my-dependency = { version = "0.1.2-pre.0" } perhaps a crate was updated and forgotten to be re-vendored? "#]]) .run(); cargo_test_support::registry::Package::new("my-dependency", "0.2.0-0").publish(); // 0.2.0-0 is the upper bound we exclude, so it doesn't match p.cargo("update -p my-dependency --precise 0.2.0-0 -Zunstable-options") .masquerade_as_nightly_cargo(&["precise-pre-release"]) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `my-dependency = "^0.1.2"` candidate versions found which didn't match: 0.2.0-0 location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `package v0.0.0 ([ROOT]/foo)` if you are looking for the prerelease package it needs to be specified explicitly my-dependency = { version = "0.2.0-0" } perhaps a crate was updated and forgotten to be re-vendored? "#]]) .run(); let lockfile = p.read_lockfile(); assert!(lockfile.contains("\nname = \"my-dependency\"\nversion = \"0.1.2\"")); } #[cargo_test] fn pre_release_should_matched() { cargo_test_support::registry::init(); cargo_test_support::registry::Package::new("my-dependency", "0.1.2").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "package" [dependencies] my-dependency = "0.1.2" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); let lockfile = p.read_lockfile(); assert!(lockfile.contains("\nname = \"my-dependency\"\nversion = \"0.1.2\"")); // Test upgrade // 0.1.3 is in the range, so it match cargo_test_support::registry::Package::new("my-dependency", "0.1.3").publish(); p.cargo("update -p my-dependency --precise 0.1.3 -Zunstable-options") .masquerade_as_nightly_cargo(&["precise-pre-release"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] my-dependency v0.1.2 -> v0.1.3 "#]]) .run(); let lockfile = p.read_lockfile(); assert!(lockfile.contains("\nname = \"my-dependency\"\nversion = \"0.1.3\"")); // Test downgrade // v0.1.3-pre.1 is in the range, so it match cargo_test_support::registry::Package::new("my-dependency", "0.1.3-pre.1").publish(); p.cargo("update -p my-dependency --precise 0.1.3-pre.1 -Zunstable-options") .masquerade_as_nightly_cargo(&["precise-pre-release"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNGRADING] my-dependency v0.1.3 -> v0.1.3-pre.1 "#]]) .run(); let lockfile = p.read_lockfile(); assert!(lockfile.contains("\nname = \"my-dependency\"\nversion = \"0.1.3-pre.1\"")); } cargo-0.86.0/tests/testsuite/proc_macro.rs000064400000000000000000000327771046102023000167170ustar 00000000000000//! Tests for proc-macros. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; #[cargo_test] fn probe_cfg_before_crate_type_discovery() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [target.'cfg(not(stage300))'.dependencies.noop] path = "../noop" "#, ) .file( "src/main.rs", r#" #[macro_use] extern crate noop; #[derive(Noop)] struct X; fn main() {} "#, ) .build(); let _noop = project() .at("noop") .file( "Cargo.toml", r#" [package] name = "noop" version = "0.0.1" edition = "2015" authors = [] [lib] proc-macro = true "#, ) .file( "src/lib.rs", r#" extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro_derive(Noop)] pub fn noop(_input: TokenStream) -> TokenStream { "".parse().unwrap() } "#, ) .build(); p.cargo("check").run(); } #[cargo_test] fn noop() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.noop] path = "../noop" "#, ) .file( "src/main.rs", r#" #[macro_use] extern crate noop; #[derive(Noop)] struct X; fn main() {} "#, ) .build(); let _noop = project() .at("noop") .file( "Cargo.toml", r#" [package] name = "noop" version = "0.0.1" edition = "2015" authors = [] [lib] proc-macro = true "#, ) .file( "src/lib.rs", r#" extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro_derive(Noop)] pub fn noop(_input: TokenStream) -> TokenStream { "".parse().unwrap() } "#, ) .build(); p.cargo("check").run(); p.cargo("check").run(); } #[cargo_test] fn impl_and_derive() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.transmogrify] path = "../transmogrify" "#, ) .file( "src/main.rs", r#" #[macro_use] extern crate transmogrify; trait ImplByTransmogrify { fn impl_by_transmogrify(&self) -> bool; } #[derive(Transmogrify, Debug)] struct X { success: bool } fn main() { let x = X::new(); assert!(x.impl_by_transmogrify()); println!("{:?}", x); } "#, ) .build(); let _transmogrify = project() .at("transmogrify") .file( "Cargo.toml", r#" [package] name = "transmogrify" version = "0.0.1" edition = "2015" authors = [] [lib] proc-macro = true "#, ) .file( "src/lib.rs", r#" extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro_derive(Transmogrify)] #[doc(hidden)] pub fn transmogrify(input: TokenStream) -> TokenStream { " impl X { fn new() -> Self { X { success: true } } } impl ImplByTransmogrify for X { fn impl_by_transmogrify(&self) -> bool { true } } ".parse().unwrap() } "#, ) .build(); p.cargo("build").run(); p.cargo("run") .with_stdout_data(str![[r#" X { success: true } "#]]) .run(); } #[cargo_test] fn proc_macro_doctest() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [lib] proc-macro = true "#, ) .file( "src/lib.rs", r#" #![crate_type = "proc-macro"] extern crate proc_macro; use proc_macro::TokenStream; /// ``` /// assert!(true); /// ``` #[proc_macro_derive(Bar)] pub fn derive(_input: TokenStream) -> TokenStream { "".parse().unwrap() } #[test] fn a() { assert!(true); } "#, ) .build(); foo.cargo("test") .with_stdout_data(str![[r#" running 1 test test a ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test src/lib.rs - derive (line 8) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn proc_macro_crate_type() { // Verify that `crate-type = ["proc-macro"]` is the same as `proc-macro = true` // and that everything, including rustdoc, works correctly. let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] pm = { path = "pm" } "#, ) .file( "src/lib.rs", r#" //! ``` //! use foo::THING; //! assert_eq!(THING, 123); //! ``` #[macro_use] extern crate pm; #[derive(MkItem)] pub struct S; #[cfg(test)] mod tests { use super::THING; #[test] fn it_works() { assert_eq!(THING, 123); } } "#, ) .file( "pm/Cargo.toml", r#" [package] name = "pm" version = "0.1.0" edition = "2015" [lib] crate-type = ["proc-macro"] "#, ) .file( "pm/src/lib.rs", r#" extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro_derive(MkItem)] pub fn mk_item(_input: TokenStream) -> TokenStream { "pub const THING: i32 = 123;".parse().unwrap() } "#, ) .build(); foo.cargo("test") .with_stdout_data(str![[r#" running 1 test test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test src/lib.rs - (line 2) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn proc_macro_crate_type_warning() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] crate-type = ["proc-macro"] "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") .with_stderr_data(str![[r#" [WARNING] library `foo` should only specify `proc-macro = true` instead of setting `crate-type` [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn lib_plugin_unused_key_warning() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] plugin = true "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") .with_stderr_data(str![[r#" [WARNING] unused manifest key: lib.plugin [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn proc_macro_crate_type_warning_plugin() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] crate-type = ["proc-macro"] "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") .with_stderr_data(str![[r#" [WARNING] library `foo` should only specify `proc-macro = true` instead of setting `crate-type` [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn proc_macro_crate_type_multiple() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [lib] crate-type = ["proc-macro", "rlib"] "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: cannot mix `proc-macro` crate type with others "#]]) .with_status(101) .run(); } #[cargo_test] fn proc_macro_extern_prelude() { // Check that proc_macro is in the extern prelude. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [lib] proc-macro = true "#, ) .file( "src/lib.rs", r#" use proc_macro::TokenStream; #[proc_macro] pub fn foo(input: TokenStream) -> TokenStream { "".parse().unwrap() } "#, ) .build(); p.cargo("test").run(); p.cargo("doc").run(); } #[cargo_test] fn proc_macro_built_once() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ['a', 'b'] resolver = "2" "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" [build-dependencies] the-macro = { path = '../the-macro' } "#, ) .file("a/build.rs", "fn main() {}") .file("a/src/main.rs", "fn main() {}") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2015" [dependencies] the-macro = { path = '../the-macro', features = ['a'] } "#, ) .file("b/src/main.rs", "fn main() {}") .file( "the-macro/Cargo.toml", r#" [package] name = "the-macro" version = "0.1.0" edition = "2015" [lib] proc-macro = true [features] a = [] "#, ) .file("the-macro/src/lib.rs", "") .build(); p.cargo("build --verbose") .with_stderr_data( str![[r#" [COMPILING] the-macro v0.1.0 ([ROOT]/foo/the-macro) [RUNNING] `rustc --crate-name the_macro [..]` [COMPILING] b v0.1.0 ([ROOT]/foo/b) [RUNNING] `rustc --crate-name b [..]` [COMPILING] a v0.1.0 ([ROOT]/foo/a) [RUNNING] `rustc --crate-name build_script_build [..]` [RUNNING] `[ROOT]/foo/target/debug/build/a-[HASH]/build-script-build` [RUNNING] `rustc --crate-name a [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } cargo-0.86.0/tests/testsuite/profile_config.rs000064400000000000000000000356711046102023000175540ustar 00000000000000//! Tests for profiles defined in config files. use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{basic_lib_manifest, paths, project, str}; use cargo_util_schemas::manifest::TomlDebugInfo; // TODO: this should be remove once -Zprofile-rustflags is stabilized #[cargo_test] fn rustflags_works_with_zflag() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [profile.dev] rustflags = ["-C", "link-dead-code=yes"] "#, ) .build(); p.cargo("check -v") .masquerade_as_nightly_cargo(&["profile-rustflags"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] config profile `dev` is not valid (defined in `[ROOT]/foo/.cargo/config.toml`) Caused by: feature `profile-rustflags` is required ... "#]]) .run(); p.cargo("check -v -Zprofile-rustflags") .masquerade_as_nightly_cargo(&["profile-rustflags"]) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -C link-dead-code=yes [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.change_file( ".cargo/config.toml", r#" [unstable] profile-rustflags = true [profile.dev] rustflags = ["-C", "link-dead-code=yes"] "#, ); p.cargo("check -v") .masquerade_as_nightly_cargo(&["profile-rustflags"]) .with_stderr_data(str![[r#" [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn profile_config_validate_warnings() { let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [profile.test] opt-level = 3 [profile.asdf] opt-level = 3 [profile.dev] bad-key = true [profile.dev.build-override] bad-key-bo = true [profile.dev.package.bar] bad-key-bar = true "#, ) .build(); p.cargo("build").with_stderr_data(str![[r#" [WARNING] unused config key `profile.dev.bad-key` in `[ROOT]/foo/.cargo/config.toml` [WARNING] unused config key `profile.dev.build-override.bad-key-bo` in `[ROOT]/foo/.cargo/config.toml` [WARNING] unused config key `profile.dev.package.bar.bad-key-bar` in `[ROOT]/foo/.cargo/config.toml` [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]].unordered()).run(); } #[cargo_test] fn profile_config_error_paths() { // Errors in config show where the error is located. let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [profile.dev] opt-level = 3 "#, ) .file( paths::home().join(".cargo/config.toml"), r#" [profile.dev] rpath = "foo" "#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] error in [ROOT]/foo/.cargo/config.toml: could not load config key `profile.dev` Caused by: error in [ROOT]/home/.cargo/config.toml: `profile.dev.rpath` expected true/false, but found a string "#]]) .run(); } #[cargo_test] fn profile_config_validate_errors() { let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [profile.dev.package.foo] panic = "abort" "#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] config profile `dev` is not valid (defined in `[ROOT]/foo/.cargo/config.toml`) Caused by: `panic` may not be specified in a `package` profile "#]]) .run(); } #[cargo_test] fn profile_config_syntax_errors() { let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [profile.dev] codegen-units = "foo" "#, ) .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] error in [ROOT]/foo/.cargo/config.toml: could not load config key `profile.dev` Caused by: error in [ROOT]/foo/.cargo/config.toml: `profile.dev.codegen-units` expected an integer, but found a string "#]]) .run(); } #[cargo_test] fn profile_config_override_spec_multiple() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = { path = "bar" } "#, ) .file( ".cargo/config.toml", r#" [profile.dev.package.bar] opt-level = 3 [profile.dev.package."bar:0.5.0"] opt-level = 3 "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file("bar/src/lib.rs", "") .build(); // Unfortunately this doesn't tell you which file, hopefully it's not too // much of a problem. p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [ERROR] multiple package overrides in profile `dev` match package `bar v0.5.0 ([ROOT]/foo/bar)` found package specs: bar, bar@0.5.0 "#]]) .run(); } #[cargo_test] fn profile_config_all_options() { // Ensure all profile options are supported. let p = project() .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [profile.release] opt-level = 1 debug = true debug-assertions = true overflow-checks = false rpath = true lto = true codegen-units = 2 panic = "abort" incremental = true "#, ) .build(); p.cargo("build --release -v") .env_remove("CARGO_INCREMENTAL") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -C opt-level=1 -C panic=abort -C lto[..]-C codegen-units=2 -C debuginfo=2 [..]-C debug-assertions=on -C overflow-checks=off [..]-C rpath --out-dir [ROOT]/foo/target/release/deps -C incremental=[ROOT]/foo/target/release/incremental[..]` [FINISHED] `release` profile [optimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn profile_config_override_precedence() { // Config values take precedence over manifest values. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = {path = "bar"} [profile.dev] codegen-units = 2 [profile.dev.package.bar] opt-level = 3 "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file("bar/src/lib.rs", "") .file( ".cargo/config.toml", r#" [profile.dev.package.bar] opt-level = 2 "#, ) .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar [..] -C opt-level=2[..]-C codegen-units=2 [..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]-C codegen-units=2 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn profile_config_no_warn_unknown_override() { let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [profile.dev.package.bar] codegen-units = 4 "#, ) .build(); p.cargo("build") .with_stderr_does_not_contain("[..]warning[..]") .run(); } #[cargo_test] fn profile_config_mixed_types() { let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [profile.dev] opt-level = 3 "#, ) .file( paths::home().join(".cargo/config.toml"), r#" [profile.dev] opt-level = 's' "#, ) .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc [..]-C opt-level=3 [..]` [FINISHED] `dev` profile [optimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn named_config_profile() { // Exercises config named profiles. // foo -> middle -> bar -> dev // middle exists in Cargo.toml, the others in .cargo/config.toml use super::config::GlobalContextBuilder; use cargo::core::compiler::CompileKind; use cargo::core::profiles::{Profiles, UnitFor}; use cargo::core::{PackageId, Workspace}; use cargo::util::interning::InternedString; use std::fs; paths::root().join(".cargo").mkdir_p(); fs::write( paths::root().join(".cargo/config.toml"), r#" [profile.foo] inherits = "middle" codegen-units = 2 [profile.foo.build-override] codegen-units = 6 [profile.foo.package.dep] codegen-units = 7 [profile.middle] inherits = "bar" codegen-units = 3 [profile.bar] inherits = "dev" codegen-units = 4 debug = 1 "#, ) .unwrap(); fs::write( paths::root().join("Cargo.toml"), r#" [workspace] [profile.middle] inherits = "bar" codegen-units = 1 opt-level = 1 [profile.middle.package.dep] overflow-checks = false [profile.foo.build-override] codegen-units = 5 debug-assertions = false [profile.foo.package.dep] codegen-units = 8 "#, ) .unwrap(); let gctx = GlobalContextBuilder::new().build(); let profile_name = InternedString::new("foo"); let ws = Workspace::new(&paths::root().join("Cargo.toml"), &gctx).unwrap(); let profiles = Profiles::new(&ws, profile_name).unwrap(); let crates_io = cargo::core::SourceId::crates_io(&gctx).unwrap(); let a_pkg = PackageId::try_new("a", "0.1.0", crates_io).unwrap(); let dep_pkg = PackageId::try_new("dep", "0.1.0", crates_io).unwrap(); // normal package let kind = CompileKind::Host; let p = profiles.get_profile(a_pkg, true, true, UnitFor::new_normal(kind), kind); 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.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) // build-override let bo = profiles.get_profile(a_pkg, true, true, UnitFor::new_host(false, kind), kind); 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.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 // package overrides let po = profiles.get_profile(dep_pkg, false, true, UnitFor::new_normal(kind), kind); 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.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 } #[cargo_test] fn named_env_profile() { // Environment variables used to define a named profile. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v --profile=other") .env("CARGO_PROFILE_OTHER_CODEGEN_UNITS", "1") .env("CARGO_PROFILE_OTHER_INHERITS", "dev") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..]-C codegen-units=1 [..]` [FINISHED] `other` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn test_with_dev_profile() { // The `test` profile inherits from `dev` for both local crates and // dependencies. Package::new("somedep", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] somedep = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("test --lib --no-run -v") .env("CARGO_PROFILE_DEV_DEBUG", "0") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] somedep v1.0.0 (registry `dummy-registry`) [COMPILING] somedep v1.0.0 [RUNNING] `rustc --crate-name somedep [..]` [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `test` profile [unoptimized] target(s) in [ELAPSED]s [EXECUTABLE] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` "#]]) .with_stdout_does_not_contain("[..] -C debuginfo=0[..]") .run(); } cargo-0.86.0/tests/testsuite/profile_custom.rs000064400000000000000000000422341046102023000176120ustar 00000000000000//! Tests for named profiles. use cargo_test_support::prelude::*; use cargo_test_support::{basic_lib_manifest, project, str}; #[cargo_test] fn inherits_on_release() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [profile.release] inherits = "dev" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `inherits` must not be specified in root profile `release` "#]]) .run(); } #[cargo_test] fn missing_inherits() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [profile.release-lto] codegen-units = 7 "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] profile `release-lto` is missing an `inherits` directive (`inherits` is required for all profiles except `dev` or `release`) "#]]) .run(); } #[cargo_test] fn invalid_profile_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [profile.'.release-lto'] inherits = "release" codegen-units = 7 "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid character `.` in profile name: `.release-lto`, allowed characters are letters, numbers, underscore, and hyphen --> Cargo.toml:8:26 | 8 | [profile.'.release-lto'] | ^^^^^^^^^^^^^^ | "#]]) .run(); } #[cargo_test] // We are currently uncertain if dir-name will ever be exposed to the user. // The code for it still roughly exists, but only for the internal profiles. // This test was kept in case we ever want to enable support for it again. #[ignore = "dir-name is disabled"] fn invalid_dir_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [profile.'release-lto'] inherits = "release" dir-name = ".subdir" codegen-units = 7 "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: Invalid character `.` in dir-name: `.subdir`", "#]]) .run(); } #[cargo_test] fn dir_name_disabled() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.release-lto] inherits = "release" dir-name = "lto" lto = true "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: dir-name="lto" in profile `release-lto` is not currently allowed, directory names are tied to the profile name for custom profiles "#]]) .run(); } #[cargo_test] fn invalid_inherits() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [profile.'release-lto'] inherits = ".release" codegen-units = 7 "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] profile `release-lto` inherits from `.release`, but that profile is not defined "#]]) .run(); } #[cargo_test] fn non_existent_inherits() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [profile.release-lto] codegen-units = 7 inherits = "non-existent" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] profile `release-lto` inherits from `non-existent`, but that profile is not defined "#]]) .run(); } #[cargo_test] fn self_inherits() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [profile.release-lto] codegen-units = 7 inherits = "release-lto" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] profile inheritance loop detected with profile `release-lto` inheriting `release-lto` "#]]) .run(); } #[cargo_test] fn inherits_loop() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [profile.release-lto] codegen-units = 7 inherits = "release-lto2" [profile.release-lto2] codegen-units = 7 inherits = "release-lto" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] profile inheritance loop detected with profile `release-lto2` inheriting `release-lto` "#]]) .run(); } #[cargo_test] fn overrides_with_custom() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] xxx = {path = "xxx"} yyy = {path = "yyy"} [profile.dev] codegen-units = 7 [profile.dev.package.xxx] codegen-units = 5 [profile.dev.package.yyy] codegen-units = 3 [profile.other] inherits = "dev" codegen-units = 2 [profile.other.package.yyy] codegen-units = 6 "#, ) .file("src/lib.rs", "") .file("xxx/Cargo.toml", &basic_lib_manifest("xxx")) .file("xxx/src/lib.rs", "") .file("yyy/Cargo.toml", &basic_lib_manifest("yyy")) .file("yyy/src/lib.rs", "") .build(); // profile overrides are inherited between profiles using inherits and have a // higher priority than profile options provided by custom profiles p.cargo("build -v") .with_stderr_data( str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] xxx v0.5.0 ([ROOT]/foo/xxx) [COMPILING] yyy v0.5.0 ([ROOT]/foo/yyy) [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name xxx [..] -C codegen-units=5 [..]` [RUNNING] `rustc --crate-name yyy [..] -C codegen-units=3 [..]` [RUNNING] `rustc --crate-name foo [..] -C codegen-units=7 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); // This also verifies that the custom profile names appears in the finished line. p.cargo("build --profile=other -v") .with_stderr_data( str![[r#" [COMPILING] xxx v0.5.0 ([ROOT]/foo/xxx) [COMPILING] yyy v0.5.0 ([ROOT]/foo/yyy) [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name xxx [..] -C codegen-units=5 [..]` [RUNNING] `rustc --crate-name yyy [..] -C codegen-units=6 [..]` [RUNNING] `rustc --crate-name foo [..] -C codegen-units=2 [..]` [FINISHED] `other` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn conflicting_usage() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --profile=dev --release") .with_status(1) .with_stderr_data(str![[r#" [ERROR] the argument '--profile ' cannot be used with '--release' Usage: cargo[EXE] build --profile For more information, try '--help'. "#]]) .run(); p.cargo("install --profile=release --debug") .with_status(1) .with_stderr_data(str![[r#" [ERROR] the argument '--profile ' cannot be used with '--debug' Usage: cargo[EXE] install --profile [CRATE[@]]... For more information, try '--help'. "#]]) .run(); p.cargo("check --profile=dev --release") .with_status(1) .with_stderr_data(str![[r#" [ERROR] the argument '--profile ' cannot be used with '--release' Usage: cargo[EXE] check --profile For more information, try '--help'. "#]]) .run(); } #[cargo_test] fn clean_custom_dirname() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [profile.other] inherits = "release" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --release") .with_stdout_data("") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("clean -p foo").run(); p.cargo("build --release") .with_stdout_data("") .with_stderr_data(str![[r#" [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("clean -p foo --release").run(); p.cargo("build --release") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build") .with_stdout_data("") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build --profile=other") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `other` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("clean").arg("--release").run(); // Make sure that 'other' was not cleaned assert!(p.build_dir().is_dir()); assert!(p.build_dir().join("debug").is_dir()); assert!(p.build_dir().join("other").is_dir()); assert!(!p.build_dir().join("release").is_dir()); // This should clean 'other' p.cargo("clean --profile=other") .with_stderr_data(str![[r#" [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .run(); assert!(p.build_dir().join("debug").is_dir()); assert!(!p.build_dir().join("other").is_dir()); } #[cargo_test] fn unknown_profile() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build --profile alpha") .with_stderr_data(str![[r#" [ERROR] profile `alpha` is not defined "#]]) .with_status(101) .run(); // Clean has a separate code path, need to check it too. p.cargo("clean --profile alpha") .with_stderr_data(str![[r#" [ERROR] profile `alpha` is not defined "#]]) .with_status(101) .run(); } #[cargo_test] fn reserved_profile_names() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.doc] opt-level = 1 "#, ) .file("src/lib.rs", "") .build(); p.cargo("build --profile=doc") .with_status(101) .with_stderr_data(str![[r#" [ERROR] profile `doc` is reserved and not allowed to be explicitly specified "#]]) .run(); // Not an exhaustive list, just a sample. for name in ["build", "cargo", "check", "rustc", "CaRgO_startswith"] { p.cargo(&format!("build --profile={}", name)) .with_status(101) .with_stderr_data(&format!( "\ [ERROR] profile name `{}` is reserved Please choose a different name. See https://doc.rust-lang.org/cargo/reference/profiles.html for more on configuring profiles. ", name )) .run(); } for name in ["build", "check", "cargo", "rustc", "CaRgO_startswith"] { p.change_file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.{}] opt-level = 1 "#, name ), ); let highlight = "^".repeat(name.len()); p.cargo("build") .with_status(101) .with_stderr_data(&format!( "\ [ERROR] profile name `{name}` is reserved Please choose a different name. See https://doc.rust-lang.org/cargo/reference/profiles.html for more on configuring profiles. --> Cargo.toml:7:30 | 7 | [profile.{name}] | {highlight} | " )) .run(); } p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [profile.debug] debug = 1 inherits = "dev" "#, ); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] profile name `debug` is reserved To configure the default development profile, use the name `dev` as in [profile.dev] See https://doc.rust-lang.org/cargo/reference/profiles.html for more on configuring profiles. --> Cargo.toml:8:25 | 8 | [profile.debug] | ^^^^^ | "#]]) .run(); } #[cargo_test] fn legacy_commands_support_custom() { // These commands have had `--profile` before custom named profiles. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.super-dev] codegen-units = 3 inherits = "dev" "#, ) .file("src/lib.rs", "") .build(); for command in ["rustc", "fix", "check"] { let mut pb = p.cargo(command); if command == "fix" { pb.arg("--allow-no-vcs"); } pb.arg("--profile=super-dev") .arg("-v") .with_stderr_data(str![ r#" ... [RUNNING] [..]codegen-units=3[..] ... "# ]) .run(); p.build_dir().rm_rf(); } } #[cargo_test] fn legacy_rustc() { // `cargo rustc` historically has supported dev/test/bench/check // other profiles are covered in check::rustc_check let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.dev] codegen-units = 3 "#, ) .file("src/lib.rs", "") .build(); p.cargo("rustc --profile dev -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]-C codegen-units=3[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/profile_overrides.rs000064400000000000000000000404151046102023000203010ustar 00000000000000//! Tests for profile overrides (build-override and per-package overrides). use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{basic_lib_manifest, basic_manifest, project, str}; #[cargo_test] fn profile_override_basic() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = {path = "bar"} [profile.dev] opt-level = 1 [profile.dev.package.bar] opt-level = 3 "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file("bar/src/lib.rs", "") .build(); p.cargo("check -v") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.5.0 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar [..] -C opt-level=3 [..]` [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -C opt-level=1 [..]` [FINISHED] `dev` profile [optimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn profile_override_warnings() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = {path = "bar"} [profile.dev.package.bart] opt-level = 3 [profile.dev.package.no-suggestion] opt-level = 3 [profile.dev.package."bar:1.2.3"] opt-level = 3 "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file("bar/src/lib.rs", "") .build(); p.cargo("build").with_stderr_data(str![[r#" ... [WARNING] profile package spec `bar@1.2.3` in profile `dev` has a version or URL that does not match any of the packages: bar v0.5.0 ([ROOT]/foo/bar) [WARNING] profile package spec `bart` in profile `dev` did not match any packages Did you mean `bar`? [WARNING] profile package spec `no-suggestion` in profile `dev` did not match any packages [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn profile_override_bad_settings() { let bad_values = [ ( "panic = \"abort\"", "`panic` may not be specified in a `package` profile", ), ( "lto = true", "`lto` may not be specified in a `package` profile", ), ( "rpath = true", "`rpath` may not be specified in a `package` profile", ), ("package = {}", "package-specific profiles cannot be nested"), ]; for &(snippet, expected) in bad_values.iter() { let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = {{path = "bar"}} [profile.dev.package.bar] {} "#, snippet ), ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file("bar/src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(format!( "\ ... Caused by:\n {} ", expected )) .run(); } } #[cargo_test] fn profile_override_hierarchy() { // Test that the precedence rules are correct for different types. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["m1", "m2", "m3"] [profile.dev] codegen-units = 1 [profile.dev.package.m2] codegen-units = 2 [profile.dev.package."*"] codegen-units = 3 [profile.dev.build-override] codegen-units = 4 "#, ) // m1 .file( "m1/Cargo.toml", r#" [package] name = "m1" version = "0.0.1" edition = "2015" [dependencies] m2 = { path = "../m2" } dep = { path = "../../dep" } "#, ) .file("m1/src/lib.rs", "extern crate m2; extern crate dep;") .file("m1/build.rs", "fn main() {}") // m2 .file( "m2/Cargo.toml", r#" [package] name = "m2" version = "0.0.1" edition = "2015" [dependencies] m3 = { path = "../m3" } [build-dependencies] m3 = { path = "../m3" } dep = { path = "../../dep" } "#, ) .file("m2/src/lib.rs", "extern crate m3;") .file( "m2/build.rs", "extern crate m3; extern crate dep; fn main() {}", ) // m3 .file("m3/Cargo.toml", &basic_lib_manifest("m3")) .file("m3/src/lib.rs", "") .build(); // dep (outside of workspace) let _dep = project() .at("dep") .file("Cargo.toml", &basic_lib_manifest("dep")) .file("src/lib.rs", "") .build(); // Profiles should be: // m3: 4 (as build.rs dependency) // m3: 1 (as [profile.dev] as workspace member) // dep: 3 (as [profile.dev.package."*"] as non-workspace member) // m1 build.rs: 4 (as [profile.dev.build-override]) // m2 build.rs: 2 (as [profile.dev.package.m2]) // m2: 2 (as [profile.dev.package.m2]) // m1: 1 (as [profile.dev]) p.cargo("build -v") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] m3 v0.5.0 ([ROOT]/foo/m3) [COMPILING] dep v0.5.0 ([ROOT]/dep) [RUNNING] `rustc --crate-name m3 --edition=2015 m3/src/lib.rs [..] --crate-type lib --emit=[..]link[..]-C codegen-units=4 [..]` [RUNNING] `rustc --crate-name dep [..][ROOT]/dep/src/lib.rs [..] --crate-type lib --emit=[..]link[..]-C codegen-units=3 [..]` [RUNNING] `rustc --crate-name m3 --edition=2015 m3/src/lib.rs [..] --crate-type lib --emit=[..]link[..]-C codegen-units=1 [..]` [RUNNING] `rustc --crate-name build_script_build --edition=2015 m1/build.rs [..] --crate-type bin --emit=[..]link[..]-C codegen-units=4 [..]` [COMPILING] m2 v0.0.1 ([ROOT]/foo/m2) [RUNNING] `rustc --crate-name build_script_build --edition=2015 m2/build.rs [..] --crate-type bin --emit=[..]link[..]-C codegen-units=2 [..]` [RUNNING] `[ROOT]/foo/target/debug/build/m1-[HASH]/build-script-build` [RUNNING] `[ROOT]/foo/target/debug/build/m2-[HASH]/build-script-build` [RUNNING] `rustc --crate-name m2 --edition=2015 m2/src/lib.rs [..] --crate-type lib --emit=[..]link[..]-C codegen-units=2 [..]` [COMPILING] m1 v0.0.1 ([ROOT]/foo/m1) [RUNNING] `rustc --crate-name m1 --edition=2015 m1/src/lib.rs [..] --crate-type lib --emit=[..]link[..]-C codegen-units=1 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]].unordered()) .run(); } #[cargo_test] fn profile_override_spec_multiple() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = { path = "bar" } [profile.dev.package.bar] opt-level = 3 [profile.dev.package."bar:0.5.0"] opt-level = 3 "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file("bar/src/lib.rs", "") .build(); p.cargo("check -v") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] multiple package overrides in profile `dev` match package `bar v0.5.0 ([ROOT]/foo/bar)` found package specs: bar, bar@0.5.0 "#]]) .run(); } #[cargo_test] fn profile_override_spec_with_version() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = { path = "bar" } [profile.dev.package."bar:0.5.0"] codegen-units = 2 "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file("bar/src/lib.rs", "") .build(); p.cargo("check -v") .with_stderr_data(str![[r#" ... [CHECKING] bar v0.5.0 ([ROOT]/foo/bar) [RUNNING] `rustc [..]bar/src/lib.rs [..] -C codegen-units=2 [..]` ... "#]]) .run(); } #[cargo_test] fn profile_override_spec_with_partial_version() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = { path = "bar" } [profile.dev.package."bar:0.5"] codegen-units = 2 "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file("bar/src/lib.rs", "") .build(); p.cargo("check -v") .with_stderr_data(str![[r#" ... [CHECKING] bar v0.5.0 ([ROOT]/foo/bar) [RUNNING] `rustc [..]bar/src/lib.rs [..] -C codegen-units=2 [..]` ... "#]]) .run(); } #[cargo_test] fn profile_override_spec() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["m1", "m2"] [profile.dev.package."dep:1.0.0"] codegen-units = 1 [profile.dev.package."dep:2.0.0"] codegen-units = 2 "#, ) // m1 .file( "m1/Cargo.toml", r#" [package] name = "m1" version = "0.0.1" edition = "2015" [dependencies] dep = { path = "../../dep1" } "#, ) .file("m1/src/lib.rs", "extern crate dep;") // m2 .file( "m2/Cargo.toml", r#" [package] name = "m2" version = "0.0.1" edition = "2015" [dependencies] dep = {path = "../../dep2" } "#, ) .file("m2/src/lib.rs", "extern crate dep;") .build(); project() .at("dep1") .file("Cargo.toml", &basic_manifest("dep", "1.0.0")) .file("src/lib.rs", "") .build(); project() .at("dep2") .file("Cargo.toml", &basic_manifest("dep", "2.0.0")) .file("src/lib.rs", "") .build(); p.cargo("check -v") .with_stderr_data( str![[r#" ... [RUNNING] `rustc [..][ROOT]/dep1/src/lib.rs [..] -C codegen-units=1 [..]` [RUNNING] `rustc [..][ROOT]/dep2/src/lib.rs [..] -C codegen-units=2 [..]` ... "#]] .unordered(), ) .run(); } #[cargo_test] fn override_proc_macro() { Package::new("shared", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] shared = "1.0" pm = {path = "pm"} [profile.dev.build-override] codegen-units = 4 "#, ) .file("src/lib.rs", r#"pm::eat!{}"#) .file( "pm/Cargo.toml", r#" [package] name = "pm" version = "0.1.0" edition = "2015" [lib] proc-macro = true [dependencies] shared = "1.0" "#, ) .file( "pm/src/lib.rs", r#" extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro] pub fn eat(_item: TokenStream) -> TokenStream { "".parse().unwrap() } "#, ) .build(); p.cargo("check -v") // Shared built for the proc-macro. .with_stderr_data(str![[r#" ... [RUNNING] `rustc [..]--crate-name shared [..] -C codegen-units=4[..]` ... [RUNNING] `rustc [..]--crate-name pm [..] -C codegen-units=4[..]` ... "#]]) // Shared built for the library. .with_stderr_line_without( &["[RUNNING] `rustc --crate-name shared --edition=2015"], &["-C codegen-units"], ) .with_stderr_line_without( &["[RUNNING] `rustc [..]--crate-name foo"], &["-C codegen-units"], ) .run(); } #[cargo_test] fn no_warning_ws() { // https://github.com/rust-lang/cargo/issues/7378, avoid warnings in a workspace. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] [profile.dev.package.a] codegen-units = 3 "#, ) .file("a/Cargo.toml", &basic_manifest("a", "0.1.0")) .file("a/src/lib.rs", "") .file("b/Cargo.toml", &basic_manifest("b", "0.1.0")) .file("b/src/lib.rs", "") .build(); p.cargo("check -p b") .with_stderr_data(str![[r#" [CHECKING] b v0.1.0 ([ROOT]/foo/b) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_override_shared() { // A dependency with a build script that is shared with a build // dependency, using different profile settings. That is: // // foo DEBUG=2 // β”œβ”€β”€ common DEBUG=2 // β”‚ └── common Run build.rs DEBUG=2 // β”‚ └── common build.rs DEBUG=0 (build_override) // └── foo Run build.rs DEBUG=2 // └── foo build.rs DEBUG=0 (build_override) // └── common DEBUG=0 (build_override) // └── common Run build.rs DEBUG=0 (build_override) // └── common build.rs DEBUG=0 (build_override) // // The key part here is that `common` RunCustomBuild is run twice, once // with DEBUG=2 (as a dependency of foo) and once with DEBUG=0 (as a // build-dependency of foo's build script). Package::new("common", "1.0.0") .file( "build.rs", r#" fn main() { if std::env::var("DEBUG").unwrap() != "false" { println!("cargo::rustc-cfg=foo_debug"); } else { println!("cargo::rustc-cfg=foo_release"); } } "#, ) .file( "src/lib.rs", r#" pub fn foo() -> u32 { if cfg!(foo_debug) { assert!(cfg!(debug_assertions)); 1 } else if cfg!(foo_release) { assert!(!cfg!(debug_assertions)); 2 } else { panic!("not set"); } } "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [build-dependencies] common = "1.0" [dependencies] common = "1.0" [profile.dev.build-override] debug = 0 debug-assertions = false "#, ) .file( "build.rs", r#" fn main() { assert_eq!(common::foo(), 2); } "#, ) .file( "src/main.rs", r#" fn main() { assert_eq!(common::foo(), 1); } "#, ) .build(); p.cargo("run").run(); } cargo-0.86.0/tests/testsuite/profile_targets.rs000064400000000000000000001141321046102023000177460ustar 00000000000000//! Tests for checking exactly how profiles correspond with each unit. For //! example, the `test` profile applying to test targets, but not other //! targets, etc. use cargo_test_support::prelude::*; use cargo_test_support::{basic_manifest, project, str, Project}; fn all_target_project() -> Project { // This abuses the `codegen-units` setting so that we can verify exactly // which profile is used for each compiler invocation. project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = { path = "bar" } [build-dependencies] bdep = { path = "bdep" } [profile.dev] codegen-units = 1 panic = "abort" [profile.release] codegen-units = 2 panic = "abort" [profile.test] codegen-units = 3 [profile.bench] codegen-units = 4 [profile.dev.build-override] codegen-units = 5 [profile.release.build-override] codegen-units = 6 "#, ) .file("src/lib.rs", "extern crate bar;") .file("src/main.rs", "extern crate foo; fn main() {}") .file("examples/ex1.rs", "extern crate foo; fn main() {}") .file("tests/test1.rs", "extern crate foo;") .file("benches/bench1.rs", "extern crate foo;") .file( "build.rs", r#" extern crate bdep; fn main() { eprintln!("foo custom build PROFILE={} DEBUG={} OPT_LEVEL={}", std::env::var("PROFILE").unwrap(), std::env::var("DEBUG").unwrap(), std::env::var("OPT_LEVEL").unwrap(), ); } "#, ) // `bar` package. .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") // `bdep` package. .file( "bdep/Cargo.toml", r#" [package] name = "bdep" version = "0.0.1" edition = "2015" [dependencies] bar = { path = "../bar" } "#, ) .file("bdep/src/lib.rs", "extern crate bar;") .build() } #[cargo_test] fn profile_selection_build() { let p = all_target_project(); // `build` // NOTES: // - bdep `panic` is not set because it thinks `build.rs` is a plugin. // - build_script_build is built without panic because it thinks `build.rs` is a plugin. // - We make sure that the build dependencies bar, bdep, and build.rs // are built with debuginfo=0. p.cargo("build -vv") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..] [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..] [COMPILING] bdep v0.0.1 ([ROOT]/foo/bdep) [RUNNING] `[..] rustc --crate-name bdep --edition=2015 bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..] [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 [..] [RUNNING] `[..][ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [foo 0.0.1] foo custom build PROFILE=debug DEBUG=true OPT_LEVEL=0 [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..] [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]].unordered()) .with_stderr_does_not_contain("[..] -C debuginfo=0[..]") .run(); p.cargo("build -vv") .with_stderr_data( str![[r#" [FRESH] bdep v0.0.1 ([ROOT]/foo/bdep) [FRESH] bar v0.0.1 ([ROOT]/foo/bar) [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn profile_selection_build_release() { let p = all_target_project(); // `build --release` p.cargo("build --release -vv") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C opt-level=3 -C panic=abort[..]-C codegen-units=2 [..] [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=6 [..] [COMPILING] bdep v0.0.1 ([ROOT]/foo/bdep) [RUNNING] `[..] rustc --crate-name bdep --edition=2015 bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=6 [..] [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=6 [..] [RUNNING] `[..][ROOT]/foo/target/release/build/foo-[HASH]/build-script-build` [foo 0.0.1] foo custom build PROFILE=release DEBUG=false OPT_LEVEL=3 [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link -C opt-level=3 -C panic=abort[..]-C codegen-units=2 [..] [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]link -C opt-level=3 -C panic=abort[..]-C codegen-units=2 [..] [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]].unordered()) .run(); p.cargo("build --release -vv") .with_stderr_data( str![[r#" [FRESH] bar v0.0.1 ([ROOT]/foo/bar) [FRESH] bdep v0.0.1 ([ROOT]/foo/bdep) [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn profile_selection_build_all_targets() { let p = all_target_project(); // `build` // NOTES: // - bdep `panic` is not set because it thinks `build.rs` is a plugin. // - build_script_build is built without panic because it thinks // `build.rs` is a plugin. // - 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; 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 // --- ------ ------- ------ // bar lib dev For foo-bin // bar lib dev-panic For tests/benches and bdep // bdep lib dev-panic For foo build.rs // foo custom dev-panic // // - `foo` target list is: // Target Profile Mode // ------ ------- ---- // lib dev+panic build (a normal lib target) // lib dev-panic build (used by tests/benches) // lib dev dev // test dev dev // bench dev dev // bin dev dev // bin dev build // example dev build p.cargo("build --all-targets -vv") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C embed-bitcode=[..]-C codegen-units=1 -C debuginfo=2 [..]` [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C panic=abort -C embed-bitcode=[..]-C codegen-units=1 -C debuginfo=2 [..]` [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C embed-bitcode=[..]-C codegen-units=5 [..]` [COMPILING] bdep v0.0.1 ([ROOT]/foo/bdep) [RUNNING] `[..] rustc --crate-name bdep --edition=2015 bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 [..]` [RUNNING] `[..][ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [foo 0.0.1] foo custom build PROFILE=debug DEBUG=true OPT_LEVEL=0 [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]` [RUNNING] `[..] rustc --crate-name test1 --edition=2015 tests/test1.rs [..]--emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]` [RUNNING] `[..] rustc --crate-name bench1 --edition=2015 benches/bench1.rs [..]--emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..]` [RUNNING] `[..] rustc --crate-name ex1 --edition=2015 examples/ex1.rs [..]--crate-type bin --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]].unordered()) .with_stderr_does_not_contain("[..] -C debuginfo=0[..]") .run(); p.cargo("build -vv") .with_stderr_data( str![[r#" [FRESH] bar v0.0.1 ([ROOT]/foo/bar) [FRESH] bdep v0.0.1 ([ROOT]/foo/bdep) [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn profile_selection_build_all_targets_release() { let p = all_target_project(); // `build --all-targets --release` // NOTES: // - bdep `panic` is not set because it thinks `build.rs` is a plugin. // - bar compiled twice. It tries with and without panic, but the "is a // plugin" logic is forcing it to be cleared. // - build_script_build is built without panic because it thinks // `build.rs` is a plugin. // - build_script_build is being run two times. Once for the `dev` and // `test` targets, once for the `bench` targets. // TODO: "PROFILE" says debug both times, though! // // - Dependency profiles: // Pkg Target Profile Reason // --- ------ ------- ------ // bar lib release For foo-bin // bar lib release-panic For tests/benches and bdep // bdep lib release-panic For foo build.rs // foo custom release-panic // // - `foo` target list is: // Target Profile Mode // ------ ------- ---- // lib release+panic build (a normal lib target) // lib release-panic build (used by tests/benches) // lib release test (bench/test de-duped) // test release test // bench release test // bin release test (bench/test de-duped) // bin release build // example release build p.cargo("build --all-targets --release -vv") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C opt-level=3 -C embed-bitcode=[..]-C codegen-units=2 [..]` [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C opt-level=3 -C panic=abort -C embed-bitcode=[..]-C codegen-units=2 [..]` [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C embed-bitcode=[..]-C codegen-units=6 [..]` [COMPILING] bdep v0.0.1 ([ROOT]/foo/bdep) [RUNNING] `[..] rustc --crate-name bdep --edition=2015 bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=6 [..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=6 [..]` [RUNNING] `[..][ROOT]/foo/target/release/build/foo-[HASH]/build-script-build` [foo 0.0.1] foo custom build PROFILE=release DEBUG=false OPT_LEVEL=3 [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link -C opt-level=3 -C panic=abort[..]-C codegen-units=2 [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--emit=[..]link -C opt-level=3[..]-C codegen-units=2 --test [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link -C opt-level=3[..]-C codegen-units=2 [..]` [RUNNING] `[..] rustc --crate-name test1 --edition=2015 tests/test1.rs [..]--emit=[..]link -C opt-level=3[..]-C codegen-units=2 --test [..]` [RUNNING] `[..] rustc --crate-name bench1 --edition=2015 benches/bench1.rs [..]--emit=[..]link -C opt-level=3[..]-C codegen-units=2 --test [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--emit=[..]link -C opt-level=3[..]-C codegen-units=2 --test [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]link -C opt-level=3 -C panic=abort[..]-C codegen-units=2 [..]` [RUNNING] `[..] rustc --crate-name ex1 --edition=2015 examples/ex1.rs [..]--crate-type bin --emit=[..]link -C opt-level=3 -C panic=abort[..]-C codegen-units=2 [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]].unordered()) .run(); p.cargo("build --all-targets --release -vv") .with_stderr_data( str![[r#" [FRESH] bar v0.0.1 ([ROOT]/foo/bar) [FRESH] bdep v0.0.1 ([ROOT]/foo/bdep) [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn profile_selection_test() { let p = all_target_project(); // `test` // NOTES: // - Dependency profiles: // Pkg Target Profile Reason // --- ------ ------- ------ // bar lib test For foo-bin // bar lib test-panic For tests/benches and bdep // bdep lib test-panic For foo build.rs // foo custom test-panic // // - `foo` target list is: // Target Profile Mode // ------ ------- ---- // lib test-panic build (for tests) // lib test build (for bins) // lib test test // test test test // example test-panic build // bin test test // bin test build // p.cargo("test -vv") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C embed-bitcode=[..]-C codegen-units=3 -C debuginfo=2 [..]` [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C embed-bitcode=[..]-C codegen-units=5 [..]` [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C panic=abort[..]-C embed-bitcode=[..]-C codegen-units=3 -C debuginfo=2 [..]` [COMPILING] bdep v0.0.1 ([ROOT]/foo/bdep) [RUNNING] `[..] rustc --crate-name bdep --edition=2015 bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 [..]` [RUNNING] `[..][ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [foo 0.0.1] foo custom build PROFILE=debug DEBUG=true OPT_LEVEL=0 [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link -C panic=abort[..]-C codegen-units=3 -C debuginfo=2 [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=3 -C debuginfo=2 [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--emit=[..]link[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]` [RUNNING] `[..] rustc --crate-name test1 --edition=2015 tests/test1.rs [..]--emit=[..]link[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]` [RUNNING] `[..] rustc --crate-name ex1 --edition=2015 examples/ex1.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=3 -C debuginfo=2 [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--emit=[..]link[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]link -C panic=abort[..]-C codegen-units=3 -C debuginfo=2 [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[..][ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [RUNNING] `[..][ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [RUNNING] `[..][ROOT]/foo/target/debug/deps/test1-[HASH][EXE]` [DOCTEST] foo [RUNNING] `[..] rustdoc [..]--test [..] "#]].unordered()) .run(); p.cargo("test -vv") .with_stderr_data( str![[r#" [FRESH] bdep v0.0.1 ([ROOT]/foo/bdep) [FRESH] bar v0.0.1 ([ROOT]/foo/bar) [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[..][ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [RUNNING] `[..][ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [RUNNING] `[..][ROOT]/foo/target/debug/deps/test1-[HASH][EXE]` [DOCTEST] foo [RUNNING] `[..] rustdoc [..]--test [..] "#]] .unordered(), ) .run(); } #[cargo_test] fn profile_selection_test_release() { let p = all_target_project(); // `test --release` // NOTES: // - Dependency profiles: // Pkg Target Profile Reason // --- ------ ------- ------ // bar lib release For foo-bin // bar lib release-panic For tests/benches and bdep // bdep lib release-panic For foo build.rs // foo custom release-panic // // - `foo` target list is: // Target Profile Mode // ------ ------- ---- // lib release-panic build (for tests) // lib release build (for bins) // lib release test // test release test // example release-panic build // bin release test // bin release build // p.cargo("test --release -vv") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=6 [..]` [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C opt-level=3 -C panic=abort[..]-C codegen-units=2 [..]` [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C opt-level=3[..]-C codegen-units=2[..]` [COMPILING] bdep v0.0.1 ([ROOT]/foo/bdep) [RUNNING] `[..] rustc --crate-name bdep --edition=2015 bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=6 [..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=6 [..]` [RUNNING] `[..][ROOT]/foo/target/release/build/foo-[HASH]/build-script-build` [foo 0.0.1] foo custom build PROFILE=release DEBUG=false OPT_LEVEL=3 [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link -C opt-level=3 -C panic=abort[..]-C codegen-units=2 [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link -C opt-level=3[..]-C codegen-units=2 [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--emit=[..]link -C opt-level=3[..]-C codegen-units=2 --test [..]` [RUNNING] `[..] rustc --crate-name test1 --edition=2015 tests/test1.rs [..]--emit=[..]link -C opt-level=3[..]-C codegen-units=2 --test [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--emit=[..]link -C opt-level=3[..]-C codegen-units=2 --test [..]` [RUNNING] `[..] rustc --crate-name ex1 --edition=2015 examples/ex1.rs [..]--crate-type bin --emit=[..]link -C opt-level=3[..]-C codegen-units=2 [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]link -C opt-level=3 -C panic=abort[..]-C codegen-units=2 [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[..][ROOT]/foo/target/release/deps/foo-[HASH][EXE]` [RUNNING] `[..][ROOT]/foo/target/release/deps/foo-[HASH][EXE]` [RUNNING] `[..][ROOT]/foo/target/release/deps/test1-[HASH][EXE]` [DOCTEST] foo [RUNNING] `[..] rustdoc [..]--test [..]` "#]].unordered()) .run(); p.cargo("test --release -vv") .with_stderr_data( str![[r#" [FRESH] bdep v0.0.1 ([ROOT]/foo/bdep) [FRESH] bar v0.0.1 ([ROOT]/foo/bar) [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[..][ROOT]/foo/target/release/deps/foo-[HASH][EXE]` [RUNNING] `[..][ROOT]/foo/target/release/deps/foo-[HASH][EXE]` [RUNNING] `[..][ROOT]/foo/target/release/deps/test1-[HASH][EXE]` [DOCTEST] foo [RUNNING] `[..] rustdoc [..]--test [..] "#]] .unordered(), ) .run(); } #[cargo_test] fn profile_selection_bench() { let p = all_target_project(); // `bench` // NOTES: // - Dependency profiles: // Pkg Target Profile Reason // --- ------ ------- ------ // bar lib bench For foo-bin // bar lib bench-panic For tests/benches and bdep // bdep lib bench-panic For foo build.rs // foo custom bench-panic // // - `foo` target list is: // Target Profile Mode // ------ ------- ---- // lib bench-panic build (for benches) // lib bench build (for bins) // lib bench test(bench) // bench bench test(bench) // bin bench test(bench) // bin bench build // p.cargo("bench -vv") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C opt-level=3 -C embed-bitcode=[..]-C codegen-units=4 [..]` [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C opt-level=3 -C panic=abort -C embed-bitcode=[..]-C codegen-units=4 [..]` [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C embed-bitcode=[..]-C codegen-units=6 [..]` [COMPILING] bdep v0.0.1 ([ROOT]/foo/bdep) [RUNNING] `[..] rustc --crate-name bdep --edition=2015 bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=6 [..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=6 [..]` [RUNNING] `[..][ROOT]/foo/target/release/build/foo-[HASH]/build-script-build` [foo 0.0.1] foo custom build PROFILE=release DEBUG=false OPT_LEVEL=3 [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link -C opt-level=3 -C panic=abort[..]-C codegen-units=4 [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link -C opt-level=3[..]-C codegen-units=4 [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--emit=[..]link -C opt-level=3[..]-C codegen-units=4 --test [..]` [RUNNING] `[..] rustc --crate-name bench1 --edition=2015 benches/bench1.rs [..]--emit=[..]link -C opt-level=3[..]-C codegen-units=4 --test [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--emit=[..]link -C opt-level=3[..]-C codegen-units=4 --test [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]link -C opt-level=3 -C panic=abort[..]-C codegen-units=4 [..]` [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[..][ROOT]/foo/target/release/deps/foo-[HASH][EXE] --bench` [RUNNING] `[..][ROOT]/foo/target/release/deps/foo-[HASH][EXE] --bench` [RUNNING] `[..][ROOT]/foo/target/release/deps/bench1-[HASH][EXE] --bench` "#]].unordered()) .run(); p.cargo("bench -vv") .with_stderr_data( str![[r#" [FRESH] bdep v0.0.1 ([ROOT]/foo/bdep) [FRESH] bar v0.0.1 ([ROOT]/foo/bar) [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[..][ROOT]/foo/target/release/deps/foo-[HASH][EXE] --bench` [RUNNING] `[..][ROOT]/foo/target/release/deps/foo-[HASH][EXE] --bench` [RUNNING] `[..][ROOT]/foo/target/release/deps/bench1-[HASH][EXE] --bench` "#]] .unordered(), ) .run(); } #[cargo_test] fn profile_selection_check_all_targets() { let p = all_target_project(); // `check` // NOTES: // - Dependency profiles: // Pkg Target Profile Action Reason // --- ------ ------- ------ ------ // bar lib dev* link For bdep // bar lib dev-panic metadata For tests/benches // bar lib dev metadata For lib/bins // bdep lib dev* link For foo build.rs // foo custom dev* link For build.rs // // `*` = wants panic, but it is cleared when args are built. // // - foo target list is: // Target Profile Mode // ------ ------- ---- // lib dev check // lib dev-panic check (for tests/benches) // lib dev-panic check-test (checking lib as a unittest) // example dev check // test dev-panic check-test // bench dev-panic check-test // bin dev check // bin dev-panic check-test (checking bin as a unittest) // p.cargo("check --all-targets -vv") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C embed-bitcode=[..]-C codegen-units=5 [..]` [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]metadata -C embed-bitcode=[..]-C codegen-units=1 -C debuginfo=2 [..]` [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]metadata -C panic=abort -C embed-bitcode=[..]-C codegen-units=1 -C debuginfo=2 [..]` [COMPILING] bdep v0.0.1 ([ROOT]/foo/bdep) [RUNNING] `[..] rustc --crate-name bdep --edition=2015 bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 [..]` [RUNNING] `[..][ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [foo 0.0.1] foo custom build PROFILE=debug DEBUG=true OPT_LEVEL=0 [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]metadata -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]metadata[..]-C codegen-units=1 -C debuginfo=2 [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--emit=[..]metadata[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]` [RUNNING] `[..] rustc --crate-name test1 --edition=2015 tests/test1.rs [..]--emit=[..]metadata[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--emit=[..]metadata[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]` [RUNNING] `[..] rustc --crate-name bench1 --edition=2015 benches/bench1.rs [..]--emit=[..]metadata[..]-C codegen-units=1 -C debuginfo=2 [..]--test [..]` [RUNNING] `[..] rustc --crate-name ex1 --edition=2015 examples/ex1.rs [..]--crate-type bin --emit=[..]metadata -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]metadata -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]].unordered()) .run(); // Starting with Rust 1.27, rustc emits `rmeta` files for bins, so // everything should be completely fresh. Previously, bins were being // rechecked. // See PR rust-lang/rust#49289 and issue rust-lang/cargo#3624. p.cargo("check --all-targets -vv") .with_stderr_data( str![[r#" [FRESH] bdep v0.0.1 ([ROOT]/foo/bdep) [FRESH] bar v0.0.1 ([ROOT]/foo/bar) [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn profile_selection_check_all_targets_release() { let p = all_target_project(); // `check --release` // See issue rust-lang/cargo#5218. // This is a pretty straightforward variant of // `profile_selection_check_all_targets` that uses `release` instead of // `dev` for all targets. p.cargo("check --all-targets --release -vv") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=6 [..] [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]metadata -C opt-level=3 -C panic=abort[..]-C codegen-units=2 [..] [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]metadata -C opt-level=3[..]-C codegen-units=2 [..] [COMPILING] bdep v0.0.1 ([ROOT]/foo/bdep) [RUNNING] `[..] rustc --crate-name bdep --edition=2015 bdep/src/lib.rs [..]--crate-type lib --emit=[..]link [..]-C codegen-units=6 [..] [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=6 [..] [RUNNING] `[..][ROOT]/foo/target/release/build/foo-[HASH]/build-script-build` [foo 0.0.1] foo custom build PROFILE=release DEBUG=false OPT_LEVEL=3 [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]metadata -C opt-level=3 -C panic=abort[..]-C codegen-units=2 [..] [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]metadata -C opt-level=3[..]-C codegen-units=2 [..] [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--emit=[..]metadata -C opt-level=3[..]-C codegen-units=2 --test [..] [RUNNING] `[..] rustc --crate-name test1 --edition=2015 tests/test1.rs [..]--emit=[..]metadata -C opt-level=3[..]-C codegen-units=2 --test [..] [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--emit=[..]metadata -C opt-level=3[..]-C codegen-units=2 --test [..] [RUNNING] `[..] rustc --crate-name bench1 --edition=2015 benches/bench1.rs [..]--emit=[..]metadata -C opt-level=3[..]-C codegen-units=2 --test [..] [RUNNING] `[..] rustc --crate-name ex1 --edition=2015 examples/ex1.rs [..]--crate-type bin --emit=[..]metadata -C opt-level=3 -C panic=abort[..]-C codegen-units=2 [..] [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]metadata -C opt-level=3 -C panic=abort[..]-C codegen-units=2 [..] [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]].unordered()) .run(); p.cargo("check --all-targets --release -vv") .with_stderr_data( str![[r#" [FRESH] bar v0.0.1 ([ROOT]/foo/bar) [FRESH] bdep v0.0.1 ([ROOT]/foo/bdep) [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn profile_selection_check_all_targets_test() { let p = all_target_project(); // `check --profile=test` // - Dependency profiles: // Pkg Target Profile Action Reason // --- ------ ------- ------ ------ // bar lib test* link For bdep // bar lib test-panic metadata For tests/benches // bdep lib test* link For foo build.rs // foo custom test* link For build.rs // // `*` = wants panic, but it is cleared when args are built. // // - foo target list is: // Target Profile Mode // ------ ------- ---- // lib test-panic check-test (for tests/benches) // lib test-panic check-test (checking lib as a unittest) // example test-panic check-test // test test-panic check-test // bench test-panic check-test // bin test-panic check-test // p.cargo("check --all-targets --profile=test -vv") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..]` [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 [..]` [COMPILING] bdep v0.0.1 ([ROOT]/foo/bdep) [RUNNING] `[..] rustc --crate-name bdep --edition=2015 bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 [..]` [RUNNING] `[..][ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [foo 0.0.1] foo custom build PROFILE=debug DEBUG=true OPT_LEVEL=0 [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/lib.rs [..]--emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]` [RUNNING] `[..] rustc --crate-name test1 --edition=2015 tests/test1.rs [..]--emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]` [RUNNING] `[..] rustc --crate-name foo --edition=2015 src/main.rs [..]--emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]` [RUNNING] `[..] rustc --crate-name bench1 --edition=2015 benches/bench1.rs [..]--emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]` [RUNNING] `[..] rustc --crate-name ex1 --edition=2015 examples/ex1.rs [..]--emit=[..]metadata[..]-C codegen-units=3 -C debuginfo=2 [..]--test [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]].unordered()) .run(); p.cargo("check --all-targets --profile=test -vv") .with_stderr_data( str![[r#" [FRESH] bdep v0.0.1 ([ROOT]/foo/bdep) [FRESH] bar v0.0.1 ([ROOT]/foo/bar) [FRESH] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn profile_selection_doc() { let p = all_target_project(); // `doc` // NOTES: // - Dependency profiles: // Pkg Target Profile Action Reason // --- ------ ------- ------ ------ // bar lib dev* link For bdep // bar lib dev metadata For rustdoc // bdep lib dev* link For foo build.rs // foo custom dev* link For build.rs // // `*` = wants panic, but it is cleared when args are built. p.cargo("doc -vv") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [DOCUMENTING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..]` [RUNNING] `[..] rustdoc [..]--crate-name bar bar/src/lib.rs [..] [RUNNING] `[..] rustc --crate-name bar --edition=2015 bar/src/lib.rs [..]--crate-type lib --emit=[..]metadata -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..]` [COMPILING] bdep v0.0.1 ([ROOT]/foo/bdep) [RUNNING] `[..] rustc --crate-name bdep --edition=2015 bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name build_script_build --edition=2015 build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 [..]` [RUNNING] `[..][ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` [foo 0.0.1] foo custom build PROFILE=debug DEBUG=true OPT_LEVEL=0 [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustdoc [..]--crate-name foo src/lib.rs [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]].unordered()) .run(); } cargo-0.86.0/tests/testsuite/profile_trim_paths.rs000064400000000000000000000610171046102023000204520ustar 00000000000000//! Tests for `-Ztrim-paths`. use cargo_test_support::basic_manifest; use cargo_test_support::git; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry::Package; use cargo_test_support::str; #[cargo_test] fn gated_manifest() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [profile.dev] trim-paths = "macro" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `trim-paths` is required ... "#]]) .run(); } #[cargo_test] fn gated_config_toml() { let p = project() .file( ".cargo/config.toml", r#" [profile.dev] trim-paths = "macro" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] config profile `dev` is not valid (defined in `[ROOT]/foo/.cargo/config.toml`) Caused by: feature `trim-paths` is required ... "#]]) .run(); } #[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")] fn release_profile_default_to_object() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build --release --verbose -Ztrim-paths") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]-Zremap-path-scope=object --remap-path-prefix=[ROOT]/foo=. --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")] fn one_option() { let build = |option| { let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" [profile.dev] trim-paths = "{option}" "# ), ) .file("src/lib.rs", "") .build(); p.cargo("build -v -Ztrim-paths") }; for option in ["macro", "diagnostics", "object", "all"] { build(option) .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_stderr_data(&format!( "\ [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]\ -Zremap-path-scope={option} \ --remap-path-prefix=[ROOT]/foo=. \ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s ", )) .run(); } build("none") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_stderr_does_not_contain("[..]-Zremap-path-scope=[..]") .with_stderr_does_not_contain("[..]--remap-path-prefix=[..]") .run(); } #[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")] fn multiple_options() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [profile.dev] trim-paths = ["diagnostics", "macro", "object"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("build --verbose -Ztrim-paths") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]-Zremap-path-scope=diagnostics,macro,object --remap-path-prefix=[ROOT]/foo=. --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")] fn profile_merge_works() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [profile.dev] trim-paths = ["macro"] [profile.custom] inherits = "dev" trim-paths = ["diagnostics"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v -Ztrim-paths --profile custom") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]-Zremap-path-scope=diagnostics --remap-path-prefix=[ROOT]/foo=. --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]` [FINISHED] `custom` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")] fn registry_dependency() { Package::new("bar", "0.0.1") .file("Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("src/lib.rs", r#"pub fn f() { println!("{}", file!()); }"#) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "0.0.1" [profile.dev] trim-paths = "object" "#, ) .file("src/main.rs", "fn main() { bar::f(); }") .build(); p.cargo("run --verbose -Ztrim-paths") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_stdout_data(str![[r#" [..]/bar-0.0.1/src/lib.rs "#]]) // Omit the hash of Source URL .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [COMPILING] bar v0.0.1 [RUNNING] `rustc [..]-Zremap-path-scope=object --remap-path-prefix=[ROOT]/home/.cargo/registry/src= --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]-Zremap-path-scope=object --remap-path-prefix=[ROOT]/foo=. --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")] fn git_dependency() { let git_project = git::new("bar", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("src/lib.rs", r#"pub fn f() { println!("{}", file!()); }"#) }); let url = git_project.url(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = {{ git = "{url}" }} [profile.dev] trim-paths = "object" "# ), ) .file("src/main.rs", "fn main() { bar::f(); }") .build(); p.cargo("run --verbose -Ztrim-paths") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_stdout_data(str![[r#" [..]/[..]/src/lib.rs "#]]) // Omit the hash of Source URL and commit .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/bar` [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.0.1 ([ROOTURL]/bar#[..]) [RUNNING] `rustc [..]-Zremap-path-scope=object --remap-path-prefix=[ROOT]/home/.cargo/git/checkouts= --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]-Zremap-path-scope=object --remap-path-prefix=[ROOT]/foo=. --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")] fn path_dependency() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = { path = "cocktail-bar" } [profile.dev] trim-paths = "object" "#, ) .file("src/main.rs", "fn main() { bar::f(); }") .file("cocktail-bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file( "cocktail-bar/src/lib.rs", r#"pub fn f() { println!("{}", file!()); }"#, ) .build(); p.cargo("run --verbose -Ztrim-paths") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_stdout_data(str![[r#" cocktail-bar/src/lib.rs "#]]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.0.1 ([ROOT]/foo/cocktail-bar) [RUNNING] `rustc [..]-Zremap-path-scope=object --remap-path-prefix=[ROOT]/foo=. --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]-Zremap-path-scope=object --remap-path-prefix=[ROOT]/foo=. --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")] fn path_dependency_outside_workspace() { let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("src/lib.rs", r#"pub fn f() { println!("{}", file!()); }"#) .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = { path = "../bar" } [profile.dev] trim-paths = "object" "#, ) .file("src/main.rs", "fn main() { bar::f(); }") .build(); p.cargo("run --verbose -Ztrim-paths") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_stdout_data(str![[r#" bar-0.0.1/src/lib.rs "#]]) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.0.1 ([ROOT]/bar) [RUNNING] `rustc [..]-Zremap-path-scope=object --remap-path-prefix=[ROOT]/bar=bar-0.0.1 --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]-Zremap-path-scope=object --remap-path-prefix=[ROOT]/foo=. --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")] fn diagnostics_works() { Package::new("bar", "0.0.1") .file("Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("src/lib.rs", r#"pub fn f() { let unused = 0; }"#) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "0.0.1" [profile.dev] trim-paths = "diagnostics" "#, ) .file("src/lib.rs", "") .build(); let registry_src = paths::home().join(".cargo/registry/src"); let registry_src = registry_src.display(); p.cargo("build -vv -Ztrim-paths") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_stderr_line_without( &["[..]bar-0.0.1/src/lib.rs:1[..]"], &[&format!("{registry_src}")], ) .with_stderr_data(str![[r#" ... [RUNNING] `[..] rustc [..]-Zremap-path-scope=diagnostics --remap-path-prefix=[ROOT]/home/.cargo/registry/src= --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]` [WARNING] unused variable: `unused` ... [RUNNING] `[..] rustc [..]-Zremap-path-scope=diagnostics --remap-path-prefix=[ROOT]/foo=. --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]` ... "#]]) .run(); } #[cfg(target_os = "macos")] mod object_works { use super::*; fn inspect_debuginfo(path: &std::path::Path) -> Vec { std::process::Command::new("nm") .arg("-pa") .arg(path) .output() .expect("nm works") .stdout } #[cargo_test(requires = "nm", nightly, reason = "-Zremap-path-scope is unstable")] fn with_split_debuginfo_off() { object_works_helper("off", inspect_debuginfo); } #[cargo_test(requires = "nm", nightly, reason = "-Zremap-path-scope is unstable")] fn with_split_debuginfo_packed() { object_works_helper("packed", inspect_debuginfo); } #[cargo_test(requires = "nm", nightly, reason = "-Zremap-path-scope is unstable")] fn with_split_debuginfo_unpacked() { object_works_helper("unpacked", inspect_debuginfo); } } #[cfg(target_os = "linux")] mod object_works { use super::*; fn inspect_debuginfo(path: &std::path::Path) -> Vec { std::process::Command::new("readelf") .arg("--debug-dump=info") .arg("--debug-dump=no-follow-links") // older version can't recognized but just a warning .arg(path) .output() .expect("readelf works") .stdout } #[cargo_test( requires = "readelf", nightly, reason = "-Zremap-path-scope is unstable" )] fn with_split_debuginfo_off() { object_works_helper("off", inspect_debuginfo); } #[cargo_test( requires = "readelf", nightly, reason = "-Zremap-path-scope is unstable" )] fn with_split_debuginfo_packed() { object_works_helper("packed", inspect_debuginfo); } #[cargo_test( requires = "readelf", nightly, reason = "-Zremap-path-scope is unstable" )] fn with_split_debuginfo_unpacked() { object_works_helper("unpacked", inspect_debuginfo); } } #[cfg(unix)] fn object_works_helper(split_debuginfo: &str, run: impl Fn(&std::path::Path) -> Vec) { use std::os::unix::ffi::OsStrExt; let registry_src = paths::home().join(".cargo/registry/src"); let registry_src_bytes = registry_src.as_os_str().as_bytes(); let rust_src = "/lib/rustc/src/rust".as_bytes(); Package::new("bar", "0.0.1") .file("Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("src/lib.rs", r#"pub fn f() { println!("{}", file!()); }"#) .publish(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "0.0.1" [profile.dev] split-debuginfo = "{split_debuginfo}" "# ), ) .file("src/main.rs", "fn main() { bar::f(); }") .build(); let pkg_root = p.root(); let pkg_root = pkg_root.as_os_str().as_bytes(); p.cargo("build").run(); let bin_path = p.bin("foo"); assert!(bin_path.is_file()); let stdout = run(&bin_path); // TODO: re-enable this check when rustc bootstrap disables remapping // // assert!(memchr::memmem::find(&stdout, rust_src).is_some()); assert!(memchr::memmem::find(&stdout, registry_src_bytes).is_some()); assert!(memchr::memmem::find(&stdout, pkg_root).is_some()); p.cargo("clean").run(); p.cargo("build --verbose -Ztrim-paths") .arg("--config") .arg(r#"profile.dev.trim-paths="object""#) .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_stderr_data(&format!( "\ [COMPILING] bar v0.0.1 [RUNNING] `rustc [..]-C split-debuginfo={split_debuginfo} [..]\ -Zremap-path-scope=object \ --remap-path-prefix=[ROOT]/home/.cargo/registry/src= \ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]-C split-debuginfo={split_debuginfo} [..]\ -Zremap-path-scope=object \ --remap-path-prefix=[ROOT]/foo=. \ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s ", )) .run(); let bin_path = p.bin("foo"); assert!(bin_path.is_file()); let stdout = run(&bin_path); assert!(memchr::memmem::find(&stdout, rust_src).is_none()); for line in stdout.split(|c| c == &b'\n') { let registry = memchr::memmem::find(line, registry_src_bytes).is_none(); let local = memchr::memmem::find(line, pkg_root).is_none(); if registry && local { continue; } #[cfg(target_os = "macos")] { // `OSO` symbols can't be trimmed at this moment. // See if memchr::memmem::find(line, b" OSO ").is_some() { continue; } // on macOS `SO` symbols are embedded in final binaries and should be trimmed. // See rust-lang/rust#117652. if memchr::memmem::find(line, b" SO ").is_some() { continue; } } #[cfg(target_os = "linux")] { // There is a bug in rustc `-Zremap-path-scope`. // See rust-lang/rust/pull/118518 if memchr::memmem::find(line, b"DW_AT_comp_dir").is_some() { continue; } if memchr::memmem::find(line, b"DW_AT_GNU_dwo_name").is_some() { continue; } } panic!( "unexpected untrimmed symbol: {}", String::from_utf8(line.into()).unwrap() ); } } // TODO: might want to move to test/testsuite/build_script.rs once stabilized. #[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")] fn custom_build_env_var_trim_paths() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/lib.rs", "") .file("build.rs", "") .build(); let test_cases = [ ("[]", "none"), ("\"all\"", "all"), ("\"diagnostics\"", "diagnostics"), ("\"macro\"", "macro"), ("\"none\"", "none"), ("\"object\"", "object"), ("false", "none"), ("true", "all"), ( r#"["diagnostics", "macro", "object"]"#, "diagnostics,macro,object", ), ]; for (opts, expected) in test_cases { p.change_file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" [profile.dev] trim-paths = {opts} "# ), ); p.change_file( "build.rs", &format!( r#" fn main() {{ assert_eq!( std::env::var("CARGO_TRIM_PATHS").unwrap().as_str(), "{expected}", ); }} "# ), ); p.cargo("build -Ztrim-paths") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .run(); } } #[cfg(unix)] #[cargo_test(requires = "lldb", nightly, reason = "-Zremap-path-scope is unstable")] fn lldb_works_after_trimmed() { use cargo_test_support::compare::assert_e2e; use cargo_util::is_ci; if !is_ci() { // On macOS lldb requires elevated privileges to run developer tools. // See rust-lang/cargo#13413 return; } let run_lldb = |path| { std::process::Command::new("lldb") .args(["-o", "breakpoint set --file src/main.rs --line 4"]) .args(["-o", "run"]) .args(["-o", "continue"]) .args(["-o", "exit"]) .arg("--no-use-colors") .arg(path) .output() .expect("lldb works") }; let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [profile.dev] trim-paths = "object" "#, ) .file( "src/main.rs", r#" fn main() { let msg = "Hello, Ferris!"; println!("{msg}"); } "#, ) .build(); p.cargo("build --verbose -Ztrim-paths") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]-Zremap-path-scope=object --remap-path-prefix=[ROOT]/foo=. --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let bin_path = p.bin("foo"); assert!(bin_path.is_file()); let stdout = String::from_utf8(run_lldb(bin_path).stdout).unwrap(); assert_e2e().eq( &stdout, str![[r#" ... [..]stopped[..] [..]stop reason = breakpoint 1.1[..] ... (lldb) continue Hello, Ferris! ... "#]], ); } #[cargo_test(nightly, reason = "rustdoc --remap-path-prefix is unstable")] fn rustdoc_without_diagnostics_scope() { Package::new("bar", "0.0.1") .file("Cargo.toml", &basic_manifest("bar", "0.0.1")) .file( "src/lib.rs", r#" /// pub struct Bar; "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "0.0.1" [profile.dev] trim-paths = "object" "#, ) .file("src/lib.rs", "") .build(); p.cargo("doc -vv -Ztrim-paths") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_stderr_data(str![[r#" ... [WARNING] unopened HTML tag `script` --> [ROOT]/home/.cargo/registry/src/-[HASH]/bar-0.0.1/src/lib.rs:2:17 ... "#]]) .run(); } #[cargo_test(nightly, reason = "rustdoc --remap-path-prefix is unstable")] fn rustdoc_diagnostics_works() { // This is expected to work after rust-lang/rust#128736 Package::new("bar", "0.0.1") .file("Cargo.toml", &basic_manifest("bar", "0.0.1")) .file( "src/lib.rs", r#" /// pub struct Bar; "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "0.0.1" [profile.dev] trim-paths = "diagnostics" "#, ) .file("src/lib.rs", "") .build(); p.cargo("doc -vv -Ztrim-paths") .masquerade_as_nightly_cargo(&["-Ztrim-paths"]) .with_stderr_data(str![[r#" ... [RUNNING] `[..]rustc [..]-Zremap-path-scope=diagnostics --remap-path-prefix=[ROOT]/home/.cargo/registry/src= --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..]` ... [WARNING] unopened HTML tag `script` --> -[..]/bar-0.0.1/src/lib.rs:2:17 ... "#]]) .run(); } cargo-0.86.0/tests/testsuite/profiles.rs000064400000000000000000000551621046102023000164070ustar 00000000000000//! Tests for profiles. use std::env; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{project, rustc_host, str}; #[cargo_test] fn profile_overrides() { let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" authors = [] [profile.dev] opt-level = 1 debug = false rpath = true "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v").with_stderr_data(str![[r#" [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name test --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..] -C opt-level=1[..] -C debug-assertions=on[..] -C metadata=[..] -C rpath --out-dir [ROOT]/foo/target/debug/deps [..] -L dependency=[ROOT]/foo/target/debug/deps` [FINISHED] `dev` profile [optimized] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn opt_level_override_0() { let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" authors = [] [profile.dev] opt-level = 0 "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v").with_stderr_data(str![[r#" [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name test --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C debuginfo=2 [..] -C metadata=[..] --out-dir [ROOT]/foo/target/debug/deps -L dependency=[ROOT]/foo/target/debug/deps` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn debug_override_1() { let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" authors = [] [profile.dev] debug = 1 "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v").with_stderr_data(str![[r#" [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name test --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C debuginfo=1 [..]-C metadata=[..] --out-dir [ROOT]/foo/target/debug/deps -L dependency=[ROOT]/foo/target/debug/deps` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } fn check_opt_level_override(profile_level: &str, rustc_level: &str) { let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "test" version = "0.0.0" edition = "2015" authors = [] [profile.dev] opt-level = {level} "#, level = profile_level ), ) .file("src/lib.rs", "") .build(); p.cargo("build -v") .with_stderr_data(&format!( "\ [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name test --edition=2015 src/lib.rs [..]--crate-type lib \ --emit=[..]link \ -C opt-level={level}[..]\ -C debuginfo=2 [..]\ -C debug-assertions=on[..] \ -C metadata=[..] \ --out-dir [..] \ -L dependency=[ROOT]/foo/target/debug/deps` [FINISHED] `dev` profile [..]+ debuginfo] target(s) in [ELAPSED]s ", level = rustc_level )) .run(); } #[cargo_test] fn opt_level_overrides() { for &(profile_level, rustc_level) in &[ ("1", "1"), ("2", "2"), ("3", "3"), ("\"s\"", "s"), ("\"z\"", "z"), ] { check_opt_level_override(profile_level, rustc_level) } } #[cargo_test] fn top_level_overrides_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" edition = "2015" authors = [] [profile.release] opt-level = 1 debug = true [dependencies.foo] path = "foo" "#, ) .file("src/lib.rs", "") .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" authors = [] [profile.release] opt-level = 0 debug = false [lib] name = "foo" crate-type = ["dylib", "rlib"] "#, ) .file("foo/src/lib.rs", "") .build(); p.cargo("build -v --release") .with_stderr_data(&format!( "\ [LOCKING] 1 package to latest compatible version [COMPILING] foo v0.0.0 ([ROOT]/foo/foo) [RUNNING] `rustc --crate-name foo --edition=2015 foo/src/lib.rs [..]\ --crate-type dylib --crate-type rlib \ --emit=[..]link \ -C prefer-dynamic \ -C opt-level=1[..]\ -C debuginfo=2 [..]\ -C metadata=[..] \ --out-dir [ROOT]/foo/target/release/deps \ -L dependency=[ROOT]/foo/target/release/deps` [COMPILING] test v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name test --edition=2015 src/lib.rs [..]--crate-type lib \ --emit=[..]link \ -C opt-level=1[..]\ -C debuginfo=2 [..]\ -C metadata=[..] \ --out-dir [..] \ -L dependency=[ROOT]/foo/target/release/deps \ --extern foo=[ROOT]/foo/target/release/deps/\ {prefix}foo[..]{suffix} \ --extern foo=[ROOT]/foo/target/release/deps/libfoo.rlib` [FINISHED] `release` profile [optimized + debuginfo] target(s) in [ELAPSED]s ", prefix = env::consts::DLL_PREFIX, suffix = env::consts::DLL_SUFFIX )) .run(); } #[cargo_test] fn profile_in_non_root_manifest_triggers_a_warning() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["bar"] [profile.dev] debug = false "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = ".." [profile.dev] opt-level = 1 "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .cwd("bar") .with_stderr_data(str![[r#" [WARNING] profiles for the non root package will be ignored, specify profiles at the workspace root: package: [ROOT]/foo/bar/Cargo.toml workspace: [ROOT]/foo/Cargo.toml [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [RUNNING] `rustc [..]` [FINISHED] `dev` profile [unoptimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn profile_in_virtual_manifest_works() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] [profile.dev] opt-level = 1 debug = false "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = ".." "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .cwd("bar") .with_stderr_data(str![[r#" [COMPILING] bar v0.1.0 ([ROOT]/foo/bar) [RUNNING] `rustc [..]` [FINISHED] `dev` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn profile_lto_string_bool_dev() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [profile.dev] lto = "true" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: `lto` setting of string `"true"` for `dev` profile is not a valid setting, must be a boolean (`true`/`false`) or a string (`"thin"`/`"fat"`/`"off"`) or omitted. "#]]) .run(); } #[cargo_test] fn profile_panic_test_bench() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [profile.test] panic = "abort" [profile.bench] panic = "abort" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_stderr_data(str![[r#" [WARNING] `panic` setting is ignored for `bench` profile [WARNING] `panic` setting is ignored for `test` profile [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn profile_doc_deprecated() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [profile.doc] opt-level = 0 "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_stderr_data(str![[r#" [WARNING] profile `doc` is deprecated and has no effect ... "#]]) .run(); } #[cargo_test] fn panic_unwind_does_not_build_twice() { // Check for a bug where `lib` was built twice, once with panic set and // once without. Since "unwind" is the default, they are the same and // should only be built once. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.dev] panic = "unwind" "#, ) .file("src/lib.rs", "") .file("src/main.rs", "fn main() {}") .file("tests/t1.rs", "") .build(); p.cargo("test -v --tests --no-run") .with_stderr_data( str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib [..]` [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..] --test [..]` [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin [..]` [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..] --test [..]` [RUNNING] `rustc --crate-name t1 --edition=2015 tests/t1.rs [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [EXECUTABLE] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [EXECUTABLE] `[ROOT]/foo/target/debug/deps/t1-[HASH][EXE]` "#]] .unordered(), ) .run(); } #[cargo_test] fn debug_0_report() { // The finished line handles 0 correctly. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.dev] debug = 0 "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]` [FINISHED] `dev` profile [unoptimized] target(s) in [ELAPSED]s "#]]) .with_stderr_does_not_contain("-C debuginfo") .run(); } #[cargo_test] fn thin_lto_works() { let p = project() .file( "Cargo.toml", r#" [package] name = "top" version = "0.5.0" edition = "2015" authors = [] [profile.release] lto = 'thin' "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --release -v") .with_stderr_data(str![[r#" [COMPILING] top v0.5.0 ([ROOT]/foo) [RUNNING] `rustc [..] -C lto=thin [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn strip_works() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.release] strip = 'symbols' "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --release -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] -C strip=symbols [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn strip_passes_unknown_option_to_rustc() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.release] strip = 'unknown' "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --release -v") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] -C strip=unknown [..]` [ERROR] incorrect value `unknown` for [..] `strip` [..] was expected ... "#]]) .run(); } #[cargo_test] fn strip_accepts_true_to_strip_symbols() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.release] strip = true "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --release -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] -C strip=symbols [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn strip_accepts_false_to_disable_strip() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.release] strip = false "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --release -v") .with_stderr_does_not_contain("[RUNNING] `rustc [..] -C strip[..]`") .run(); } #[cargo_test] fn strip_debuginfo_in_release() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --release -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] -C strip=debuginfo[..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build --release -v --target") .arg(rustc_host()) .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] -C strip=debuginfo[..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn strip_debuginfo_without_debug() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [profile.dev] debug = 0 "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -C strip=debuginfo[..]` [FINISHED] `dev` profile [unoptimized] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn do_not_strip_debuginfo_with_requested_debug() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } [profile.release.package.bar] debug = 1 "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("build --release -v") .with_stderr_does_not_contain("[RUNNING] `rustc [..] -C strip=debuginfo[..]`") .run(); } #[cargo_test] fn rustflags_works() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["profile-rustflags"] [profile.dev] rustflags = ["-C", "link-dead-code=yes"] [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .masquerade_as_nightly_cargo(&["profile-rustflags"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -C link-dead-code=yes [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rustflags_works_with_env() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["profile-rustflags"] [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .env("CARGO_PROFILE_DEV_RUSTFLAGS", "-C link-dead-code=yes") .masquerade_as_nightly_cargo(&["profile-rustflags"]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -C link-dead-code=yes [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rustflags_requires_cargo_feature() { let p = project() .file( "Cargo.toml", r#" [profile.dev] rustflags = ["-C", "link-dead-code=yes"] [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v") .masquerade_as_nightly_cargo(&["profile-rustflags"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `profile-rustflags` is required The package requires the Cargo feature called `profile-rustflags`, but that feature is not stabilized in this version of Cargo (1.[..]). Consider adding `cargo-features = ["profile-rustflags"]` to the top of Cargo.toml (above the [package] table) to tell Cargo you are opting in to use this unstable feature. See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#profile-rustflags-option for more information about the status of this feature. "#]]) .run(); Package::new("bar", "1.0.0").publish(); p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = "1.0" [profile.dev.package.bar] rustflags = ["-C", "link-dead-code=yes"] "#, ); p.cargo("check") .masquerade_as_nightly_cargo(&["profile-rustflags"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `profile-rustflags` is required The package requires the Cargo feature called `profile-rustflags`, but that feature is not stabilized in this version of Cargo (1.[..]). Consider adding `cargo-features = ["profile-rustflags"]` to the top of Cargo.toml (above the [package] table) to tell Cargo you are opting in to use this unstable feature. See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#profile-rustflags-option for more information about the status of this feature. "#]]) .run(); } #[cargo_test] fn debug_options_valid() { let build = |option| { let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" authors = [] version = "0.0.0" edition = "2015" [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_data(&format!( "\ ... [RUNNING] `rustc [..]-C debuginfo={cli} [..]` ... " )) .run(); } build("none") .with_stderr_does_not_contain("[..]-C debuginfo[..]") .run(); } cargo-0.86.0/tests/testsuite/progress.rs000064400000000000000000000074321046102023000164250ustar 00000000000000//! Tests for progress bar. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry::Package; use cargo_test_support::str; #[cargo_test] fn bad_progress_config_unknown_when() { let p = project() .file( ".cargo/config.toml", r#" [term] progress = { when = 'unknown' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] error in [ROOT]/foo/.cargo/config.toml: could not load config key `term.progress.when` Caused by: unknown variant `unknown`, expected one of `auto`, `never`, `always` "#]]) .run(); } #[cargo_test] fn bad_progress_config_missing_width() { let p = project() .file( ".cargo/config.toml", r#" [term] progress = { when = 'always' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] "always" progress requires a `width` key "#]]) .run(); } #[cargo_test] fn bad_progress_config_missing_when() { let p = project() .file( ".cargo/config.toml", r#" [term] progress = { width = 1000 } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] error in [ROOT]/foo/.cargo/config.toml: could not load config key `term.progress` Caused by: missing field `when` "#]]) .run(); } #[cargo_test] fn always_shows_progress() { const N: usize = 3; let mut deps = String::new(); for i in 1..=N { Package::new(&format!("dep{}", i), "1.0.0").publish(); deps.push_str(&format!("dep{} = \"1.0\"\n", i)); } let p = project() .file( ".cargo/config.toml", r#" [term] progress = { when = 'always', width = 100 } "#, ) .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] {} "#, deps ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data( str![[r#" [DOWNLOADING] [..] crate [DOWNLOADED] 3 crates ([..]KB) in [..]s [BUILDING] [..] [..]/4: [..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s ... "#]] .unordered(), ) .run(); } #[cargo_test] fn never_progress() { const N: usize = 3; let mut deps = String::new(); for i in 1..=N { Package::new(&format!("dep{}", i), "1.0.0").publish(); deps.push_str(&format!("dep{} = \"1.0\"\n", i)); } let p = project() .file( ".cargo/config.toml", r#" [term] progress = { when = 'never' } "#, ) .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] {} "#, deps ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_does_not_contain("[DOWNLOADING] [..] crates [..]") .with_stderr_does_not_contain("[..][DOWNLOADED] 3 crates ([..]) in [..]") .with_stderr_does_not_contain("[BUILDING] [..] [..]/4: [..]") .run(); } cargo-0.86.0/tests/testsuite/pub_priv.rs000064400000000000000000000460211046102023000164040ustar 00000000000000//! Tests for public/private dependencies. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry::{Dependency, Package}; use cargo_test_support::str; #[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")] fn exported_priv_warning() { Package::new("priv_dep", "0.1.0") .file("src/lib.rs", "pub struct FromPriv;") .publish(); let p = project() .file( "Cargo.toml", r#" cargo-features = ["public-dependency"] [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] priv_dep = "0.1.0" "#, ) .file( "src/lib.rs", " extern crate priv_dep; pub fn use_priv(_: priv_dep::FromPriv) {} ", ) .build(); p.cargo("check --message-format=short") .masquerade_as_nightly_cargo(&["public-dependency"]) .with_stderr_data(str![[r#" ... src/lib.rs:3:13: [WARNING] type `FromPriv` from private dependency 'priv_dep' in public interface ... "#]]) .run(); } #[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")] fn exported_pub_dep() { Package::new("pub_dep", "0.1.0") .file("src/lib.rs", "pub struct FromPub;") .publish(); let p = project() .file( "Cargo.toml", r#" cargo-features = ["public-dependency"] [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] pub_dep = {version = "0.1.0", public = true} "#, ) .file( "src/lib.rs", " extern crate pub_dep; pub fn use_pub(_: pub_dep::FromPub) {} ", ) .build(); p.cargo("check --message-format=short") .masquerade_as_nightly_cargo(&["public-dependency"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] pub_dep v0.1.0 (registry `dummy-registry`) [CHECKING] pub_dep v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] pub fn requires_nightly_cargo() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["public-dependency"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check --message-format=short") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: the cargo feature `public-dependency` requires a nightly version of Cargo, but this is the `stable` channel See https://doc.rust-lang.org/book/appendix-07-nightly-rust.html for more information about Rust release channels. See https://doc.rust-lang.org/[..]cargo/reference/unstable.html#public-dependency for more information about using this feature. "#]]) .run(); } #[cargo_test] fn requires_feature() { Package::new("pub_dep", "0.1.0") .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] pub_dep = { version = "0.1.0", public = true } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check --message-format=short") .masquerade_as_nightly_cargo(&["public-dependency"]) .with_stderr_data(str![[r#" [WARNING] ignoring `public` on dependency pub_dep, pass `-Zpublic-dependency` to enable support for it [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] pub_dep v0.1.0 (registry `dummy-registry`) [CHECKING] pub_dep v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn pub_dev_dependency() { Package::new("pub_dep", "0.1.0") .file("src/lib.rs", "pub struct FromPub;") .publish(); let p = project() .file( "Cargo.toml", r#" cargo-features = ["public-dependency"] [package] name = "foo" version = "0.0.1" edition = "2015" [dev-dependencies] pub_dep = {version = "0.1.0", public = true} "#, ) .file( "src/lib.rs", " extern crate pub_dep; pub fn use_pub(_: pub_dep::FromPub) {} ", ) .build(); p.cargo("check --message-format=short") .masquerade_as_nightly_cargo(&["public-dependency"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: 'public' specifier can only be used on regular dependencies, not dev-dependencies "#]]) .run(); } #[cargo_test] fn pub_dev_dependency_without_feature() { Package::new("pub_dep", "0.1.0") .file("src/lib.rs", "pub struct FromPub;") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dev-dependencies] pub_dep = {version = "0.1.0", public = true} "#, ) .file( "tests/mod.rs", " extern crate pub_dep; pub fn use_pub(_: pub_dep::FromPub) {} ", ) .build(); p.cargo("check --message-format=short") .with_stderr_data(str![[r#" [WARNING] 'public' specifier can only be used on regular dependencies, not dev-dependencies [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")] fn workspace_pub_disallowed() { Package::new("foo1", "0.1.0") .file("src/lib.rs", "pub struct FromFoo;") .publish(); Package::new("foo2", "0.1.0") .file("src/lib.rs", "pub struct FromFoo;") .publish(); Package::new("foo3", "0.1.0") .file("src/lib.rs", "pub struct FromFoo;") .publish(); let p = project() .file( "Cargo.toml", r#" cargo-features = ["public-dependency"] [package] name = "foo" version = "0.0.1" edition = "2015" [workspace.dependencies] foo1 = "0.1.0" foo2 = { version = "0.1.0", public = true } foo3 = { version = "0.1.0", public = false } [dependencies] foo1 = { workspace = true, public = true } foo2 = { workspace = true } foo3 = { workspace = true, public = true } "#, ) .file( "src/lib.rs", " #![deny(exported_private_dependencies)] pub fn use_priv1(_: foo1::FromFoo) {} pub fn use_priv2(_: foo2::FromFoo) {} pub fn use_priv3(_: foo3::FromFoo) {} ", ) .build(); p.cargo("check") .masquerade_as_nightly_cargo(&["public-dependency"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: foo2 is public, but workspace dependencies cannot be public "#]]) .run(); } #[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")] fn allow_priv_in_tests() { Package::new("priv_dep", "0.1.0") .file("src/lib.rs", "pub struct FromPriv;") .publish(); let p = project() .file( "Cargo.toml", r#" cargo-features = ["public-dependency"] [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] priv_dep = {version = "0.1.0", public = false} "#, ) .file( "tests/mod.rs", " extern crate priv_dep; pub fn use_priv(_: priv_dep::FromPriv) {} ", ) .build(); p.cargo("check --tests --message-format=short") .masquerade_as_nightly_cargo(&["public-dependency"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] priv_dep v0.1.0 (registry `dummy-registry`) [CHECKING] priv_dep v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")] fn allow_priv_in_benchs() { Package::new("priv_dep", "0.1.0") .file("src/lib.rs", "pub struct FromPriv;") .publish(); let p = project() .file( "Cargo.toml", r#" cargo-features = ["public-dependency"] [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] priv_dep = {version = "0.1.0", public = false} "#, ) .file( "benches/mod.rs", " extern crate priv_dep; pub fn use_priv(_: priv_dep::FromPriv) {} ", ) .build(); p.cargo("check --benches --message-format=short") .masquerade_as_nightly_cargo(&["public-dependency"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] priv_dep v0.1.0 (registry `dummy-registry`) [CHECKING] priv_dep v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")] fn allow_priv_in_bins() { Package::new("priv_dep", "0.1.0") .file("src/lib.rs", "pub struct FromPriv;") .publish(); let p = project() .file( "Cargo.toml", r#" cargo-features = ["public-dependency"] [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] priv_dep = {version = "0.1.0", public = false} "#, ) .file( "src/main.rs", " extern crate priv_dep; pub fn use_priv(_: priv_dep::FromPriv) {} fn main() {} ", ) .build(); p.cargo("check --bins --message-format=short") .masquerade_as_nightly_cargo(&["public-dependency"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] priv_dep v0.1.0 (registry `dummy-registry`) [CHECKING] priv_dep v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")] fn allow_priv_in_examples() { Package::new("priv_dep", "0.1.0") .file("src/lib.rs", "pub struct FromPriv;") .publish(); let p = project() .file( "Cargo.toml", r#" cargo-features = ["public-dependency"] [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] priv_dep = {version = "0.1.0", public = false} "#, ) .file( "examples/lib.rs", " extern crate priv_dep; pub fn use_priv(_: priv_dep::FromPriv) {} fn main() {} ", ) .build(); p.cargo("check --examples --message-format=short") .masquerade_as_nightly_cargo(&["public-dependency"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] priv_dep v0.1.0 (registry `dummy-registry`) [CHECKING] priv_dep v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")] fn allow_priv_in_custom_build() { Package::new("priv_dep", "0.1.0") .file("src/lib.rs", "pub struct FromPriv;") .publish(); let p = project() .file( "Cargo.toml", r#" cargo-features = ["public-dependency"] [package] name = "foo" version = "0.0.1" edition = "2015" [build-dependencies] priv_dep = "0.1.0" "#, ) .file("src/main.rs", "fn main() {}") .file( "build.rs", " extern crate priv_dep; pub fn use_priv(_: priv_dep::FromPriv) {} fn main() {} ", ) .build(); p.cargo("check --all-targets --message-format=short") .masquerade_as_nightly_cargo(&["public-dependency"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] priv_dep v0.1.0 (registry `dummy-registry`) [COMPILING] priv_dep v0.1.0 [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")] fn publish_package_with_public_dependency() { Package::new("pub_bar", "0.1.0") .file("src/lib.rs", "pub struct FromPub;") .publish(); Package::new("bar", "0.1.0") .cargo_feature("public-dependency") .add_dep(Dependency::new("pub_bar", "0.1.0").public(true)) .file( "src/lib.rs", " extern crate pub_bar; pub use pub_bar::FromPub as BarFromPub; ", ) .publish(); let p = project() .file( "Cargo.toml", r#" cargo-features = ["public-dependency"] [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = {version = "0.1.0", public = true} "#, ) .file( "src/lib.rs", " extern crate bar; pub fn use_pub(_: bar::BarFromPub) {} ", ) .build(); p.cargo("check --message-format=short") .masquerade_as_nightly_cargo(&["public-dependency"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] pub_bar v0.1.0 (registry `dummy-registry`) [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [CHECKING] pub_bar v0.1.0 [CHECKING] bar v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")] fn verify_mix_cargo_feature_z() { Package::new("dep", "0.1.0") .file("src/lib.rs", "pub struct FromDep;") .publish(); Package::new("priv_dep", "0.1.0") .file("src/lib.rs", "pub struct FromPriv;") .publish(); Package::new("pub_dep", "0.1.0") .file("src/lib.rs", "pub struct FromPub;") .publish(); let p = project() .file( "Cargo.toml", r#" cargo-features = ["public-dependency"] [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] dep = "0.1.0" priv_dep = {version = "0.1.0", public = false} pub_dep = {version = "0.1.0", public = true} "#, ) .file( "src/lib.rs", " extern crate dep; extern crate priv_dep; extern crate pub_dep; pub fn use_dep(_: dep::FromDep) {} pub fn use_priv(_: priv_dep::FromPriv) {} pub fn use_pub(_: pub_dep::FromPub) {} ", ) .build(); p.cargo("check -Zpublic-dependency --message-format=short") .masquerade_as_nightly_cargo(&["public-dependency"]) .with_stderr_data(str![[r#" ... src/lib.rs:5:13: [WARNING] type `FromDep` from private dependency 'dep' in public interface src/lib.rs:6:13: [WARNING] type `FromPriv` from private dependency 'priv_dep' in public interface ... "#]]) .run(); } #[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")] fn verify_z_public_dependency() { Package::new("dep", "0.1.0") .file("src/lib.rs", "pub struct FromDep;") .publish(); Package::new("priv_dep", "0.1.0") .file("src/lib.rs", "pub struct FromPriv;") .publish(); Package::new("pub_dep", "0.1.0") .file("src/lib.rs", "pub struct FromPub;") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] dep = "0.1.0" priv_dep = {version = "0.1.0", public = false} pub_dep = {version = "0.1.0", public = true} "#, ) .file( "src/lib.rs", " extern crate dep; extern crate priv_dep; extern crate pub_dep; pub fn use_dep(_: dep::FromDep) {} pub fn use_priv(_: priv_dep::FromPriv) {} pub fn use_pub(_: pub_dep::FromPub) {} ", ) .build(); p.cargo("check -Zpublic-dependency --message-format=short") .masquerade_as_nightly_cargo(&["public-dependency"]) .with_stderr_data( str![[r#" ... src/lib.rs:5:13: [WARNING] type `FromDep` from private dependency 'dep' in public interface src/lib.rs:6:13: [WARNING] type `FromPriv` from private dependency 'priv_dep' in public interface ... "#]] .unordered(), ) .run(); } cargo-0.86.0/tests/testsuite/publish.rs000064400000000000000000003552211046102023000162310ustar 00000000000000//! Tests for the `cargo publish` command. use std::fs; use std::sync::{Arc, Mutex}; use cargo_test_support::git::{self, repo}; use cargo_test_support::prelude::*; use cargo_test_support::registry::{self, Package, RegistryBuilder, Response}; use cargo_test_support::{basic_manifest, project, publish, str}; use cargo_test_support::{paths, Project}; const CLEAN_FOO_JSON: &str = r#" { "authors": [], "badges": {}, "categories": [], "deps": [], "description": "foo", "documentation": "foo", "features": {}, "homepage": "foo", "keywords": [], "license": "MIT", "license_file": null, "links": null, "name": "foo", "readme": null, "readme_file": null, "repository": "foo", "rust_version": null, "vers": "0.0.1" } "#; fn validate_upload_foo() { publish::validate_upload( r#" { "authors": [], "badges": {}, "categories": [], "deps": [], "description": "foo", "documentation": null, "features": {}, "homepage": null, "keywords": [], "license": "MIT", "license_file": null, "links": null, "name": "foo", "readme": null, "readme_file": null, "repository": null, "rust_version": null, "vers": "0.0.1" } "#, "foo-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], ); } fn validate_upload_li() { publish::validate_upload( r#" { "authors": [], "badges": {}, "categories": [], "deps": [], "description": "li", "documentation": null, "features": {}, "homepage": null, "keywords": [], "license": "MIT", "license_file": null, "links": null, "name": "li", "readme": null, "readme_file": null, "repository": null, "rust_version": "1.69", "vers": "0.0.1" } "#, "li-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], ); } #[cargo_test] fn simple() { let registry = RegistryBuilder::new().http_api().http_index().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `crates-io` [NOTE] waiting for `foo v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `crates-io` "#]]) .run(); validate_upload_foo(); } #[cargo_test] fn duplicate_version() { let registry_dupl = RegistryBuilder::new().http_api().http_index().build(); Package::new("foo", "0.0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish --dry-run") .replace_crates_io(registry_dupl.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] crate foo@0.0.1 already exists on crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [WARNING] aborting upload due to dry run "#]]) .run(); p.cargo("publish") .replace_crates_io(registry_dupl.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] crate foo@0.0.1 already exists on crates.io index "#]]) .run(); } // Check that the `token` key works at the root instead of under a // `[registry]` table. #[cargo_test] fn simple_publish_with_http() { let _reg = registry::RegistryBuilder::new() .http_api() .token(registry::Token::Plaintext("sekrit".to_string())) .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish --no-verify --token sekrit --registry dummy-registry") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `dummy-registry` [NOTE] waiting for `foo v0.0.1` to be available at registry `dummy-registry`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `dummy-registry` "#]]) .run(); } #[cargo_test] fn simple_publish_with_asymmetric() { let _reg = registry::RegistryBuilder::new() .http_api() .http_index() .alternative_named("dummy-registry") .token(registry::Token::rfc_key()) .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish --no-verify -Zasymmetric-token --registry dummy-registry") .masquerade_as_nightly_cargo(&["asymmetric-token"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `dummy-registry` [NOTE] waiting for `foo v0.0.1` to be available at registry `dummy-registry`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `dummy-registry` "#]]) .run(); } #[cargo_test] fn old_token_location() { // `publish` generally requires a remote registry let registry = registry::RegistryBuilder::new().http_api().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); let credentials = paths::home().join(".cargo/credentials.toml"); fs::remove_file(&credentials).unwrap(); // Verify can't publish without a token. p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] no token found, please run `cargo login` or use environment variable CARGO_REGISTRY_TOKEN "#]]) .run(); fs::write(&credentials, format!(r#"token = "{}""#, registry.token())).unwrap(); p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `crates-io` [NOTE] waiting for `foo v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `crates-io` "#]]) .run(); // Skip `validate_upload_foo` as we just cared we got far enough for verify the token behavior. // Other tests will verify the endpoint gets the right payload. } #[cargo_test] fn simple_with_index() { // `publish` generally requires a remote registry let registry = registry::RegistryBuilder::new().http_api().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish --no-verify") .arg("--token") .arg(registry.token()) .arg("--index") .arg(registry.index_url().as_str()) .with_stderr_data(str![[r#" [UPDATING] `[ROOT]/registry` index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `[ROOT]/registry` [NOTE] waiting for `foo v0.0.1` to be available at registry `[ROOT]/registry`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `[ROOT]/registry` "#]]) .run(); // Skip `validate_upload_foo` as we just cared we got far enough for verify the VCS behavior. // Other tests will verify the endpoint gets the right payload. } #[cargo_test] fn git_deps() { // Use local registry for faster test times since no publish will occur let registry = registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [dependencies.foo] git = "git://path/to/nowhere" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] all dependencies must have a version specified when publishing. dependency `foo` does not specify a version Note: The published dependency will use the version from crates.io, the `git` specification will be removed from the dependency declaration. "#]]) .run(); } #[cargo_test] fn path_dependency_no_version() { // Use local registry for faster test times since no publish will occur let registry = registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [dependencies.bar] path = "bar" "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("publish") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] all dependencies must have a version specified when publishing. dependency `bar` does not specify a version Note: The published dependency will use the version from crates.io, the `path` specification will be removed from the dependency declaration. "#]]) .run(); } #[cargo_test] fn unpublishable_crate() { // Use local registry for faster test times since no publish will occur let registry = registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" publish = false "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish --index") .arg(registry.index_url().as_str()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] `foo` cannot be published. `package.publish` must be set to `true` or a non-empty list in Cargo.toml to publish. "#]]) .run(); } #[cargo_test] fn dont_publish_dirty() { // Use local registry for faster test times since no publish will occur let registry = registry::init(); let p = project().file("bar", "").build(); let _ = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] 1 files in the working directory contain changes that were not yet committed into git: bar to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag "#]]) .run(); } #[cargo_test] fn publish_clean() { // `publish` generally requires a remote registry let registry = registry::RegistryBuilder::new().http_api().build(); let p = project().build(); let _ = repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `crates-io` [NOTE] waiting for `foo v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `crates-io` "#]]) .run(); // Skip `validate_upload_foo_clean` as we just cared we got far enough for verify the VCS behavior. // Other tests will verify the endpoint gets the right payload. } #[cargo_test] fn publish_in_sub_repo() { // `publish` generally requires a remote registry let registry = registry::RegistryBuilder::new().http_api().build(); let p = project().no_manifest().file("baz", "").build(); let _ = repo(&paths::root().join("foo")) .file( "bar/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("publish") .replace_crates_io(registry.index_url()) .cwd("bar") .with_stderr_data(str![[r#" [UPDATING] crates.io index [PACKAGING] foo v0.0.1 ([ROOT]/foo/bar) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo/bar) [COMPILING] foo v0.0.1 ([ROOT]/foo/bar/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo/bar) [UPLOADED] foo v0.0.1 to registry `crates-io` [NOTE] waiting for `foo v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `crates-io` "#]]) .run(); // Skip `validate_upload_foo_clean` as we just cared we got far enough for verify the VCS behavior. // Other tests will verify the endpoint gets the right payload. } #[cargo_test] fn publish_when_ignored() { // `publish` generally requires a remote registry let registry = registry::RegistryBuilder::new().http_api().build(); let p = project().file("baz", "").build(); let _ = repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" "#, ) .file("src/main.rs", "fn main() {}") .file(".gitignore", "baz") .build(); p.cargo("publish") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 6 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `crates-io` [NOTE] waiting for `foo v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `crates-io` "#]]) .run(); // Skip `validate_upload` as we just cared we got far enough for verify the VCS behavior. // Other tests will verify the endpoint gets the right payload. } #[cargo_test] fn ignore_when_crate_ignored() { // `publish` generally requires a remote registry let registry = registry::RegistryBuilder::new().http_api().build(); let p = project().no_manifest().file("bar/baz", "").build(); let _ = repo(&paths::root().join("foo")) .file(".gitignore", "bar") .nocommit_file( "bar/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" "#, ) .nocommit_file("bar/src/main.rs", "fn main() {}"); p.cargo("publish") .replace_crates_io(registry.index_url()) .cwd("bar") .with_stderr_data(str![[r#" [UPDATING] crates.io index [PACKAGING] foo v0.0.1 ([ROOT]/foo/bar) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo/bar) [COMPILING] foo v0.0.1 ([ROOT]/foo/bar/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo/bar) [UPLOADED] foo v0.0.1 to registry `crates-io` [NOTE] waiting for `foo v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `crates-io` "#]]) .run(); // Skip `validate_upload` as we just cared we got far enough for verify the VCS behavior. // Other tests will verify the endpoint gets the right payload. } #[cargo_test] fn new_crate_rejected() { // Use local registry for faster test times since no publish will occur let registry = registry::init(); let p = project().file("baz", "").build(); let _ = repo(&paths::root().join("foo")) .nocommit_file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" "#, ) .nocommit_file("src/main.rs", "fn main() {}"); p.cargo("publish") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] 3 files in the working directory contain changes that were not yet committed into git: ... "#]]) .run(); } #[cargo_test] fn dry_run() { // Use local registry for faster test times since no publish will occur let registry = registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish --dry-run --index") .arg(registry.index_url().as_str()) .with_stderr_data(str![[r#" [UPDATING] `[ROOT]/registry` index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [WARNING] aborting upload due to dry run "#]]) .run(); // Ensure the API request wasn't actually made assert!(registry::api_path().join("api/v1/crates").exists()); assert!(!registry::api_path().join("api/v1/crates/new").exists()); } #[cargo_test] fn registry_not_in_publish_list() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" publish = [ "test" ] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish") .arg("--registry") .arg("alternative") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `foo` cannot be published. The registry `alternative` is not listed in the `package.publish` value in Cargo.toml. "#]]) .run(); } #[cargo_test] fn publish_empty_list() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" publish = [] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish --registry alternative") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `foo` cannot be published. `package.publish` must be set to `true` or a non-empty list in Cargo.toml to publish. "#]]) .run(); } #[cargo_test] fn publish_allowed_registry() { let _registry = RegistryBuilder::new() .http_api() .http_index() .alternative() .build(); let p = project().build(); let _ = repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" publish = ["alternative"] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish --registry alternative") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `alternative` [NOTE] waiting for `foo v0.0.1` to be available at registry `alternative`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `alternative` "#]]) .run(); publish::validate_alt_upload( CLEAN_FOO_JSON, "foo-0.0.1.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs", ".cargo_vcs_info.json", ], ); } #[cargo_test] fn publish_implicitly_to_only_allowed_registry() { let _registry = RegistryBuilder::new() .http_api() .http_index() .alternative() .build(); let p = project().build(); let _ = repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" publish = ["alternative"] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish") .with_stderr_data(str![[r#" [NOTE] found `alternative` as only allowed registry. Publishing to it automatically. [UPDATING] `alternative` index [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `alternative` [NOTE] waiting for `foo v0.0.1` to be available at registry `alternative`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `alternative` "#]]) .run(); publish::validate_alt_upload( CLEAN_FOO_JSON, "foo-0.0.1.crate", &[ "Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs", ".cargo_vcs_info.json", ], ); } #[cargo_test] fn publish_failed_with_index_and_only_allowed_registry() { let registry = RegistryBuilder::new() .http_api() .http_index() .alternative() .build(); let p = project().build(); let _ = repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" publish = ["alternative"] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish") .arg("--index") .arg(registry.index_url().as_str()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] command-line argument --index requires --token to be specified "#]]) .run(); } #[cargo_test] fn publish_fail_with_no_registry_specified() { let p = project().build(); let _ = repo(&paths::root().join("foo")) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" publish = ["alternative", "test"] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish") .with_status(101) .with_stderr_data(str![[r#" [ERROR] --registry is required to disambiguate between "alternative" or "test" registries "#]]) .run(); } #[cargo_test] fn block_publish_no_registry() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" publish = [] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish --registry alternative") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `foo` cannot be published. `package.publish` must be set to `true` or a non-empty list in Cargo.toml to publish. "#]]) .run(); } // Explicitly setting `crates-io` in the publish list. #[cargo_test] fn publish_with_crates_io_explicit() { // `publish` generally requires a remote registry let registry = registry::RegistryBuilder::new().http_api().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" publish = ["crates-io"] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish --registry alternative") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `foo` cannot be published. The registry `alternative` is not listed in the `package.publish` value in Cargo.toml. "#]]) .run(); p.cargo("publish") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `crates-io` [NOTE] waiting for `foo v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `crates-io` "#]]) .run(); } #[cargo_test] fn publish_with_select_features() { // `publish` generally requires a remote registry let registry = registry::RegistryBuilder::new().http_api().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [features] required = [] optional = [] "#, ) .file( "src/main.rs", "#[cfg(not(feature = \"required\"))] compile_error!(\"This crate requires `required` feature!\"); fn main() {}", ) .build(); p.cargo("publish --features required") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `crates-io` [NOTE] waiting for `foo v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `crates-io` "#]]) .run(); } #[cargo_test] fn publish_with_all_features() { // `publish` generally requires a remote registry let registry = registry::RegistryBuilder::new().http_api().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [features] required = [] optional = [] "#, ) .file( "src/main.rs", "#[cfg(not(feature = \"required\"))] compile_error!(\"This crate requires `required` feature!\"); fn main() {}", ) .build(); p.cargo("publish --all-features") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `crates-io` [NOTE] waiting for `foo v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `crates-io` "#]]) .run(); } #[cargo_test] fn publish_with_no_default_features() { // Use local registry for faster test times since no publish will occur let registry = registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [features] default = ["required"] required = [] "#, ) .file( "src/main.rs", "#[cfg(not(feature = \"required\"))] compile_error!(\"This crate requires `required` feature!\"); fn main() {}", ) .build(); p.cargo("publish --no-default-features") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] This crate requires `required` feature! ... "#]]) .run(); } #[cargo_test] fn publish_with_patch() { let registry = RegistryBuilder::new().http_api().http_index().build(); Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [dependencies] bar = "1.0" [patch.crates-io] bar = { path = "bar" } "#, ) .file( "src/main.rs", "extern crate bar; fn main() { bar::newfunc(); }", ) .file("bar/Cargo.toml", &basic_manifest("bar", "1.0.0")) .file("bar/src/lib.rs", "pub fn newfunc() {}") .build(); // Check that it works with the patched crate. p.cargo("build").run(); // Check that verify fails with patched crate which has new functionality. p.cargo("publish") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" ... error[E0425]: cannot find function `newfunc` in crate `bar` ... "#]]) .run(); // Remove the usage of new functionality and try again. p.change_file("src/main.rs", "extern crate bar; pub fn main() {}"); p.cargo("publish") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] bar v1.0.0 [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `crates-io` [NOTE] waiting for `foo v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `crates-io` "#]]) .run(); publish::validate_upload( r#" { "authors": [], "badges": {}, "categories": [], "deps": [ { "default_features": true, "features": [], "kind": "normal", "name": "bar", "optional": false, "target": null, "version_req": "^1.0" } ], "description": "foo", "documentation": null, "features": {}, "homepage": null, "keywords": [], "license": "MIT", "license_file": null, "links": null, "name": "foo", "readme": null, "readme_file": null, "repository": null, "rust_version": null, "vers": "0.0.1" } "#, "foo-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], ); } #[cargo_test] fn publish_checks_for_token_before_verify() { let registry = registry::RegistryBuilder::new() .no_configure_token() .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); // Assert upload token error before the package is verified p.cargo("publish") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] no token found, please run `cargo login` or use environment variable CARGO_REGISTRY_TOKEN "#]]) .with_stderr_does_not_contain("[VERIFYING] foo v0.0.1 ([CWD])") .run(); // Assert package verified successfully on dry run p.cargo("publish --dry-run") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [WARNING] aborting upload due to dry run "#]]) .run(); } #[cargo_test] fn publish_with_bad_source() { let p = project() .file( ".cargo/config.toml", r#" [source.crates-io] replace-with = 'local-registry' [source.local-registry] local-registry = 'registry' "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish") .with_status(101) .with_stderr_data(str![[r#" [ERROR] crates-io is replaced with non-remote-registry source registry `[ROOT]/foo/registry`; include `--registry crates-io` to use crates.io "#]]) .run(); p.change_file( ".cargo/config.toml", r#" [source.crates-io] replace-with = "vendored-sources" [source.vendored-sources] directory = "vendor" "#, ); p.cargo("publish") .with_status(101) .with_stderr_data(str![[r#" [ERROR] crates-io is replaced with non-remote-registry source dir [ROOT]/foo/vendor; include `--registry crates-io` to use crates.io "#]]) .run(); } // A dependency with both `git` and `version`. #[cargo_test] fn publish_git_with_version() { let registry = RegistryBuilder::new().http_api().http_index().build(); Package::new("dep1", "1.0.1") .file("src/lib.rs", "pub fn f() -> i32 {1}") .publish(); let git_project = git::new("dep1", |project| { project .file("Cargo.toml", &basic_manifest("dep1", "1.0.0")) .file("src/lib.rs", "pub fn f() -> i32 {2}") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" authors = [] edition = "2018" license = "MIT" description = "foo" [dependencies] dep1 = {{version = "1.0", git="{}"}} "#, git_project.url() ), ) .file( "src/main.rs", r#" pub fn main() { println!("{}", dep1::f()); } "#, ) .build(); p.cargo("run") .with_stdout_data(str![[r#" 2 "#]]) .run(); p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.1.0 ([ROOT]/foo) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.1.0 ([ROOT]/foo) [UPLOADED] foo v0.1.0 to registry `crates-io` [NOTE] waiting for `foo v0.1.0` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.1.0 at registry `crates-io` "#]]) .run(); publish::validate_upload_with_contents( r#" { "authors": [], "badges": {}, "categories": [], "deps": [ { "default_features": true, "features": [], "kind": "normal", "name": "dep1", "optional": false, "target": null, "version_req": "^1.0" } ], "description": "foo", "documentation": null, "features": {}, "homepage": null, "keywords": [], "license": "MIT", "license_file": null, "links": null, "name": "foo", "readme": null, "readme_file": null, "repository": null, "rust_version": null, "vers": "0.1.0" } "#, "foo-0.1.0.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], [ ( "Cargo.toml", // Check that only `version` is included in Cargo.toml. str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "foo" version = "0.1.0" authors = [] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" readme = false license = "MIT" [[bin]] name = "foo" path = "src/main.rs" [dependencies.dep1] version = "1.0" "##]], ), ( "Cargo.lock", // The important check here is that it is 1.0.1 in the registry. str![[r##" # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "dep1" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "[..]" [[package]] name = "foo" version = "0.1.0" dependencies = [ "dep1", ] "##]], ), ], ); } #[cargo_test] fn publish_dev_dep_stripping() { let registry = RegistryBuilder::new().http_api().http_index().build(); Package::new("normal-only", "1.0.0") .feature("cat", &[]) .publish(); Package::new("optional-dep-feature", "1.0.0") .feature("cat", &[]) .publish(); Package::new("optional-namespaced", "1.0.0") .feature("cat", &[]) .publish(); Package::new("optional-renamed-dep-feature", "1.0.0") .feature("cat", &[]) .publish(); Package::new("optional-renamed-namespaced", "1.0.0") .feature("cat", &[]) .publish(); Package::new("build-only", "1.0.0") .feature("cat", &[]) .publish(); Package::new("normal-and-dev", "1.0.0") .feature("cat", &[]) .publish(); Package::new("target-normal-only", "1.0.0") .feature("cat", &[]) .publish(); Package::new("target-build-only", "1.0.0") .feature("cat", &[]) .publish(); Package::new("target-normal-and-dev", "1.0.0") .feature("cat", &[]) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" [features] foo_feature = [ "normal-only/cat", "build-only/cat", "dev-only/cat", "renamed-dev-only01/cat", "normal-and-dev/cat", "target-normal-only/cat", "target-build-only/cat", "target-dev-only/cat", "target-normal-and-dev/cat", "optional-dep-feature/cat", "dep:optional-namespaced", "optional-renamed-dep-feature10/cat", "dep:optional-renamed-namespaced10", ] [dependencies] normal-only = { version = "1.0", features = ["cat"] } normal-and-dev = { version = "1.0", features = ["cat"] } optional-dep-feature = { version = "1.0", features = ["cat"], optional = true } optional-namespaced = { version = "1.0", features = ["cat"], optional = true } optional-renamed-dep-feature10 = { version = "1.0", features = ["cat"], optional = true, package = "optional-renamed-dep-feature" } optional-renamed-namespaced10 = { version = "1.0", features = ["cat"], optional = true, package = "optional-renamed-namespaced" } [build-dependencies] build-only = { version = "1.0", features = ["cat"] } [dev-dependencies] dev-only = { path = "../dev-only", features = ["cat"] } renamed-dev-only01 = { path = "../renamed-dev-only", features = ["cat"], package = "renamed-dev-only" } normal-and-dev = { version = "1.0", features = ["cat"] } [target.'cfg(unix)'.dependencies] target-normal-only = { version = "1.0", features = ["cat"] } target-normal-and-dev = { version = "1.0", features = ["cat"] } [target.'cfg(unix)'.build-dependencies] target-build-only = { version = "1.0", features = ["cat"] } [target.'cfg(unix)'.dev-dependencies] target-dev-only = { path = "../dev-only", features = ["cat"] } target-normal-and-dev = { version = "1.0", features = ["cat"] } "#, ) .file("src/main.rs", "") .file( "dev-only/Cargo.toml", r#" [package] name = "dev-only" version = "0.1.0" edition = "2015" authors = [] [features] cat = [] "#, ) .file( "dev-only/src/lib.rs", r#" #[cfg(feature = "cat")] pub fn cat() {} "#, ) .file( "renamed-dev-only/Cargo.toml", r#" [package] name = "renamed-dev-only" version = "0.1.0" edition = "2015" authors = [] [features] cat = [] "#, ) .file( "renamed-dev-only/src/lib.rs", r#" #[cfg(feature = "cat")] pub fn cat() {} "#, ) .build(); p.cargo("publish --no-verify") .env("RUSTFLAGS", "--cfg unix") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [PACKAGING] foo v0.1.0 ([ROOT]/foo) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.1.0 ([ROOT]/foo) [UPLOADED] foo v0.1.0 to registry `crates-io` [NOTE] waiting for `foo v0.1.0` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.1.0 at registry `crates-io` "#]]) .run(); publish::validate_upload_with_contents( r#" { "authors": [], "badges": {}, "categories": [], "deps": [ { "default_features": true, "features": [ "cat" ], "kind": "normal", "name": "normal-and-dev", "optional": false, "target": null, "version_req": "^1.0" }, { "default_features": true, "features": [ "cat" ], "kind": "normal", "name": "normal-only", "optional": false, "target": null, "version_req": "^1.0" }, { "default_features": true, "features": [ "cat" ], "kind": "normal", "name": "optional-dep-feature", "optional": true, "target": null, "version_req": "^1.0" }, { "default_features": true, "features": [ "cat" ], "kind": "normal", "name": "optional-namespaced", "optional": true, "target": null, "version_req": "^1.0" }, { "default_features": true, "explicit_name_in_toml": "optional-renamed-dep-feature10", "features": [ "cat" ], "kind": "normal", "name": "optional-renamed-dep-feature", "optional": true, "target": null, "version_req": "^1.0" }, { "default_features": true, "explicit_name_in_toml": "optional-renamed-namespaced10", "features": [ "cat" ], "kind": "normal", "name": "optional-renamed-namespaced", "optional": true, "target": null, "version_req": "^1.0" }, { "default_features": true, "features": [ "cat" ], "kind": "dev", "name": "normal-and-dev", "optional": false, "target": null, "version_req": "^1.0" }, { "default_features": true, "features": [ "cat" ], "kind": "build", "name": "build-only", "optional": false, "target": null, "version_req": "^1.0" }, { "default_features": true, "features": [ "cat" ], "kind": "normal", "name": "target-normal-and-dev", "optional": false, "target": "cfg(unix)", "version_req": "^1.0" }, { "default_features": true, "features": [ "cat" ], "kind": "normal", "name": "target-normal-only", "optional": false, "target": "cfg(unix)", "version_req": "^1.0" }, { "default_features": true, "features": [ "cat" ], "kind": "build", "name": "target-build-only", "optional": false, "target": "cfg(unix)", "version_req": "^1.0" }, { "default_features": true, "features": [ "cat" ], "kind": "dev", "name": "target-normal-and-dev", "optional": false, "target": "cfg(unix)", "version_req": "^1.0" } ], "description": "foo", "documentation": "foo", "features": { "foo_feature": [ "normal-only/cat", "build-only/cat", "normal-and-dev/cat", "target-normal-only/cat", "target-build-only/cat", "target-normal-and-dev/cat", "optional-dep-feature/cat", "dep:optional-namespaced", "optional-renamed-dep-feature10/cat", "dep:optional-renamed-namespaced10" ] }, "homepage": "foo", "keywords": [], "license": "MIT", "license_file": null, "links": null, "name": "foo", "readme": null, "readme_file": null, "repository": "foo", "rust_version": null, "vers": "0.1.0" } "#, "foo-0.1.0.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.1.0" authors = [] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" homepage = "foo" documentation = "foo" readme = false license = "MIT" repository = "foo" [features] foo_feature = [ "normal-only/cat", "build-only/cat", "normal-and-dev/cat", "target-normal-only/cat", "target-build-only/cat", "target-normal-and-dev/cat", "optional-dep-feature/cat", "dep:optional-namespaced", "optional-renamed-dep-feature10/cat", "dep:optional-renamed-namespaced10", ] [[bin]] name = "foo" path = "src/main.rs" [dependencies.normal-and-dev] version = "1.0" features = ["cat"] [dependencies.normal-only] version = "1.0" features = ["cat"] [dependencies.optional-dep-feature] version = "1.0" features = ["cat"] optional = true [dependencies.optional-namespaced] version = "1.0" features = ["cat"] optional = true [dependencies.optional-renamed-dep-feature10] version = "1.0" features = ["cat"] optional = true package = "optional-renamed-dep-feature" [dependencies.optional-renamed-namespaced10] version = "1.0" features = ["cat"] optional = true package = "optional-renamed-namespaced" [dev-dependencies.normal-and-dev] version = "1.0" features = ["cat"] [build-dependencies.build-only] version = "1.0" features = ["cat"] [target."cfg(unix)".dependencies.target-normal-and-dev] version = "1.0" features = ["cat"] [target."cfg(unix)".dependencies.target-normal-only] version = "1.0" features = ["cat"] [target."cfg(unix)".build-dependencies.target-build-only] version = "1.0" features = ["cat"] [target."cfg(unix)".dev-dependencies.target-normal-and-dev] version = "1.0" features = ["cat"] "##]], )], ); } #[cargo_test] fn credentials_ambiguous_filename() { // `publish` generally requires a remote registry let registry = registry::RegistryBuilder::new().http_api().build(); // Make token in `credentials.toml` incorrect to ensure it is not read. let credentials_toml = paths::home().join(".cargo/credentials.toml"); fs::write(credentials_toml, r#"token = "wrong-token""#).unwrap(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" ... Unauthorized message from server. "#]]) .run(); // Favor `credentials` if exists. let credentials = paths::home().join(".cargo/credentials"); fs::write(credentials, r#"token = "sekrit""#).unwrap(); p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] both `[ROOT]/home/.cargo/credentials` and `[ROOT]/home/.cargo/credentials.toml` exist. Using `[ROOT]/home/.cargo/credentials` [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `crates-io` [NOTE] waiting for `foo v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `crates-io` "#]]) .run(); } // --index will not load registry.token to avoid possibly leaking // crates.io token to another server. #[cargo_test] fn index_requires_token() { // Use local registry for faster test times since no publish will occur let registry = registry::init(); let credentials = paths::home().join(".cargo/credentials.toml"); fs::remove_file(&credentials).unwrap(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish --no-verify --index") .arg(registry.index_url().as_str()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] command-line argument --index requires --token to be specified "#]]) .run(); } // publish with source replacement without --registry #[cargo_test] fn cratesio_source_replacement() { registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish --no-verify") .with_status(101) .with_stderr_data(str![[r#" [ERROR] crates-io is replaced with remote registry dummy-registry; include `--registry dummy-registry` or `--registry crates-io` "#]]) .run(); } // Registry returns an API error. #[cargo_test] fn api_error_json() { let _registry = registry::RegistryBuilder::new() .alternative() .http_api() .add_responder("/api/v1/crates/new", |_, _| Response { body: br#"{"errors": [{"detail": "you must be logged in"}]}"#.to_vec(), code: 403, headers: vec![], }) .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish --no-verify --registry alternative") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.0.1 ([ROOT]/foo) [ERROR] failed to publish to registry at http://127.0.0.1:[..]/ Caused by: the remote server responded with an error (status 403 Forbidden): you must be logged in "#]]) .run(); } // Registry returns an API error with a 200 status code. #[cargo_test] fn api_error_200() { let _registry = registry::RegistryBuilder::new() .alternative() .http_api() .add_responder("/api/v1/crates/new", |_, _| Response { body: br#"{"errors": [{"detail": "max upload size is 123"}]}"#.to_vec(), code: 200, headers: vec![], }) .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish --no-verify --registry alternative") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.0.1 ([ROOT]/foo) [ERROR] failed to publish to registry at http://127.0.0.1:[..]/ Caused by: the remote server responded with an [ERROR] max upload size is 123 "#]]) .run(); } // Registry returns an error code without a JSON message. #[cargo_test] fn api_error_code() { let _registry = registry::RegistryBuilder::new() .alternative() .http_api() .add_responder("/api/v1/crates/new", |_, _| Response { body: br#"go away"#.to_vec(), code: 400, headers: vec![], }) .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish --no-verify --registry alternative") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.0.1 ([ROOT]/foo) [ERROR] failed to publish to registry at http://127.0.0.1:[..]/ Caused by: failed to get a 200 OK response, got 400 headers: HTTP/1.1 400 Content-Length: 7 Connection: close body: go away "#]]) .run(); } // Registry has a network error. #[cargo_test] fn api_curl_error() { let _registry = registry::RegistryBuilder::new() .alternative() .http_api() .add_responder("/api/v1/crates/new", |_, _| { panic!("broke"); }) .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" "#, ) .file("src/lib.rs", "") .build(); // This doesn't check for the exact text of the error in the remote // possibility that cargo is linked with a weird version of libcurl, or // curl changes the text of the message. Currently the message 52 // (CURLE_GOT_NOTHING) is: // Server returned nothing (no headers, no data) (Empty reply from server) p.cargo("publish --no-verify --registry alternative") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.0.1 ([ROOT]/foo) [ERROR] failed to publish to registry at http://127.0.0.1:[..]/ Caused by: [52] Server returned nothing (no headers, no data) (Empty reply from server) "#]]) .run(); } // Registry returns an invalid response. #[cargo_test] fn api_other_error() { let _registry = registry::RegistryBuilder::new() .alternative() .http_api() .add_responder("/api/v1/crates/new", |_, _| Response { body: b"\xff".to_vec(), code: 200, headers: vec![], }) .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish --no-verify --registry alternative") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.0.1 ([ROOT]/foo) [ERROR] failed to publish to registry at http://127.0.0.1:[..]/ Caused by: invalid response body from server Caused by: invalid utf-8 sequence of 1 bytes from index 0 "#]]) .run(); } #[cargo_test] fn in_package_workspace() { let registry = RegistryBuilder::new().http_api().http_index().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2021" [workspace] members = ["li"] "#, ) .file("src/main.rs", "fn main() {}") .file( "li/Cargo.toml", r#" [package] name = "li" version = "0.0.1" edition = "2015" rust-version = "1.69" description = "li" license = "MIT" "#, ) .file("li/src/main.rs", "fn main() {}") .build(); p.cargo("publish -p li --no-verify") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] li v0.0.1 ([ROOT]/foo/li) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] li v0.0.1 ([ROOT]/foo/li) [UPLOADED] li v0.0.1 to registry `crates-io` [NOTE] waiting for `li v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] li v0.0.1 at registry `crates-io` "#]]) .run(); validate_upload_li(); } #[cargo_test] fn with_duplicate_spec_in_members() { // Use local registry for faster test times since no publish will occur let registry = registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] resolver = "2" members = ["li","bar"] default-members = ["li","bar"] "#, ) .file("src/main.rs", "fn main() {}") .file( "li/Cargo.toml", r#" [package] name = "li" version = "0.0.1" edition = "2015" description = "li" license = "MIT" "#, ) .file("li/src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" description = "bar" license = "MIT" "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `-p` argument must be specified to select a single package to publish "#]]) .run(); } #[cargo_test] fn in_package_workspace_with_members_with_features_old() { let registry = RegistryBuilder::new().http_api().http_index().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["li"] "#, ) .file("src/main.rs", "fn main() {}") .file( "li/Cargo.toml", r#" [package] name = "li" version = "0.0.1" edition = "2015" rust-version = "1.69" description = "li" license = "MIT" "#, ) .file("li/src/main.rs", "fn main() {}") .build(); p.cargo("publish -p li --no-verify") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] li v0.0.1 ([ROOT]/foo/li) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] li v0.0.1 ([ROOT]/foo/li) [UPLOADED] li v0.0.1 to registry `crates-io` [NOTE] waiting for `li v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] li v0.0.1 at registry `crates-io` "#]]) .run(); validate_upload_li(); } #[cargo_test] fn in_virtual_workspace() { // Use local registry for faster test times since no publish will occur let registry = registry::init(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo"] "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("foo/src/main.rs", "fn main() {}") .build(); p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `-p` argument must be specified in the root of a virtual workspace "#]]) .run(); } #[cargo_test] fn in_virtual_workspace_with_p() { // `publish` generally requires a remote registry let registry = registry::RegistryBuilder::new().http_api().build(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo","li"] "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("foo/src/main.rs", "fn main() {}") .file( "li/Cargo.toml", r#" [package] name = "li" version = "0.0.1" edition = "2015" rust-version = "1.69" description = "li" license = "MIT" "#, ) .file("li/src/main.rs", "fn main() {}") .build(); p.cargo("publish -p li --no-verify") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] li v0.0.1 ([ROOT]/foo/li) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] li v0.0.1 ([ROOT]/foo/li) [UPLOADED] li v0.0.1 to registry `crates-io` [NOTE] waiting for `li v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] li v0.0.1 at registry `crates-io` "#]]) .run(); } #[cargo_test] fn in_package_workspace_not_found() { // Use local registry for faster test times since no publish will occur let registry = registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2021" [workspace] "#, ) .file("src/main.rs", "fn main() {}") .file( "li/Cargo.toml", r#" [package] name = "li" version = "0.0.1" edition = "2021" authors = [] license = "MIT" description = "li" "#, ) .file("li/src/main.rs", "fn main() {}") .build(); p.cargo("publish -p li --no-verify") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] package ID specification `li` did not match any packages Did you mean `foo`? "#]]) .run(); } #[cargo_test] fn in_package_workspace_found_multiple() { // Use local registry for faster test times since no publish will occur let registry = registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2021" [workspace] members = ["li","lii"] "#, ) .file("src/main.rs", "fn main() {}") .file( "li/Cargo.toml", r#" [package] name = "li" version = "0.0.1" edition = "2021" authors = [] license = "MIT" description = "li" "#, ) .file("li/src/main.rs", "fn main() {}") .file( "lii/Cargo.toml", r#" [package] name = "lii" version = "0.0.1" edition = "2021" authors = [] license = "MIT" description = "lii" "#, ) .file("lii/src/main.rs", "fn main() {}") .build(); p.cargo("publish -p li* --no-verify") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `-p` argument must be specified to select a single package to publish "#]]) .run(); } #[cargo_test] // https://github.com/rust-lang/cargo/issues/10536 fn publish_path_dependency_without_workspace() { // Use local registry for faster test times since no publish will occur let registry = registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2021" [dependencies.bar] path = "bar" "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2021" authors = [] license = "MIT" description = "bar" "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("publish -p bar --no-verify") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] package ID specification `bar` did not match any packages Did you mean `foo`? "#]]) .run(); } #[cargo_test] fn http_api_not_noop() { let registry = registry::RegistryBuilder::new().http_api().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `crates-io` [NOTE] waiting for `foo v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `crates-io` "#]]) .run(); let p = project() .file( "Cargo.toml", r#" [project] name = "bar" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [dependencies] foo = "0.0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build").run(); } #[cargo_test] fn wait_for_first_publish() { // Counter for number of tries before the package is "published" let arc: Arc> = Arc::new(Mutex::new(0)); let arc2 = arc.clone(); // Registry returns an invalid response. let registry = registry::RegistryBuilder::new() .http_index() .http_api() .add_responder("/index/de/la/delay", move |req, server| { let mut lock = arc.lock().unwrap(); *lock += 1; if *lock <= 1 { server.not_found(req) } else { server.index(req) } }) .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "delay" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .with_status(0) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] delay v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] delay v0.0.1 ([ROOT]/foo) [UPLOADED] delay v0.0.1 to registry `crates-io` [NOTE] waiting for `delay v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] delay v0.0.1 at registry `crates-io` "#]]) .run(); // Verify the responder has been pinged let lock = arc2.lock().unwrap(); assert_eq!(*lock, 2); drop(lock); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] delay = "0.0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build").with_status(0).run(); } /// A separate test is needed for package names with - or _ as they hit /// the responder twice per cargo invocation. If that ever gets changed /// this test will need to be changed accordingly. #[cargo_test] fn wait_for_first_publish_underscore() { // Counter for number of tries before the package is "published" let arc: Arc> = Arc::new(Mutex::new(0)); let arc2 = arc.clone(); let misses = Arc::new(Mutex::new(Vec::new())); let misses2 = misses.clone(); // Registry returns an invalid response. let registry = registry::RegistryBuilder::new() .http_index() .http_api() .add_responder("/index/de/la/delay_with_underscore", move |req, server| { let mut lock = arc.lock().unwrap(); *lock += 1; if *lock <= 1 { server.not_found(req) } else { server.index(req) } }) .not_found_handler(move |req, _| { misses.lock().unwrap().push(req.url.to_string()); Response { body: b"not found".to_vec(), code: 404, headers: vec![], } }) .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "delay_with_underscore" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .with_status(0) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] delay_with_underscore v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] delay_with_underscore v0.0.1 ([ROOT]/foo) [UPLOADED] delay_with_underscore v0.0.1 to registry `crates-io` [NOTE] waiting for `delay_with_underscore v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] delay_with_underscore v0.0.1 at registry `crates-io` "#]]) .run(); // Verify the repsponder has been pinged let lock = arc2.lock().unwrap(); assert_eq!(*lock, 2); drop(lock); { let misses = misses2.lock().unwrap(); assert!( misses.len() == 1, "should only have 1 not found URL; instead found {misses:?}" ); } let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] delay_with_underscore = "0.0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build").with_status(0).run(); } #[cargo_test] fn wait_for_subsequent_publish() { // Counter for number of tries before the package is "published" let arc: Arc> = Arc::new(Mutex::new(0)); let arc2 = arc.clone(); let publish_req = Arc::new(Mutex::new(None)); let publish_req2 = publish_req.clone(); let registry = registry::RegistryBuilder::new() .http_index() .http_api() .add_responder("/api/v1/crates/new", move |req, server| { // Capture the publish request, but defer publishing *publish_req.lock().unwrap() = Some(req.clone()); server.ok(req) }) .add_responder("/index/de/la/delay", move |req, server| { let mut lock = arc.lock().unwrap(); *lock += 1; if *lock == 3 { // Run the publish on the 3rd attempt let rep = server .check_authorized_publish(&publish_req2.lock().unwrap().as_ref().unwrap()); assert_eq!(rep.code, 200); } server.index(req) }) .build(); // Publish an earlier version Package::new("delay", "0.0.1") .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "delay" version = "0.0.2" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .with_status(0) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] delay v0.0.2 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] delay v0.0.2 ([ROOT]/foo) [UPLOADED] delay v0.0.2 to registry `crates-io` [NOTE] waiting for `delay v0.0.2` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] delay v0.0.2 at registry `crates-io` "#]]) .run(); // Verify the responder has been pinged let lock = arc2.lock().unwrap(); assert_eq!(*lock, 3); drop(lock); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] delay = "0.0.2" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check").with_status(0).run(); } #[cargo_test] fn skip_wait_for_publish() { // Intentionally using local registry so the crate never makes it to the index let registry = registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", " [publish] timeout = 0 ", ) .build(); p.cargo("publish --no-verify -Zpublish-timeout") .replace_crates_io(registry.index_url()) .masquerade_as_nightly_cargo(&["publish-timeout"]) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `crates-io` "#]]) .run(); } #[cargo_test] fn timeout_waiting_for_publish() { // Publish doesn't happen within the timeout window. let registry = registry::RegistryBuilder::new() .http_api() .delayed_index_update(20) .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "delay" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [publish] timeout = 2 "#, ) .build(); p.cargo("publish --no-verify -Zpublish-timeout") .replace_crates_io(registry.index_url()) .masquerade_as_nightly_cargo(&["publish-timeout"]) .with_status(0) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] delay v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] delay v0.0.1 ([ROOT]/foo) [UPLOADED] delay v0.0.1 to registry `crates-io` [NOTE] waiting for `delay v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [WARNING] timed out waiting for `delay v0.0.1` to be available in registry `crates-io` [NOTE] the registry may have a backlog that is delaying making the crate available. The crate should be available soon. "#]]) .run(); } #[cargo_test] fn timeout_waiting_for_dependency_publish() { // Publish doesn't happen within the timeout window. let registry = registry::RegistryBuilder::new() .http_api() .delayed_index_update(20) .build(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["main", "other", "dep"] "#, ) .file( "main/Cargo.toml", r#" [package] name = "main" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [dependencies] dep = { version = "0.0.1", path = "../dep" } "#, ) .file("main/src/main.rs", "fn main() {}") .file( "other/Cargo.toml", r#" [package] name = "other" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [dependencies] dep = { version = "0.0.1", path = "../dep" } "#, ) .file("other/src/main.rs", "fn main() {}") .file( "dep/Cargo.toml", r#" [package] name = "dep" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("dep/src/lib.rs", "") .file( ".cargo/config.toml", r#" [publish] timeout = 2 "#, ) .build(); p.cargo("publish --no-verify -Zpublish-timeout -Zpackage-workspace") .replace_crates_io(registry.index_url()) .masquerade_as_nightly_cargo(&["publish-timeout", "package-workspace"]) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] dep v0.0.1 ([ROOT]/foo/dep) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] main v0.0.1 ([ROOT]/foo/main) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] other v0.0.1 ([ROOT]/foo/other) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] dep v0.0.1 ([ROOT]/foo/dep) [UPLOADED] dep v0.0.1 to registry `crates-io` [NOTE] waiting for `dep v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [WARNING] timed out waiting for `dep v0.0.1` to be available in registry `crates-io` [NOTE] the registry may have a backlog that is delaying making the crate available. The crate should be available soon. [ERROR] unable to publish `main v0.0.1` and `other v0.0.1` due to time out while waiting for published dependencies to be available. "#]]) .run(); } #[cargo_test] fn package_selection() { let registry = registry::RegistryBuilder::new().http_api().build(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file("a/Cargo.toml", &basic_manifest("a", "0.1.0")) .file("a/src/lib.rs", "#[test] fn a() {}") .file("b/Cargo.toml", &basic_manifest("b", "0.1.0")) .file("b/src/lib.rs", "#[test] fn b() {}") .build(); p.cargo("publish --no-verify --dry-run -Zpackage-workspace --workspace") .replace_crates_io(registry.index_url()) .masquerade_as_nightly_cargo(&["package-workspace"]) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] a v0.1.0 ([ROOT]/foo/a) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] b v0.1.0 ([ROOT]/foo/b) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] a v0.1.0 ([ROOT]/foo/a) [WARNING] aborting upload due to dry run [UPLOADING] b v0.1.0 ([ROOT]/foo/b) [WARNING] aborting upload due to dry run "#]]) .with_stdout_data(str![[r#""#]]) .run(); p.cargo("publish --no-verify --dry-run -Zpackage-workspace --package a --package b") .replace_crates_io(registry.index_url()) .masquerade_as_nightly_cargo(&["package-workspace"]) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] a v0.1.0 ([ROOT]/foo/a) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] b v0.1.0 ([ROOT]/foo/b) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] a v0.1.0 ([ROOT]/foo/a) [WARNING] aborting upload due to dry run [UPLOADING] b v0.1.0 ([ROOT]/foo/b) [WARNING] aborting upload due to dry run "#]]) .with_stdout_data(str![[r#""#]]) .run(); p.cargo("publish --no-verify --dry-run -Zpackage-workspace --workspace --exclude b") .replace_crates_io(registry.index_url()) .masquerade_as_nightly_cargo(&["package-workspace"]) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no description, license, license-file, documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] a v0.1.0 ([ROOT]/foo/a) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] a v0.1.0 ([ROOT]/foo/a) [WARNING] aborting upload due to dry run "#]]) .with_stdout_data(str![[r#""#]]) .run(); p.cargo("publish --no-verify --dry-run --package a --package b") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `--package (multiple occurrences)` flag is unstable, and only available on the nightly channel of Cargo, but this is the `stable` channel See https://doc.rust-lang.org/book/appendix-07-nightly-rust.html for more information about Rust release channels. See https://github.com/rust-lang/cargo/issues/10948 for more information about the `--package (multiple occurrences)` flag. "#]]) .with_stdout_data(str![[r#""#]]) .run(); p.cargo("publish --no-verify --dry-run --workspace") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `--workspace` flag is unstable, and only available on the nightly channel of Cargo, but this is the `stable` channel See https://doc.rust-lang.org/book/appendix-07-nightly-rust.html for more information about Rust release channels. See https://github.com/rust-lang/cargo/issues/10948 for more information about the `--workspace` flag. "#]]) .with_stdout_data(str![[r#""#]]) .run(); p.cargo("publish --no-verify --dry-run --exclude b") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `--exclude` flag is unstable, and only available on the nightly channel of Cargo, but this is the `stable` channel See https://doc.rust-lang.org/book/appendix-07-nightly-rust.html for more information about Rust release channels. See https://github.com/rust-lang/cargo/issues/10948 for more information about the `--exclude` flag. "#]]) .with_stdout_data(str![[r#""#]]) .run(); } #[cargo_test] fn wait_for_git_publish() { // Slow publish to an index with a git index. let registry = registry::RegistryBuilder::new() .http_api() .delayed_index_update(5) .build(); // Publish an earlier version Package::new("delay", "0.0.1") .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "delay" version = "0.0.2" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .with_status(0) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] delay v0.0.2 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] delay v0.0.2 ([ROOT]/foo) [UPLOADED] delay v0.0.2 to registry `crates-io` [NOTE] waiting for `delay v0.0.2` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] delay v0.0.2 at registry `crates-io` "#]]) .run(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] delay = "0.0.2" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check").with_status(0).run(); } #[cargo_test] fn invalid_token() { // Checks publish behavior with an invalid token. let registry = RegistryBuilder::new().http_api().http_index().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish --no-verify") .replace_crates_io(registry.index_url()) .env("CARGO_REGISTRY_TOKEN", "\x16") .with_stderr_data(str![[r#" [UPDATING] crates.io index [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [UPLOADING] foo v0.0.1 ([ROOT]/foo) [ERROR] failed to publish to registry at http://127.0.0.1:[..]/ Caused by: token contains invalid characters. Only printable ISO-8859-1 characters are allowed as it is sent in a HTTPS header. "#]]) .with_status(101) .run(); } #[cargo_test] fn versionless_package() { // Use local registry for faster test times since no publish will occur let registry = registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" description = "foo" "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); p.cargo("publish") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] `foo` cannot be published. `package.publish` must be set to `true` or a non-empty list in Cargo.toml to publish. "#]]) .run(); } // A workspace with three projects that depend on one another (level1 -> level2 -> level3). // level1 is a binary package, to test lockfile generation. fn workspace_with_local_deps_project() -> Project { project() .file( "Cargo.toml", r#" [workspace] members = ["level1", "level2", "level3"] [workspace.dependencies] level2 = { path = "level2", version = "0.0.1" } "# ) .file( "level1/Cargo.toml", r#" [package] name = "level1" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level1" repository = "bar" [dependencies] # Let one dependency also specify features, for the added test coverage when generating package files. level2 = { workspace = true, features = ["foo"] } "#, ) .file("level1/src/main.rs", "fn main() {}") .file( "level2/Cargo.toml", r#" [package] name = "level2" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level2" repository = "bar" [features] foo = [] [dependencies] level3 = { path = "../level3", version = "0.0.1" } "# ) .file("level2/src/lib.rs", "") .file( "level3/Cargo.toml", r#" [package] name = "level3" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "level3" repository = "bar" "#, ) .file("level3/src/lib.rs", "") .build() } #[cargo_test] fn workspace_with_local_deps() { let crates_io = registry::init(); let p = workspace_with_local_deps_project(); p.cargo("publish") .replace_crates_io(crates_io.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `-p` argument must be specified to select a single package to publish "#]]) .run(); } #[cargo_test] fn workspace_with_local_deps_nightly() { let registry = RegistryBuilder::new().http_api().http_index().build(); let p = workspace_with_local_deps_project(); p.cargo("publish -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [PACKAGING] level3 v0.0.1 ([ROOT]/foo/level3) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] level2 v0.0.1 ([ROOT]/foo/level2) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] level1 v0.0.1 ([ROOT]/foo/level1) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] level3 v0.0.1 ([ROOT]/foo/level3) [COMPILING] level3 v0.0.1 ([ROOT]/foo/target/package/level3-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] level2 v0.0.1 ([ROOT]/foo/level2) [UPDATING] crates.io index [UNPACKING] level3 v0.0.1 (registry `[ROOT]/foo/target/package/tmp-registry`) [COMPILING] level3 v0.0.1 [COMPILING] level2 v0.0.1 ([ROOT]/foo/target/package/level2-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] level1 v0.0.1 ([ROOT]/foo/level1) [UPDATING] crates.io index [UNPACKING] level2 v0.0.1 (registry `[ROOT]/foo/target/package/tmp-registry`) [COMPILING] level3 v0.0.1 [COMPILING] level2 v0.0.1 [COMPILING] level1 v0.0.1 ([ROOT]/foo/target/package/level1-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] level3 v0.0.1 ([ROOT]/foo/level3) [UPLOADED] level3 v0.0.1 to registry `crates-io` [NOTE] waiting for `level3 v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] level3 v0.0.1 at registry `crates-io` [UPLOADING] level2 v0.0.1 ([ROOT]/foo/level2) [UPLOADED] level2 v0.0.1 to registry `crates-io` [NOTE] waiting for `level2 v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] level2 v0.0.1 at registry `crates-io` [UPLOADING] level1 v0.0.1 ([ROOT]/foo/level1) [UPLOADED] level1 v0.0.1 to registry `crates-io` [NOTE] waiting for `level1 v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] level1 v0.0.1 at registry `crates-io` "#]]) .run(); } #[cargo_test] fn workspace_parallel() { let registry = RegistryBuilder::new().http_api().http_index().build(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b", "c"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "a" repository = "bar" "#, ) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "b" repository = "bar" "#, ) .file("b/src/lib.rs", "") .file( "c/Cargo.toml", r#" [package] name = "c" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "c" repository = "bar" [dependencies] a = { path = "../a", version = "0.0.1" } b = { path = "../b", version = "0.0.1" } "#, ) .file("c/src/lib.rs", "") .build(); p.cargo("publish -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .replace_crates_io(registry.index_url()) .with_stderr_data( str![[r#" [UPDATING] crates.io index [PACKAGING] a v0.0.1 ([ROOT]/foo/a) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] b v0.0.1 ([ROOT]/foo/b) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [PACKAGING] c v0.0.1 ([ROOT]/foo/c) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] a v0.0.1 ([ROOT]/foo/a) [COMPILING] a v0.0.1 ([ROOT]/foo/target/package/a-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] b v0.0.1 ([ROOT]/foo/b) [COMPILING] b v0.0.1 ([ROOT]/foo/target/package/b-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] c v0.0.1 ([ROOT]/foo/c) [UPDATING] crates.io index [UNPACKING] a v0.0.1 (registry `[ROOT]/foo/target/package/tmp-registry`) [UNPACKING] b v0.0.1 (registry `[ROOT]/foo/target/package/tmp-registry`) [COMPILING] a v0.0.1 [COMPILING] b v0.0.1 [COMPILING] c v0.0.1 ([ROOT]/foo/target/package/c-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADED] b v0.0.1 to registry `crates-io` [UPLOADED] a v0.0.1 to registry `crates-io` [NOTE] waiting for `a v0.0.1` or `b v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] a v0.0.1, b v0.0.1 at registry `crates-io` [UPLOADING] c v0.0.1 ([ROOT]/foo/c) [UPLOADED] c v0.0.1 to registry `crates-io` [NOTE] waiting for `c v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] c v0.0.1 at registry `crates-io` [UPLOADING] a v0.0.1 ([ROOT]/foo/a) [UPLOADING] b v0.0.1 ([ROOT]/foo/b) [UPDATING] crates.io index "#]] .unordered(), ) .run(); } #[cargo_test] fn workspace_missing_dependency() { let registry = RegistryBuilder::new().http_api().http_index().build(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "a" repository = "bar" "#, ) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "b" repository = "bar" [dependencies] a = { path = "../a", version = "0.0.1" } "#, ) .file("b/src/lib.rs", "") .build(); p.cargo("publish -Zpackage-workspace -p b") .masquerade_as_nightly_cargo(&["package-workspace"]) .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [PACKAGING] b v0.0.1 ([ROOT]/foo/b) [UPDATING] crates.io index [ERROR] failed to prepare local package for uploading Caused by: no matching package named `a` found location searched: crates.io index required by package `b v0.0.1 ([ROOT]/foo/b)` "#]]) .run(); p.cargo("publish -Zpackage-workspace -p a") .masquerade_as_nightly_cargo(&["package-workspace"]) .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [PACKAGING] a v0.0.1 ([ROOT]/foo/a) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] a v0.0.1 ([ROOT]/foo/a) [COMPILING] a v0.0.1 ([ROOT]/foo/target/package/a-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] a v0.0.1 ([ROOT]/foo/a) [UPLOADED] a v0.0.1 to registry `crates-io` [NOTE] waiting for `a v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] a v0.0.1 at registry `crates-io` "#]]) .run(); // Publishing the whole workspace now will fail, as `a` is already published. p.cargo("publish -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] crate a@0.0.1 already exists on crates.io index "#]]) .run(); } #[cargo_test] fn one_unpublishable_package() { let _alt_reg = registry::RegistryBuilder::new() .http_api() .http_index() .alternative() .build(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["dep", "main"] "#, ) .file( "main/Cargo.toml", r#" [package] name = "main" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "main" repository = "bar" publish = false [dependencies] dep = { path = "../dep", version = "0.1.0", registry = "alternative" } "#, ) .file("main/src/main.rs", "fn main() {}") .file( "dep/Cargo.toml", r#" [package] name = "dep" version = "0.1.0" edition = "2015" authors = [] license = "MIT" description = "dep" repository = "bar" publish = ["alternative"] "#, ) .file("dep/src/lib.rs", "") .build(); p.cargo("publish -Zpackage-workspace") .masquerade_as_nightly_cargo(&["package-workspace"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] `main` cannot be published. `package.publish` must be set to `true` or a non-empty list in Cargo.toml to publish. "#]]) .run(); } cargo-0.86.0/tests/testsuite/publish_lockfile.rs000064400000000000000000000415751046102023000201050ustar 00000000000000//! Tests for including `Cargo.lock` when publishing/packaging. use std::fs::File; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{ basic_manifest, cargo_process, git, paths, project, publish::validate_crate_contents, str, }; fn pl_manifest(name: &str, version: &str, extra: &str) -> String { format!( r#" [package] name = "{}" version = "{}" edition = "2015" authors = [] license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" {} "#, name, version, extra ) } #[cargo_test] fn removed() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["publish-lockfile"] [package] name = "foo" version = "0.1.0" edition = "2015" publish-lockfile = true license = "MIT" description = "foo" documentation = "foo" homepage = "foo" repository = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("package") .masquerade_as_nightly_cargo(&["publish-lockfile"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: the cargo feature `publish-lockfile` has been removed in the 1.37 release Remove the feature from Cargo.toml to remove this error. See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#publish-lockfile for more information about using this feature. "#]]) .run(); } #[cargo_test] fn package_lockfile() { let p = project() .file("Cargo.toml", &pl_manifest("foo", "0.0.1", "")) .file("src/main.rs", "fn main() {}") .build(); p.cargo("package") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.root().join("target/package/foo-0.0.1.crate").is_file()); p.cargo("package -l") .with_stdout_data(str![[r#" Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); p.cargo("package") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &["Cargo.toml", "Cargo.toml.orig", "Cargo.lock", "src/main.rs"], (), ); } #[cargo_test] fn package_lockfile_git_repo() { // Create a Git repository containing a minimal Rust project. let g = git::repo(&paths::root().join("foo")) .file("Cargo.toml", &pl_manifest("foo", "0.0.1", "")) .file("src/main.rs", "fn main() {}") .build(); cargo_process("package -l") .cwd(g.root()) .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); cargo_process("package -v") .cwd(g.root()) .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [ARCHIVING] .cargo_vcs_info.json [ARCHIVING] Cargo.lock [ARCHIVING] Cargo.toml [ARCHIVING] Cargo.toml.orig [ARCHIVING] src/main.rs [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn lock_file_with_library() { let p = project() .file("Cargo.toml", &pl_manifest("foo", "0.0.1", "")) .file("src/lib.rs", "") .build(); p.cargo("package").run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "Cargo.lock"], (), ); } #[cargo_test] fn lock_file_and_workspace() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo"] "#, ) .file("foo/Cargo.toml", &pl_manifest("foo", "0.0.1", "")) .file("foo/src/main.rs", "fn main() {}") .build(); p.cargo("package").cwd("foo").run(); let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &["Cargo.toml", "Cargo.toml.orig", "src/main.rs", "Cargo.lock"], (), ); } #[cargo_test] fn note_resolve_changes() { // `multi` has multiple sources (path and registry). Package::new("multi", "0.1.0").publish(); // `updated` is always from registry, but should not change. Package::new("updated", "1.0.0").publish(); // `patched` is [patch]ed. Package::new("patched", "1.0.0").publish(); let p = project() .file( "Cargo.toml", &pl_manifest( "foo", "0.0.1", r#" [dependencies] multi = { path = "multi", version = "0.1" } updated = "1.0" patched = "1.0" [patch.crates-io] patched = { path = "patched" } "#, ), ) .file("src/main.rs", "fn main() {}") .file("multi/Cargo.toml", &basic_manifest("multi", "0.1.0")) .file("multi/src/lib.rs", "") .file("patched/Cargo.toml", &basic_manifest("patched", "1.0.0")) .file("patched/src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); // Make sure this does not change or warn. Package::new("updated", "1.0.1").publish(); p.cargo("package --no-verify -v --allow-dirty") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [ARCHIVING] Cargo.lock [UPDATING] `dummy-registry` index [NOTE] package `multi v0.1.0` added to the packaged Cargo.lock file, was originally sourced from `[ROOT]/foo/multi` [NOTE] package `patched v1.0.0` added to the packaged Cargo.lock file, was originally sourced from `[ROOT]/foo/patched` [ARCHIVING] Cargo.toml [ARCHIVING] Cargo.toml.orig [ARCHIVING] src/main.rs [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [WARNING] found (git) Cargo.toml ignored at `[..]/foo/Cargo.toml` in workdir `[..]` "#]].unordered()) .run(); } #[cargo_test] fn outdated_lock_version_change_does_not_warn() { // If the version of the package being packaged changes, but Cargo.lock is // not updated, don't bother warning about it. let p = project() .file("Cargo.toml", &pl_manifest("foo", "0.1.0", "")) .file("src/main.rs", "fn main() {}") .build(); p.cargo("generate-lockfile").run(); p.change_file("Cargo.toml", &pl_manifest("foo", "0.2.0", "")); p.cargo("package --no-verify") .with_stderr_data(str![[r#" [PACKAGING] foo v0.2.0 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) "#]]) .run(); } #[cargo_test] fn no_warn_workspace_extras() { // Other entries in workspace lock file should be ignored. Package::new("dep1", "1.0.0").publish(); Package::new("dep2", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file( "a/Cargo.toml", &pl_manifest( "a", "0.1.0", r#" [dependencies] dep1 = "1.0" "#, ), ) .file("a/src/main.rs", "fn main() {}") .file( "b/Cargo.toml", &pl_manifest( "b", "0.1.0", r#" [dependencies] dep2 = "1.0" "#, ), ) .file("b/src/main.rs", "fn main() {}") .build(); p.cargo("generate-lockfile").run(); p.cargo("package --no-verify") .cwd("a") .with_stderr_data(str![[r#" [PACKAGING] a v0.1.0 ([ROOT]/foo/a) [UPDATING] `dummy-registry` index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) "#]]) .run(); } #[cargo_test] fn warn_package_with_yanked() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", &pl_manifest( "foo", "0.0.1", r#" [dependencies] bar = "0.1" "#, ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("generate-lockfile").run(); Package::new("bar", "0.1.0").yanked(true).publish(); // Make sure it sticks with the locked (yanked) version. Package::new("bar", "0.1.1").publish(); p.cargo("package --no-verify") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [UPDATING] `dummy-registry` index [WARNING] package `bar v0.1.0` in Cargo.lock is yanked in registry `crates-io`, consider updating to a version that is not yanked [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) "#]]) .run(); } #[cargo_test] fn warn_install_with_yanked() { Package::new("bar", "0.1.0").yanked(true).publish(); Package::new("bar", "0.1.1").publish(); Package::new("foo", "0.1.0") .dep("bar", "0.1") .file("src/main.rs", "fn main() {}") .file( "Cargo.lock", r#" [[package]] name = "bar" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "foo" version = "0.1.0" dependencies = [ "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] "#, ) .publish(); cargo_process("install --locked foo") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.1.0 (registry `dummy-registry`) [INSTALLING] foo v0.1.0 [WARNING] package `bar v0.1.0` in Cargo.lock is yanked in registry `crates-io`, consider running without --locked [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [COMPILING] bar v0.1.0 [COMPILING] foo v0.1.0 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.1.0` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); // Try again without --locked, make sure it uses 0.1.1 and does not warn. cargo_process("install --force foo") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [INSTALLING] foo v0.1.0 [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.1 (registry `dummy-registry`) [COMPILING] bar v0.1.1 [COMPILING] foo v0.1.0 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [REPLACING] [ROOT]/home/.cargo/bin/foo[EXE] [REPLACED] package `foo v0.1.0` with `foo v0.1.0` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); } #[cargo_test] fn ignore_lockfile() { // With an explicit `include` list, but Cargo.lock in .gitignore, don't // complain about `Cargo.lock` being ignored. Note that it is still // included in the packaged regardless. let p = git::new("foo", |p| { p.file( "Cargo.toml", &pl_manifest( "foo", "0.0.1", r#" include = [ "src/main.rs" ] "#, ), ) .file("src/main.rs", "fn main() {}") .file(".gitignore", "Cargo.lock") }); p.cargo("package -l") .with_stdout_data(str![[r#" .cargo_vcs_info.json Cargo.lock Cargo.toml Cargo.toml.orig src/main.rs "#]]) .run(); p.cargo("generate-lockfile").run(); p.cargo("package -v") .with_stderr_data(str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [ARCHIVING] .cargo_vcs_info.json [ARCHIVING] Cargo.lock [ARCHIVING] Cargo.toml [ARCHIVING] Cargo.toml.orig [ARCHIVING] src/main.rs [PACKAGED] 5 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn ignore_lockfile_inner() { // Ignore `Cargo.lock` if in .gitignore in a git subdirectory. let p = git::new("foo", |p| { p.no_manifest() .file("bar/Cargo.toml", &pl_manifest("bar", "0.0.1", "")) .file("bar/src/main.rs", "fn main() {}") .file("bar/.gitignore", "Cargo.lock") }); p.cargo("generate-lockfile").cwd("bar").run(); p.cargo("package -v --no-verify") .cwd("bar") .with_stderr_data(str![[r#" [PACKAGING] bar v0.0.1 ([ROOT]/foo/bar) [ARCHIVING] .cargo_vcs_info.json [ARCHIVING] .gitignore [ARCHIVING] Cargo.lock [ARCHIVING] Cargo.toml [ARCHIVING] Cargo.toml.orig [ARCHIVING] src/main.rs [PACKAGED] 6 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) "#]]) .run(); } #[cargo_test] fn use_workspace_root_lockfile() { // Issue #11148 // Workspace members should use `Cargo.lock` at workspace root Package::new("serde", "0.2.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [dependencies] serde = "0.2" [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "bar" workspace = ".." [dependencies] serde = "0.2" "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); // Create `Cargo.lock` in the workspace root. p.cargo("generate-lockfile").run(); // Now, add a newer version of `serde`. Package::new("serde", "0.2.1").publish(); // Expect: package `bar` uses `serde v0.2.0` as required by workspace `Cargo.lock`. p.cargo("package --workspace") .with_stderr_data(str![[r#" [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] bar v0.0.1 ([ROOT]/foo/bar) [UPDATING] `dummy-registry` index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] bar v0.0.1 ([ROOT]/foo/bar) [DOWNLOADING] crates ... [DOWNLOADED] serde v0.2.0 (registry `dummy-registry`) [COMPILING] serde v0.2.0 [COMPILING] bar v0.0.1 ([ROOT]/foo/target/package/bar-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [VERIFYING] foo v0.0.1 ([ROOT]/foo) [COMPILING] serde v0.2.0 [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let package_path = p.root().join("target/package/foo-0.0.1.crate"); assert!(package_path.is_file()); let f = File::open(&package_path).unwrap(); validate_crate_contents( f, "foo-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], (), ); let package_path = p.root().join("target/package/bar-0.0.1.crate"); assert!(package_path.is_file()); let f = File::open(&package_path).unwrap(); validate_crate_contents( f, "bar-0.0.1.crate", &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"], (), ); } cargo-0.86.0/tests/testsuite/read_manifest.rs000064400000000000000000000122021046102023000173510ustar 00000000000000//! Tests for the `cargo read-manifest` command. use cargo_test_support::prelude::*; use cargo_test_support::{basic_bin_manifest, main_file, project, str}; pub fn basic_bin_manifest_with_readme(name: &str, readme_filename: &str) -> String { format!( r#" [package] name = "{}" version = "0.5.0" authors = ["wycats@example.com"] readme = {} [[bin]] name = "{}" "#, name, readme_filename, name ) } #[cargo_test] fn cargo_read_manifest_path_to_cargo_toml_relative() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("read-manifest --manifest-path foo/Cargo.toml") .cwd(p.root().parent().unwrap()) .with_stdout_data( str![[r#" { "readme": null, "...": "{...}" } "#]] .is_json(), ) .run(); } #[cargo_test] fn cargo_read_manifest_path_to_cargo_toml_absolute() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("read-manifest --manifest-path") .arg(p.root().join("Cargo.toml")) .cwd(p.root().parent().unwrap()) .with_stdout_data( str![[r#" { "readme": null, "...": "{...}" } "#]] .is_json(), ) .run(); } #[cargo_test] fn cargo_read_manifest_path_to_cargo_toml_parent_relative() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("read-manifest --manifest-path foo") .cwd(p.root().parent().unwrap()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the manifest-path must be a path to a Cargo.toml file "#]]) .run(); } #[cargo_test] fn cargo_read_manifest_path_to_cargo_toml_parent_absolute() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("read-manifest --manifest-path") .arg(p.root()) .cwd(p.root().parent().unwrap()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the manifest-path must be a path to a Cargo.toml file "#]]) .run(); } #[cargo_test] fn cargo_read_manifest_cwd() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("read-manifest") .with_stdout_data( str![[r#" { "readme": null, "...": "{...}" } "#]] .is_json(), ) .run(); } #[cargo_test] fn cargo_read_manifest_with_specified_readme() { let p = project() .file( "Cargo.toml", &basic_bin_manifest_with_readme("foo", r#""SomeReadme.txt""#), ) .file("SomeReadme.txt", "Sample Project") .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("read-manifest") .with_stdout_data( str![[r#" { "readme": "SomeReadme.txt", "...": "{...}" } "#]] .is_json(), ) .run(); } #[cargo_test] fn cargo_read_manifest_default_readme() { let assert_output = |readme, expected| { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file(readme, "Sample project") .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("read-manifest").with_stdout_data(expected).run(); }; assert_output( "README.md", str![[r#" { "readme": "README.md", "...": "{...}" } "#]] .is_json(), ); assert_output( "README.txt", str![[r#" { "readme": "README.txt", "...": "{...}" } "#]] .is_json(), ); assert_output( "README", str![[r#" { "readme": "README", "...": "{...}" } "#]] .is_json(), ); } #[cargo_test] fn cargo_read_manifest_suppress_default_readme() { let p = project() .file( "Cargo.toml", &basic_bin_manifest_with_readme("foo", "false"), ) .file("README.txt", "Sample project") .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("read-manifest") .with_stdout_data( str![[r#" { "readme": null, "...": "{...}" } "#]] .is_json(), ) .run(); } // If a file named README.md exists, and `readme = true`, the value `README.md` should be defaulted in. #[cargo_test] fn cargo_read_manifest_defaults_readme_if_true() { let p = project() .file("Cargo.toml", &basic_bin_manifest_with_readme("foo", "true")) .file("README.md", "Sample project") .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("read-manifest") .with_stdout_data( str![[r#" { "readme": "README.md", "...": "{...}" } "#]] .is_json(), ) .run(); } cargo-0.86.0/tests/testsuite/registry.rs000064400000000000000000003554371046102023000164440ustar 00000000000000//! Tests for normal registry dependencies. use std::fmt::Write; use std::fs::{self, File}; use std::path::Path; use std::sync::Arc; use std::sync::Mutex; use cargo::core::SourceId; use cargo_test_support::cargo_process; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::{ self, registry_path, Dependency, Package, RegistryBuilder, Response, TestRegistry, }; use cargo_test_support::{basic_manifest, project, str}; use cargo_test_support::{git, t}; use cargo_util::paths::remove_dir_all; fn setup_http() -> TestRegistry { RegistryBuilder::new().http_index().build() } #[cargo_test] fn test_server_stops() { let server = setup_http(); server.join(); // ensure the server fully shuts down } #[cargo_test] fn simple_http() { let _server = setup_http(); simple( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } #[cargo_test] fn simple_git() { simple( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } fn simple(pre_clean_expected: impl IntoData, post_clean_expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = ">= 0.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").publish(); p.cargo("check").with_stderr_data(pre_clean_expected).run(); p.cargo("clean").run(); assert!(paths::home().join(".cargo/registry/CACHEDIR.TAG").is_file()); // Don't download a second time p.cargo("check").with_stderr_data(post_clean_expected).run(); } #[cargo_test] fn deps_http() { let _server = setup_http(); deps(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] ba[..] v0.0.1 (registry `dummy-registry`) [DOWNLOADED] ba[..] v0.0.1 (registry `dummy-registry`) [CHECKING] baz v0.0.1 [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } #[cargo_test] fn deps_git() { deps(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] ba[..] v0.0.1 (registry `dummy-registry`) [DOWNLOADED] ba[..] v0.0.1 (registry `dummy-registry`) [CHECKING] baz v0.0.1 [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } fn deps(expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = ">= 0.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("baz", "0.0.1").publish(); Package::new("bar", "0.0.1").dep("baz", "*").publish(); p.cargo("check").with_stderr_data(expected).run(); assert!(paths::home().join(".cargo/registry/CACHEDIR.TAG").is_file()); } #[cargo_test] fn nonexistent_http() { let _server = setup_http(); nonexistent(str![[r#" [UPDATING] `dummy-registry` index [ERROR] no matching package named `nonexistent` found location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]]); } #[cargo_test] fn nonexistent_git() { nonexistent(str![[r#" [UPDATING] `dummy-registry` index [ERROR] no matching package named `nonexistent` found location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]]); } fn nonexistent(expected: impl IntoData) { Package::new("init", "0.0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] nonexistent = ">= 0.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(expected) .run(); } #[cargo_test] fn wrong_case_http() { let _server = setup_http(); wrong_case(str![[r#" [UPDATING] `dummy-registry` index [ERROR] no matching package found searched package name: `Init` perhaps you meant: init location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]]); } #[cargo_test] fn wrong_case_git() { wrong_case(str![[r#" [UPDATING] `dummy-registry` index [ERROR] no matching package found searched package name: `Init` perhaps you meant: init location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]]); } fn wrong_case(expected: impl IntoData) { Package::new("init", "0.0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] Init = ">= 0.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); // #5678 to make this work p.cargo("check") .with_status(101) .with_stderr_data(expected) .run(); } #[cargo_test] fn mis_hyphenated_http() { let _server = setup_http(); mis_hyphenated(str![[r#" [UPDATING] `dummy-registry` index [ERROR] no matching package found searched package name: `mis_hyphenated` perhaps you meant: mis-hyphenated location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]]); } #[cargo_test] fn mis_hyphenated_git() { mis_hyphenated(str![[r#" [UPDATING] `dummy-registry` index [ERROR] no matching package found searched package name: `mis_hyphenated` perhaps you meant: mis-hyphenated location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]]); } fn mis_hyphenated(expected: impl IntoData) { Package::new("mis-hyphenated", "0.0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] mis_hyphenated = ">= 0.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); // #2775 to make this work p.cargo("check") .with_status(101) .with_stderr_data(expected) .run(); } #[cargo_test] fn wrong_version_http() { let _server = setup_http(); wrong_version( str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `foo = ">=1.0.0"` candidate versions found which didn't match: 0.0.2, 0.0.1 location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` perhaps a crate was updated and forgotten to be re-vendored? "#]], str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `foo = ">=1.0.0"` candidate versions found which didn't match: 0.0.4, 0.0.3, 0.0.2, ... location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` perhaps a crate was updated and forgotten to be re-vendored? "#]], ); } #[cargo_test] fn wrong_version_git() { wrong_version( str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `foo = ">=1.0.0"` candidate versions found which didn't match: 0.0.2, 0.0.1 location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` perhaps a crate was updated and forgotten to be re-vendored? "#]], str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `foo = ">=1.0.0"` candidate versions found which didn't match: 0.0.4, 0.0.3, 0.0.2, ... location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` perhaps a crate was updated and forgotten to be re-vendored? "#]], ); } fn wrong_version(pre_publish_expected: impl IntoData, post_publish_expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] foo = ">= 1.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("foo", "0.0.1").publish(); Package::new("foo", "0.0.2").publish(); p.cargo("check") .with_status(101) .with_stderr_data(pre_publish_expected) .run(); Package::new("foo", "0.0.3").publish(); Package::new("foo", "0.0.4").publish(); p.cargo("check") .with_status(101) .with_stderr_data(post_publish_expected) .run(); } #[cargo_test] fn bad_cksum_http() { let _server = setup_http(); bad_cksum(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bad-cksum v0.0.1 (registry `dummy-registry`) [ERROR] failed to download replaced source registry `crates-io` Caused by: failed to verify the checksum of `bad-cksum v0.0.1 (registry `dummy-registry`)` "#]]); } #[cargo_test] fn bad_cksum_git() { bad_cksum(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bad-cksum v0.0.1 (registry `dummy-registry`) [ERROR] failed to download replaced source registry `crates-io` Caused by: failed to verify the checksum of `bad-cksum v0.0.1 (registry `dummy-registry`)` "#]]); } fn bad_cksum(expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bad-cksum = ">= 0.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); let pkg = Package::new("bad-cksum", "0.0.1"); pkg.publish(); t!(File::create(&pkg.archive_dst())); p.cargo("check -v") .with_status(101) .with_stderr_data(expected) .run(); } #[cargo_test] fn update_registry_http() { let _server = setup_http(); update_registry( str![[r#" [UPDATING] `dummy-registry` index [ERROR] no matching package named `notyet` found location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]], str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] notyet v0.0.1 (registry `dummy-registry`) [CHECKING] notyet v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } #[cargo_test] fn update_registry_git() { update_registry( str![[r#" [UPDATING] `dummy-registry` index [ERROR] no matching package named `notyet` found location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]], str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] notyet v0.0.1 (registry `dummy-registry`) [CHECKING] notyet v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } fn update_registry(pre_publish_expected: impl IntoData, post_publish_expected: impl IntoData) { Package::new("init", "0.0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] notyet = ">= 0.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(pre_publish_expected) .run(); Package::new("notyet", "0.0.1").publish(); p.cargo("check") .with_stderr_data(post_publish_expected) .run(); } #[cargo_test] fn package_with_path_deps_http() { let _server = setup_http(); package_with_path_deps( str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [UPDATING] `dummy-registry` index [ERROR] failed to prepare local package for uploading Caused by: no matching package named `notyet` found location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]], str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [UPDATING] `dummy-registry` index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [DOWNLOADING] crates ... [DOWNLOADED] notyet v0.0.1 (registry `dummy-registry`) [COMPILING] notyet v0.0.1 [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } #[cargo_test] fn package_with_path_deps_git() { package_with_path_deps( str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [UPDATING] `dummy-registry` index [ERROR] failed to prepare local package for uploading Caused by: no matching package named `notyet` found location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]], str![[r#" [PACKAGING] foo v0.0.1 ([ROOT]/foo) [UPDATING] `dummy-registry` index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [DOWNLOADING] crates ... [DOWNLOADED] notyet v0.0.1 (registry `dummy-registry`) [COMPILING] notyet v0.0.1 [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } fn package_with_path_deps( pre_publish_expected: impl IntoData, post_publish_expected: impl IntoData, ) { Package::new("init", "0.0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" repository = "bar" [dependencies.notyet] version = "0.0.1" path = "notyet" "#, ) .file("src/main.rs", "fn main() {}") .file("notyet/Cargo.toml", &basic_manifest("notyet", "0.0.1")) .file("notyet/src/lib.rs", "") .build(); p.cargo("package") .with_status(101) .with_stderr_data(pre_publish_expected) .run(); Package::new("notyet", "0.0.1").publish(); p.cargo("package") .with_stderr_data(post_publish_expected) .run(); } #[cargo_test] fn lockfile_locks_http() { let _server = setup_http(); lockfile_locks( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } #[cargo_test] fn lockfile_locks_git() { lockfile_locks( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } fn lockfile_locks(pre_publish_expected: impl IntoData, post_publish_expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").publish(); p.cargo("check") .with_stderr_data(pre_publish_expected) .run(); p.root().move_into_the_past(); Package::new("bar", "0.0.2").publish(); p.cargo("check") .with_stderr_data(post_publish_expected) .run(); } #[cargo_test] fn lockfile_locks_transitively_http() { let _server = setup_http(); lockfile_locks_transitively( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] ba[..] v0.0.1 (registry `dummy-registry`) [DOWNLOADED] ba[..] v0.0.1 (registry `dummy-registry`) [CHECKING] baz v0.0.1 [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } #[cargo_test] fn lockfile_locks_transitively_git() { lockfile_locks_transitively( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] ba[..] v0.0.1 (registry `dummy-registry`) [DOWNLOADED] ba[..] v0.0.1 (registry `dummy-registry`) [CHECKING] baz v0.0.1 [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } fn lockfile_locks_transitively( pre_publish_expected: impl IntoData, post_publish_expected: impl IntoData, ) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("baz", "0.0.1").publish(); Package::new("bar", "0.0.1").dep("baz", "*").publish(); p.cargo("check") .with_stderr_data(pre_publish_expected) .run(); p.root().move_into_the_past(); Package::new("baz", "0.0.2").publish(); Package::new("bar", "0.0.2").dep("baz", "*").publish(); p.cargo("check") .with_stderr_data(post_publish_expected) .run(); } #[cargo_test] fn yanks_are_not_used_http() { let _server = setup_http(); yanks_are_not_used(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] ba[..] v0.0.1 (registry `dummy-registry`) [DOWNLOADED] ba[..] v0.0.1 (registry `dummy-registry`) [CHECKING] baz v0.0.1 [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } #[cargo_test] fn yanks_are_not_used_git() { yanks_are_not_used(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] ba[..] v0.0.1 (registry `dummy-registry`) [DOWNLOADED] ba[..] v0.0.1 (registry `dummy-registry`) [CHECKING] baz v0.0.1 [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } fn yanks_are_not_used(expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("baz", "0.0.1").publish(); Package::new("baz", "0.0.2").yanked(true).publish(); Package::new("bar", "0.0.1").dep("baz", "*").publish(); Package::new("bar", "0.0.2") .dep("baz", "*") .yanked(true) .publish(); p.cargo("check").with_stderr_data(expected).run(); } #[cargo_test] fn relying_on_a_yank_is_bad_http() { let _server = setup_http(); relying_on_a_yank_is_bad(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `baz = "=0.0.2"` version 0.0.2 is yanked location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `bar v0.0.1` ... which satisfies dependency `bar = "*"` of package `foo v0.0.1 ([ROOT]/foo)` "#]]); } #[cargo_test] fn relying_on_a_yank_is_bad_git() { relying_on_a_yank_is_bad(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `baz = "=0.0.2"` version 0.0.2 is yanked location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `bar v0.0.1` ... which satisfies dependency `bar = "*"` of package `foo v0.0.1 ([ROOT]/foo)` "#]]); } fn relying_on_a_yank_is_bad(expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("baz", "0.0.1").publish(); Package::new("baz", "0.0.2").yanked(true).publish(); Package::new("bar", "0.0.1").dep("baz", "=0.0.2").publish(); p.cargo("check") .with_status(101) .with_stderr_data(expected) .run(); } #[cargo_test] fn yanks_in_lockfiles_are_ok_http() { let _server = setup_http(); yanks_in_lockfiles_are_ok( str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `bar = "*"` version 0.0.1 is yanked location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]], ); } #[cargo_test] fn yanks_in_lockfiles_are_ok_git() { yanks_in_lockfiles_are_ok( str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `bar = "*"` version 0.0.1 is yanked location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]], ); } fn yanks_in_lockfiles_are_ok(expected_check: impl IntoData, expected_update: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").publish(); p.cargo("check").run(); registry_path().join("3").rm_rf(); Package::new("bar", "0.0.1").yanked(true).publish(); p.cargo("check").with_stderr_data(expected_check).run(); p.cargo("update") .with_status(101) .with_stderr_data(expected_update) .run(); } #[cargo_test] fn yanks_in_lockfiles_are_ok_for_other_update_http() { let _server = setup_http(); yanks_in_lockfiles_are_ok_for_other_update( str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `bar = "*"` version 0.0.1 is yanked location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]], str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] baz v0.0.1 -> v0.0.2 "#]], ); } #[cargo_test] fn yanks_in_lockfiles_are_ok_for_other_update_git() { yanks_in_lockfiles_are_ok_for_other_update( str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `bar = "*"` version 0.0.1 is yanked location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]], str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] baz v0.0.1 -> v0.0.2 "#]], ); } fn yanks_in_lockfiles_are_ok_for_other_update( expected_check: impl IntoData, expected_update: impl IntoData, expected_other_update: impl IntoData, ) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" baz = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").publish(); Package::new("baz", "0.0.1").publish(); p.cargo("check").run(); registry_path().join("3").rm_rf(); Package::new("bar", "0.0.1").yanked(true).publish(); Package::new("baz", "0.0.1").publish(); p.cargo("check").with_stderr_data(expected_check).run(); Package::new("baz", "0.0.2").publish(); p.cargo("update") .with_status(101) .with_stderr_data(expected_update) .run(); p.cargo("update baz") .with_stderr_data(expected_other_update) .run(); } #[cargo_test] fn yanks_in_lockfiles_are_ok_with_new_dep_http() { let _server = setup_http(); yanks_in_lockfiles_are_ok_with_new_dep(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [ADDING] baz v0.0.1 [DOWNLOADING] crates ... [DOWNLOADED] baz v0.0.1 (registry `dummy-registry`) [CHECKING] baz v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } #[cargo_test] fn yanks_in_lockfiles_are_ok_with_new_dep_git() { yanks_in_lockfiles_are_ok_with_new_dep(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [ADDING] baz v0.0.1 [DOWNLOADING] crates ... [DOWNLOADED] baz v0.0.1 (registry `dummy-registry`) [CHECKING] baz v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } fn yanks_in_lockfiles_are_ok_with_new_dep(expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").publish(); p.cargo("check").run(); registry_path().join("3").rm_rf(); Package::new("bar", "0.0.1").yanked(true).publish(); Package::new("baz", "0.0.1").publish(); p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" baz = "*" "#, ); p.cargo("check").with_stderr_data(expected).run(); } #[cargo_test] fn update_with_lockfile_if_packages_missing_http() { let _server = setup_http(); update_with_lockfile_if_packages_missing(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } #[cargo_test] fn update_with_lockfile_if_packages_missing_git() { update_with_lockfile_if_packages_missing(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } fn update_with_lockfile_if_packages_missing(expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").publish(); p.cargo("check").run(); p.root().move_into_the_past(); paths::home().join(".cargo/registry").rm_rf(); p.cargo("check").with_stderr_data(expected).run(); } #[cargo_test] fn update_lockfile_http() { let _server = setup_http(); update_lockfile( str![[r#" [UPDATING] `dummy-registry` index [UPDATING] bar v0.0.1 -> v0.0.2 "#]], str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.2 (registry `dummy-registry`) [CHECKING] bar v0.0.2 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] bar v0.0.2 -> v0.0.3 "#]], str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.3 (registry `dummy-registry`) [CHECKING] bar v0.0.3 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [UPDATING] bar v0.0.3 -> v0.0.4 [ADDING] spam v0.2.5 "#]], str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] bar v0.0.4 -> v0.0.5 [REMOVING] spam v0.2.5 "#]], ); } #[cargo_test] fn update_lockfile_git() { update_lockfile( str![[r#" [UPDATING] `dummy-registry` index [UPDATING] bar v0.0.1 -> v0.0.2 "#]], str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.2 (registry `dummy-registry`) [CHECKING] bar v0.0.2 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] bar v0.0.2 -> v0.0.3 "#]], str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.3 (registry `dummy-registry`) [CHECKING] bar v0.0.3 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [UPDATING] bar v0.0.3 -> v0.0.4 [ADDING] spam v0.2.5 "#]], str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] bar v0.0.4 -> v0.0.5 [REMOVING] spam v0.2.5 "#]], ); } fn update_lockfile( expected_update: impl IntoData, expected_check: impl IntoData, expected_other_update: impl IntoData, expected_other_check: impl IntoData, expected_new_update: impl IntoData, expected_new_check: impl IntoData, ) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); println!("0.0.1"); Package::new("bar", "0.0.1").publish(); p.cargo("check").run(); Package::new("bar", "0.0.2").publish(); Package::new("bar", "0.0.3").publish(); paths::home().join(".cargo/registry").rm_rf(); println!("0.0.2 update"); p.cargo("update bar --precise 0.0.2") .with_stderr_data(expected_update) .run(); println!("0.0.2 build"); p.cargo("check").with_stderr_data(expected_check).run(); println!("0.0.3 update"); p.cargo("update bar") .with_stderr_data(expected_other_update) .run(); println!("0.0.3 build"); p.cargo("check") .with_stderr_data(expected_other_check) .run(); println!("new dependencies update"); Package::new("bar", "0.0.4").dep("spam", "0.2.5").publish(); Package::new("spam", "0.2.5").publish(); p.cargo("update bar") .with_stderr_data(expected_new_update) .run(); println!("new dependencies update"); Package::new("bar", "0.0.5").publish(); p.cargo("update bar") .with_stderr_data(expected_new_check) .run(); } #[cargo_test] fn dev_dependency_not_used_http() { let _server = setup_http(); dev_dependency_not_used(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } #[cargo_test] fn dev_dependency_not_used_git() { dev_dependency_not_used(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } fn dev_dependency_not_used(expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("baz", "0.0.1").publish(); Package::new("bar", "0.0.1").dev_dep("baz", "*").publish(); p.cargo("check").with_stderr_data(expected).run(); } #[cargo_test] fn bad_license_file_http() { let registry = setup_http(); bad_license_file( ®istry, str![[r#" ... [ERROR] license-file `foo` does not appear to exist (relative to `[ROOT]/foo`). ... "#]], ); } #[cargo_test] fn bad_license_file_git() { let registry = registry::init(); bad_license_file( ®istry, str![[r#" ... [ERROR] license-file `foo` does not appear to exist (relative to `[ROOT]/foo`). ... "#]], ); } fn bad_license_file(registry: &TestRegistry, expected: impl IntoData) { Package::new("foo", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license-file = "foo" description = "bar" repository = "baz" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("publish -v") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(expected) .run(); } #[cargo_test] fn updating_a_dep_http() { let _server = setup_http(); updating_a_dep( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [CHECKING] bar v0.0.1 [CHECKING] a v0.0.1 ([ROOT]/foo/a) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] bar v0.0.1 -> v0.1.0 [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [CHECKING] bar v0.1.0 [CHECKING] a v0.0.1 ([ROOT]/foo/a) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } #[cargo_test] fn updating_a_dep_git() { updating_a_dep( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [CHECKING] bar v0.0.1 [CHECKING] a v0.0.1 ([ROOT]/foo/a) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] bar v0.0.1 -> v0.1.0 [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) [CHECKING] bar v0.1.0 [CHECKING] a v0.0.1 ([ROOT]/foo/a) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } fn updating_a_dep(pre_update_expected: impl IntoData, post_update_expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.a] path = "a" "#, ) .file("src/main.rs", "fn main() {}") .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("a/src/lib.rs", "") .build(); Package::new("bar", "0.0.1").publish(); p.cargo("check").with_stderr_data(pre_update_expected).run(); assert!(paths::home().join(".cargo/registry/CACHEDIR.TAG").is_file()); // Now delete the CACHEDIR.TAG file: this is the situation we'll be in after // upgrading from a version of Cargo that doesn't mark this directory, to one that // does. It should be recreated. fs::remove_file(paths::home().join(".cargo/registry/CACHEDIR.TAG")) .expect("remove CACHEDIR.TAG"); p.change_file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" "#, ); Package::new("bar", "0.1.0").publish(); println!("second"); p.cargo("check") .with_stderr_data(post_update_expected) .run(); assert!( paths::home().join(".cargo/registry/CACHEDIR.TAG").is_file(), "CACHEDIR.TAG recreated in existing registry" ); } #[cargo_test] fn git_and_registry_dep_http() { let _server = setup_http(); git_and_registry_dep( str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/b` [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] a v0.0.1 (registry `dummy-registry`) [CHECKING] a v0.0.1 [CHECKING] b v0.0.1 ([ROOTURL]/b#[..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } #[cargo_test] fn git_and_registry_dep_git() { git_and_registry_dep( str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/b` [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] a v0.0.1 (registry `dummy-registry`) [CHECKING] a v0.0.1 [CHECKING] b v0.0.1 ([ROOTURL]/b#[..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } fn git_and_registry_dep(pre_move_expected: impl IntoData, post_move_expected: impl IntoData) { let b = git::repo(&paths::root().join("b")) .file( "Cargo.toml", r#" [package] name = "b" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = "0.0.1" "#, ) .file("src/lib.rs", "") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = "0.0.1" [dependencies.b] git = '{}' "#, b.url() ), ) .file("src/main.rs", "fn main() {}") .build(); Package::new("a", "0.0.1").publish(); p.root().move_into_the_past(); p.cargo("check").with_stderr_data(pre_move_expected).run(); p.root().move_into_the_past(); println!("second"); p.cargo("check").with_stderr_data(post_move_expected).run(); } #[cargo_test] fn update_publish_then_update_http() { let _server = setup_http(); update_publish_then_update(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] a v0.1.1 (registry `dummy-registry`) [COMPILING] a v0.1.1 [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } #[cargo_test] fn update_publish_then_update_git() { update_publish_then_update(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] a v0.1.1 (registry `dummy-registry`) [COMPILING] a v0.1.1 [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } fn update_publish_then_update(expected: impl IntoData) { // First generate a Cargo.lock and a clone of the registry index at the // "head" of the current registry. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = "0.1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("a", "0.1.0").publish(); p.cargo("build").run(); // Next, publish a new package and back up the copy of the registry we just // created. Package::new("a", "0.1.1").publish(); let registry = paths::home().join(".cargo/registry"); let backup = paths::root().join("registry-backup"); t!(fs::rename(®istry, &backup)); // Generate a Cargo.lock with the newer version, and then move the old copy // of the registry back into place. let p2 = project() .at("foo2") .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = "0.1.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); p2.cargo("build").run(); registry.rm_rf(); t!(fs::rename(&backup, ®istry)); t!(fs::rename( p2.root().join("Cargo.lock"), p.root().join("Cargo.lock") )); // Finally, build the first project again (with our newer Cargo.lock) which // should force an update of the old registry, download the new crate, and // then build everything again. p.cargo("build").with_stderr_data(expected).run(); } #[cargo_test] fn fetch_downloads_http() { let _server = setup_http(); fetch_downloads(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] a v0.1.0 (registry `dummy-registry`) "#]]); } #[cargo_test] fn fetch_downloads_git() { fetch_downloads(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] a v0.1.0 (registry `dummy-registry`) "#]]); } fn fetch_downloads(expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = "0.1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("a", "0.1.0").publish(); p.cargo("fetch").with_stderr_data(expected).run(); } #[cargo_test] fn update_transitive_dependency_http() { let _server = setup_http(); update_transitive_dependency( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] b v0.1.0 -> v0.1.1 "#]], str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] b v0.1.1 (registry `dummy-registry`) [CHECKING] b v0.1.1 [CHECKING] a v0.1.0 [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } #[cargo_test] fn update_transitive_dependency_git() { update_transitive_dependency( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] b v0.1.0 -> v0.1.1 "#]], str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] b v0.1.1 (registry `dummy-registry`) [CHECKING] b v0.1.1 [CHECKING] a v0.1.0 [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } fn update_transitive_dependency(expected_update: impl IntoData, expected_check: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = "0.1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("a", "0.1.0").dep("b", "*").publish(); Package::new("b", "0.1.0").publish(); p.cargo("fetch").run(); Package::new("b", "0.1.1").publish(); p.cargo("update b").with_stderr_data(expected_update).run(); p.cargo("check").with_stderr_data(expected_check).run(); } #[cargo_test] fn update_backtracking_ok_http() { let _server = setup_http(); update_backtracking_ok(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [UPDATING] hyper v0.6.5 -> v0.6.6 [UPDATING] openssl v0.1.0 -> v0.1.1 "#]]); } #[cargo_test] fn update_backtracking_ok_git() { update_backtracking_ok(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [UPDATING] hyper v0.6.5 -> v0.6.6 [UPDATING] openssl v0.1.0 -> v0.1.1 "#]]); } fn update_backtracking_ok(expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] webdriver = "0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("webdriver", "0.1.0") .dep("hyper", "0.6") .publish(); Package::new("hyper", "0.6.5") .dep("openssl", "0.1") .dep("cookie", "0.1") .publish(); Package::new("cookie", "0.1.0") .dep("openssl", "0.1") .publish(); Package::new("openssl", "0.1.0").publish(); p.cargo("generate-lockfile").run(); Package::new("openssl", "0.1.1").publish(); Package::new("hyper", "0.6.6") .dep("openssl", "0.1.1") .dep("cookie", "0.1.0") .publish(); p.cargo("update hyper").with_stderr_data(expected).run(); } #[cargo_test] fn update_multiple_packages_http() { let _server = setup_http(); update_multiple_packages( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [UPDATING] a v0.1.0 -> v0.1.1 [UPDATING] b v0.1.0 -> v0.1.1 [NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest "#]], str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] c v0.1.0 -> v0.1.1 "#]], str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] a v0.1.1 (registry `dummy-registry`) [DOWNLOADED] b v0.1.1 (registry `dummy-registry`) [DOWNLOADED] c v0.1.1 (registry `dummy-registry`) [CHECKING] a v0.1.1 [CHECKING] c v0.1.1 [CHECKING] b v0.1.1 [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } #[cargo_test] fn update_multiple_packages_git() { update_multiple_packages( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [UPDATING] a v0.1.0 -> v0.1.1 [UPDATING] b v0.1.0 -> v0.1.1 [NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest "#]], str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] c v0.1.0 -> v0.1.1 "#]], str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] c v0.1.1 (registry `dummy-registry`) [DOWNLOADED] b v0.1.1 (registry `dummy-registry`) [DOWNLOADED] a v0.1.1 (registry `dummy-registry`) [CHECKING] b v0.1.1 [CHECKING] a v0.1.1 [CHECKING] c v0.1.1 [CHECKING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]], ); } fn update_multiple_packages( expected_update: impl IntoData, expected_other_update: impl IntoData, expected_check: impl IntoData, ) { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] a = "*" b = "*" c = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("a", "0.1.0").publish(); Package::new("b", "0.1.0").publish(); Package::new("c", "0.1.0").publish(); p.cargo("fetch").run(); Package::new("a", "0.1.1").publish(); Package::new("b", "0.1.1").publish(); Package::new("c", "0.1.1").publish(); p.cargo("update a b") .with_stderr_data(expected_update) .run(); p.cargo("update b c") .with_stderr_data(expected_other_update) .run(); p.cargo("check") .with_stderr_data(IntoData::unordered(expected_check)) .run(); } #[cargo_test] fn bundled_crate_in_registry_http() { let _server = setup_http(); bundled_crate_in_registry(); } #[cargo_test] fn bundled_crate_in_registry_git() { bundled_crate_in_registry(); } fn bundled_crate_in_registry() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] bar = "0.1" baz = "0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.1.0").publish(); Package::new("baz", "0.1.0") .dep("bar", "0.1.0") .file( "Cargo.toml", r#" [package] name = "baz" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = { path = "bar", version = "0.1.0" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "") .publish(); p.cargo("run").run(); } #[cargo_test] fn update_same_prefix_oh_my_how_was_this_a_bug_http() { let _server = setup_http(); update_same_prefix_oh_my_how_was_this_a_bug(); } #[cargo_test] fn update_same_prefix_oh_my_how_was_this_a_bug_git() { update_same_prefix_oh_my_how_was_this_a_bug(); } fn update_same_prefix_oh_my_how_was_this_a_bug() { let p = project() .file( "Cargo.toml", r#" [package] name = "ugh" version = "0.5.0" edition = "2015" authors = [] [dependencies] foo = "0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("foobar", "0.2.0").publish(); Package::new("foo", "0.1.0") .dep("foobar", "0.2.0") .publish(); p.cargo("generate-lockfile").run(); p.cargo("update foobar --precise=0.2.0").run(); } #[cargo_test] fn use_semver_http() { let _server = setup_http(); use_semver(); } #[cargo_test] fn use_semver_git() { use_semver(); } fn use_semver() { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [dependencies] foo = "1.2.3-alpha.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("foo", "1.2.3-alpha.0").publish(); p.cargo("check").run(); } #[cargo_test] fn use_semver_package_incorrectly_http() { let _server = setup_http(); use_semver_package_incorrectly(str![[r#" [ERROR] failed to select a version for the requirement `a = "^0.1"` candidate versions found which didn't match: 0.1.1-alpha.0 location searched: [ROOT]/foo/a required by package `b v0.1.0 ([ROOT]/foo/b)` if you are looking for the prerelease package it needs to be specified explicitly a = { version = "0.1.1-alpha.0" } "#]]); } #[cargo_test] fn use_semver_package_incorrectly_git() { use_semver_package_incorrectly(str![[r#" [ERROR] failed to select a version for the requirement `a = "^0.1"` candidate versions found which didn't match: 0.1.1-alpha.0 location searched: [ROOT]/foo/a required by package `b v0.1.0 ([ROOT]/foo/b)` if you are looking for the prerelease package it needs to be specified explicitly a = { version = "0.1.1-alpha.0" } "#]]); } fn use_semver_package_incorrectly(expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.1-alpha.0" edition = "2015" authors = [] "#, ) .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2015" authors = [] [dependencies] a = { version = "^0.1", path = "../a" } "#, ) .file("a/src/main.rs", "fn main() {}") .file("b/src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(expected) .run(); } #[cargo_test] fn only_download_relevant_http() { let _server = setup_http(); only_download_relevant(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 3 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] baz v0.1.0 (registry `dummy-registry`) [CHECKING] baz v0.1.0 [CHECKING] bar v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } #[cargo_test] fn only_download_relevant_git() { only_download_relevant(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 3 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] baz v0.1.0 (registry `dummy-registry`) [CHECKING] baz v0.1.0 [CHECKING] bar v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } fn only_download_relevant(expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [target.foo.dependencies] foo = "*" [dev-dependencies] bar = "*" [dependencies] baz = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("foo", "0.1.0").publish(); Package::new("bar", "0.1.0").publish(); Package::new("baz", "0.1.0").publish(); p.cargo("check").with_stderr_data(expected).run(); } #[cargo_test] fn resolve_and_backtracking_http() { let _server = setup_http(); resolve_and_backtracking(); } #[cargo_test] fn resolve_and_backtracking_git() { resolve_and_backtracking(); } fn resolve_and_backtracking() { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [dependencies] foo = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("foo", "0.1.1") .feature_dep("bar", "0.1", &["a", "b"]) .publish(); Package::new("foo", "0.1.0").publish(); p.cargo("check").run(); } #[cargo_test] fn upstream_warnings_on_extra_verbose_http() { let _server = setup_http(); upstream_warnings_on_extra_verbose(str![[r#" ... [WARNING] function `unused` is never used ... "#]]); } #[cargo_test] fn upstream_warnings_on_extra_verbose_git() { upstream_warnings_on_extra_verbose(str![[r#" ... [WARNING] function `unused` is never used ... "#]]); } fn upstream_warnings_on_extra_verbose(expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [dependencies] foo = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("foo", "0.1.0") .file("src/lib.rs", "fn unused() {}") .publish(); p.cargo("check -vv").with_stderr_data(expected).run(); } #[cargo_test] fn disallow_network_http() { let _server = setup_http(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [dependencies] foo = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check --frozen") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to get `foo` as a dependency of package `bar v0.5.0 ([ROOT]/foo)` Caused by: failed to query replaced source registry `crates-io` Caused by: attempting to make an HTTP request, but --frozen was specified "#]]) .run(); } #[cargo_test] fn disallow_network_git() { let _server = RegistryBuilder::new().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [dependencies] foo = "*" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check --frozen") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to get `foo` as a dependency of package `bar v0.5.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `foo` Caused by: Unable to update registry `crates-io` Caused by: failed to update replaced source registry `crates-io` Caused by: attempting to make an HTTP request, but --frozen was specified "#]]) .run(); } #[cargo_test] fn add_dep_dont_update_registry_http() { let _server = setup_http(); add_dep_dont_update_registry(str![[r#" [CHECKING] bar v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } #[cargo_test] fn add_dep_dont_update_registry_git() { add_dep_dont_update_registry(str![[r#" [CHECKING] bar v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } fn add_dep_dont_update_registry(expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [dependencies] baz = { path = "baz" } "#, ) .file("src/main.rs", "fn main() {}") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.5.0" edition = "2015" authors = [] [dependencies] remote = "0.3" "#, ) .file("baz/src/lib.rs", "") .build(); Package::new("remote", "0.3.4").publish(); p.cargo("check").run(); p.change_file( "Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [dependencies] baz = { path = "baz" } remote = "0.3" "#, ); p.cargo("check").with_stderr_data(expected).run(); } #[cargo_test] fn bump_version_dont_update_registry_http() { let _server = setup_http(); bump_version_dont_update_registry(str![[r#" [CHECKING] bar v0.6.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } #[cargo_test] fn bump_version_dont_update_registry_git() { bump_version_dont_update_registry(str![[r#" [CHECKING] bar v0.6.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]); } fn bump_version_dont_update_registry(expected: impl IntoData) { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [dependencies] baz = { path = "baz" } "#, ) .file("src/main.rs", "fn main() {}") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.5.0" edition = "2015" authors = [] [dependencies] remote = "0.3" "#, ) .file("baz/src/lib.rs", "") .build(); Package::new("remote", "0.3.4").publish(); p.cargo("check").run(); p.change_file( "Cargo.toml", r#" [package] name = "bar" version = "0.6.0" edition = "2015" authors = [] [dependencies] baz = { path = "baz" } "#, ); p.cargo("check").with_stderr_data(expected).run(); } #[cargo_test] fn toml_lies_but_index_is_truth_http() { let _server = setup_http(); toml_lies_but_index_is_truth(); } #[cargo_test] fn toml_lies_but_index_is_truth_git() { toml_lies_but_index_is_truth(); } fn toml_lies_but_index_is_truth() { Package::new("foo", "0.2.0").publish(); Package::new("bar", "0.3.0") .dep("foo", "0.2.0") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.3.0" edition = "2015" authors = [] [dependencies] foo = "0.1.0" "#, ) .file("src/lib.rs", "extern crate foo;") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = [] [dependencies] bar = "0.3" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check -v").run(); } #[cargo_test] fn vv_prints_warnings_http() { let _server = setup_http(); vv_prints_warnings(); } #[cargo_test] fn vv_prints_warnings_git() { vv_prints_warnings(); } fn vv_prints_warnings() { Package::new("foo", "0.2.0") .file( "src/lib.rs", "#![deny(warnings)] fn foo() {} // unused function", ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "fo" version = "0.5.0" edition = "2015" authors = [] [dependencies] foo = "0.2" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check -vv").run(); } #[cargo_test] fn bad_and_or_malicious_packages_rejected_http() { let _server = setup_http(); bad_and_or_malicious_packages_rejected(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] foo v0.2.0 (registry `dummy-registry`) [ERROR] failed to download replaced source registry `crates-io` Caused by: failed to unpack package `foo v0.2.0 (registry `dummy-registry`)` Caused by: invalid tarball downloaded, contains a file at "foo-0.1.0/src/lib.rs" which isn't under "foo-0.2.0" "#]]); } #[cargo_test] fn bad_and_or_malicious_packages_rejected_git() { bad_and_or_malicious_packages_rejected(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] foo v0.2.0 (registry `dummy-registry`) [ERROR] failed to download replaced source registry `crates-io` Caused by: failed to unpack package `foo v0.2.0 (registry `dummy-registry`)` Caused by: invalid tarball downloaded, contains a file at "foo-0.1.0/src/lib.rs" which isn't under "foo-0.2.0" "#]]); } fn bad_and_or_malicious_packages_rejected(expected: impl IntoData) { Package::new("foo", "0.2.0") .extra_file("foo-0.1.0/src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "fo" version = "0.5.0" edition = "2015" authors = [] [dependencies] foo = "0.2" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check -vv") .with_status(101) .with_stderr_data(expected) .run(); } #[cargo_test] fn git_init_templatedir_missing_http() { let _server = setup_http(); git_init_templatedir_missing(); } #[cargo_test] fn git_init_templatedir_missing_git() { git_init_templatedir_missing(); } fn git_init_templatedir_missing() { Package::new("foo", "0.2.0").dep("bar", "*").publish(); Package::new("bar", "0.2.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "fo" version = "0.5.0" edition = "2015" authors = [] [dependencies] foo = "0.2" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check").run(); remove_dir_all(paths::home().join(".cargo/registry")).unwrap(); fs::write( paths::home().join(".gitconfig"), r#" [init] templatedir = nowhere "#, ) .unwrap(); p.cargo("check").run(); p.cargo("check").run(); } #[cargo_test] fn rename_deps_and_features_http() { let _server = setup_http(); rename_deps_and_features(); } #[cargo_test] fn rename_deps_and_features_git() { rename_deps_and_features(); } fn rename_deps_and_features() { Package::new("foo", "0.1.0") .file("src/lib.rs", "pub fn f1() {}") .publish(); Package::new("foo", "0.2.0") .file("src/lib.rs", "pub fn f2() {}") .publish(); Package::new("bar", "0.2.0") .add_dep( Dependency::new("foo01", "0.1.0") .package("foo") .optional(true), ) .add_dep(Dependency::new("foo02", "0.2.0").package("foo")) .feature("another", &["foo01"]) .file( "src/lib.rs", r#" extern crate foo02; #[cfg(feature = "foo01")] extern crate foo01; pub fn foo() { foo02::f2(); #[cfg(feature = "foo01")] foo01::f1(); } "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] [dependencies] bar = "0.2" "#, ) .file( "src/main.rs", " extern crate bar; fn main() { bar::foo(); } ", ) .build(); p.cargo("check").run(); p.cargo("check --features bar/foo01").run(); p.cargo("check --features bar/another").run(); } #[cargo_test] fn ignore_invalid_json_lines_http() { let _server = setup_http(); ignore_invalid_json_lines(); } #[cargo_test] fn ignore_invalid_json_lines_git() { ignore_invalid_json_lines(); } fn ignore_invalid_json_lines() { Package::new("foo", "0.1.0").publish(); Package::new("foo", "0.1.1") .invalid_index_line(true) .publish(); Package::new("foo", "0.2.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] [dependencies] foo = '0.1.0' foo02 = { version = '0.2.0', package = 'foo' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); } #[cargo_test] fn invalid_json_lines_error() { Package::new("foo", "0.1.0") .rust_version("1.0") .schema_version(2) .publish(); Package::new("foo", "0.1.1") // Bad name field, too corrupt to use .invalid_index_line(true) .publish(); Package::new("foo", "0.1.2") // Bad version field, too corrupt to use .index_line( r#"{"cksum":"7ca5fc2301ad96ade45356faf53225aea36437d99930bbfa951155c01faecf79","deps":[],"features":{},"links":null,"name":"foo","vers":"bad","yanked":false,"rust_version":"1.2345","v":1000000000}"#, ) .publish(); Package::new("foo", "0.1.3") // Bad field, report rust version .index_line( r#"{"cksum":"7ca5fc2301ad96ade45356faf53225aea36437d99930bbfa951155c01faecf79","deps":[],"features":"bad","links":null,"name":"foo","vers":"0.1.3","yanked":false,"rust_version":"1.2345","v":1000000000}"#, ) .publish(); Package::new("foo", "0.1.4") // Bad field, report schema .index_line( r#"{"cksum":"7ca5fc2301ad96ade45356faf53225aea36437d99930bbfa951155c01faecf79","deps":[],"features":"bad","links":null,"name":"foo","vers":"0.1.4","yanked":false,"v":1000000000}"#, ) .publish(); Package::new("foo", "0.1.5") // Bad field, report error .index_line( r#"{"cksum":"7ca5fc2301ad96ade45356faf53225aea36437d99930bbfa951155c01faecf79","deps":[],"features":"bad","links":null,"name":"foo","vers":"0.1.5","yanked":false}"#, ) .publish(); Package::new("foo", "0.1.6") // Bad field with bad rust version, report schema .index_line( r#"{"cksum":"7ca5fc2301ad96ade45356faf53225aea36437d99930bbfa951155c01faecf79","deps":[],"features":"bad","links":null,"name":"foo","vers":"0.1.6","yanked":false,"rust_version":"bad","v":1000000000}"#, ) .publish(); Package::new("foo", "0.1.7") // Bad field with bad rust version and schema, report error .index_line( r#"{"cksum":"7ca5fc2301ad96ade45356faf53225aea36437d99930bbfa951155c01faecf79","deps":[],"features":"bad","links":null,"name":"foo","vers":"0.1.7","yanked":false,"rust_version":"bad","v":"bad"}"#, ) .publish(); Package::new("foo", "0.2.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] [dependencies] foo = "0.1.1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `foo = "^0.1.1"` version 0.1.3 requires cargo 1.2345 version 0.1.4 requires a Cargo version that supports index version 1000000000 version 0.1.5's index entry is invalid version 0.1.6 requires a Cargo version that supports index version 1000000000 version 0.1.7's index entry is invalid location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `a v0.5.0 ([ROOT]/foo)` "#]]) .run(); p.cargo("generate-lockfile") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `foo = "^0.1.1"` version 0.1.3 requires cargo 1.2345 version 0.1.4 requires a Cargo version that supports index version 1000000000 version 0.1.5's index entry is invalid version 0.1.6 requires a Cargo version that supports index version 1000000000 version 0.1.7's index entry is invalid location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `a v0.5.0 ([ROOT]/foo)` "#]]) .run(); } #[cargo_test] fn readonly_registry_still_works_http() { let _server = setup_http(); readonly_registry_still_works(); } #[cargo_test] fn readonly_registry_still_works_git() { readonly_registry_still_works(); } fn readonly_registry_still_works() { Package::new("foo", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.5.0" edition = "2015" authors = [] [dependencies] foo = '0.1.0' "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); p.cargo("fetch --locked").run(); chmod_readonly(&paths::home(), true); p.cargo("check").run(); // make sure we un-readonly the files afterwards so "cargo clean" can remove them (#6934) chmod_readonly(&paths::home(), false); fn chmod_readonly(path: &Path, readonly: bool) { for entry in t!(path.read_dir()) { let entry = t!(entry); let path = entry.path(); if t!(entry.file_type()).is_dir() { chmod_readonly(&path, readonly); } else { set_readonly(&path, readonly); } } set_readonly(path, readonly); } fn set_readonly(path: &Path, readonly: bool) { let mut perms = t!(path.metadata()).permissions(); perms.set_readonly(readonly); t!(fs::set_permissions(path, perms)); } } #[cargo_test] fn registry_index_rejected_http() { let _server = setup_http(); registry_index_rejected( str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: the `registry.index` config value is no longer supported Use `[source]` replacement to alter the default index for crates.io. "#]], str![[r#" [ERROR] the `registry.index` config value is no longer supported Use `[source]` replacement to alter the default index for crates.io. "#]], ); } #[cargo_test] fn registry_index_rejected_git() { registry_index_rejected( str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: the `registry.index` config value is no longer supported Use `[source]` replacement to alter the default index for crates.io. "#]], str![[r#" [ERROR] the `registry.index` config value is no longer supported Use `[source]` replacement to alter the default index for crates.io. "#]], ); } fn registry_index_rejected(expected_check: impl IntoData, expected_login: impl IntoData) { Package::new("dep", "0.1.0").publish(); let p = project() .file( ".cargo/config.toml", r#" [registry] index = "https://example.com/" "#, ) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] dep = "0.1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(expected_check) .run(); p.cargo("login") .with_status(101) .with_stderr_data(expected_login) .run(); } #[cargo_test] fn package_lock_inside_package_is_overwritten() { let registry = registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = ">= 0.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1") .file("src/lib.rs", "") .file(".cargo-ok", "") .publish(); p.cargo("check").run(); let id = SourceId::for_registry(registry.index_url()).unwrap(); let hash = cargo::util::hex::short_hash(&id); let ok = paths::cargo_home() .join("registry") .join("src") .join(format!("-{}", hash)) .join("bar-0.0.1") .join(".cargo-ok"); assert_eq!(ok.metadata().unwrap().len(), 7); } #[cargo_test] fn package_lock_as_a_symlink_inside_package_is_overwritten() { let registry = registry::init(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = ">= 0.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1") .file("src/lib.rs", "pub fn f() {}") .symlink(".cargo-ok", "src/lib.rs") .publish(); p.cargo("check").run(); let id = SourceId::for_registry(registry.index_url()).unwrap(); let hash = cargo::util::hex::short_hash(&id); let pkg_root = paths::cargo_home() .join("registry") .join("src") .join(format!("-{}", hash)) .join("bar-0.0.1"); let ok = pkg_root.join(".cargo-ok"); let librs = pkg_root.join("src/lib.rs"); // Is correctly overwritten and doesn't affect the file linked to assert_eq!(ok.metadata().unwrap().len(), 7); assert_eq!(fs::read_to_string(librs).unwrap(), "pub fn f() {}"); } #[cargo_test] fn ignores_unknown_index_version_http() { let _server = setup_http(); ignores_unknown_index_version(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar v1.0.0 "#]]); } #[cargo_test] fn ignores_unknown_index_version_git() { ignores_unknown_index_version(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar v1.0.0 "#]]); } fn ignores_unknown_index_version(expected: impl IntoData) { // If the version field is not understood, it is ignored. Package::new("bar", "1.0.0").publish(); Package::new("bar", "1.0.1") .schema_version(u32::MAX) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree").with_stdout_data(expected).run(); } #[cargo_test] fn unknown_index_version_error() { Package::new("bar", "0.0.1").publish(); // If the version field is not understood, it is ignored. Package::new("bar", "1.0.1") .schema_version(u32::MAX) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `bar = "^1.0"` version 1.0.1 requires a Cargo version that supports index version 4294967295 location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.1.0 ([ROOT]/foo)` "#]]) .run(); p.cargo("generate-lockfile") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `bar = "^1.0"` version 1.0.1 requires a Cargo version that supports index version 4294967295 location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.1.0 ([ROOT]/foo)` "#]]) .run(); } #[cargo_test] fn unknown_index_version_with_msrv_error() { Package::new("bar", "0.0.1").publish(); // If the version field is not understood, it is ignored. Package::new("bar", "1.0.1") .schema_version(u32::MAX) .rust_version("1.2345") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `bar = "^1.0"` version 1.0.1 requires cargo 1.2345 location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.1.0 ([ROOT]/foo)` "#]]) .run(); } #[cargo_test] fn protocol() { cargo_process("install bar") .with_status(101) .env("CARGO_REGISTRIES_CRATES_IO_PROTOCOL", "invalid") .with_stderr_data(str![[r#" [ERROR] unsupported registry protocol `invalid` (defined in environment variable `CARGO_REGISTRIES_CRATES_IO_PROTOCOL`) "#]]) .run(); } #[cargo_test] fn http_requires_trailing_slash() { cargo_process("install bar --index sparse+https://invalid.crates.io/test") .with_status(101) .with_stderr_data(str![[r#" [ERROR] sparse registry url must end in a slash `/`: sparse+https://invalid.crates.io/test "#]]) .run(); } // Limit the test to debug builds so that `__CARGO_TEST_MAX_UNPACK_SIZE` will take affect. #[cfg(debug_assertions)] #[cargo_test] fn reach_max_unpack_size() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = ">= 0.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); // Size of bar.crate is around 180 bytes. Package::new("bar", "0.0.1").publish(); p.cargo("check") .env("__CARGO_TEST_MAX_UNPACK_SIZE", "8") // hit 8 bytes limit and boom! .env("__CARGO_TEST_MAX_UNPACK_RATIO", "0") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [ERROR] failed to download replaced source registry `crates-io` Caused by: failed to unpack package `bar v0.0.1 (registry `dummy-registry`)` Caused by: failed to iterate over archive Caused by: maximum limit reached when reading "#]]) .run(); // Restore to the default ratio and it should compile. p.cargo("check") .env("__CARGO_TEST_MAX_UNPACK_SIZE", "8") .with_stderr_data(str![[r#" [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn sparse_blocking_count() { let fail_count = Mutex::new(0); let _registry = RegistryBuilder::new() .http_index() .add_responder("/index/3/b/bar", move |req, server| { let mut fail_count = fail_count.lock().unwrap(); if *fail_count < 1 { *fail_count += 1; server.internal_server_error(req) } else { server.index(req) } }) .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = ">= 0.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").publish(); // Ensure we have the expected number of `block_until_ready` calls. // The 1st (0 transfers pending), is the deliberate extra call in `ensure_loaded` for a source. // The 2nd (1 transfers pending), is the registry `config.json`. // the 3rd (1 transfers pending), is the package metadata for `bar`. p.cargo("check") .env("CARGO_LOG", "network::HttpRegistry::block_until_ready=trace") .with_stderr_data(str![[r#" [..] TRACE network::HttpRegistry::block_until_ready: 0 transfers pending [UPDATING] `dummy-registry` index [..] TRACE network::HttpRegistry::block_until_ready: 1 transfers pending [..] TRACE network::HttpRegistry::block_until_ready: 1 transfers pending [WARNING] spurious network error (3 tries remaining): failed to get successful HTTP response from `[..]/index/3/b/bar` ([..]), got 500 body: internal server error [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn sparse_retry_single() { let fail_count = Mutex::new(0); let _registry = RegistryBuilder::new() .http_index() .add_responder("/index/3/b/bar", move |req, server| { let mut fail_count = fail_count.lock().unwrap(); if *fail_count < 2 { *fail_count += 1; server.internal_server_error(req) } else { server.index(req) } }) .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = ">= 0.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").publish(); p.cargo("check").with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [WARNING] spurious network error (3 tries remaining): failed to get successful HTTP response from `http://127.0.0.1:[..]/index/3/b/bar` (127.0.0.1), got 500 body: internal server error [WARNING] spurious network error (2 tries remaining): failed to get successful HTTP response from `http://127.0.0.1:[..]/index/3/b/bar` (127.0.0.1), got 500 body: internal server error [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn sparse_retry_multiple() { // Tests retry behavior of downloading lots of packages with various // failure rates accessing the sparse index. // The index is the number of retries, the value is the number of packages // that retry that number of times. Thus 50 packages succeed on first try, // 25 on second, etc. const RETRIES: &[u32] = &[50, 25, 12, 6]; let pkgs: Vec<_> = RETRIES .iter() .enumerate() .flat_map(|(retries, num)| { (0..*num) .into_iter() .map(move |n| (retries as u32, format!("{}-{n}-{retries}", rand_prefix()))) }) .collect(); let mut builder = RegistryBuilder::new().http_index(); let fail_counts: Arc>> = Arc::new(Mutex::new(vec![0; pkgs.len()])); let mut cargo_toml = r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] "# .to_string(); // The expected stderr output. let mut expected = "\ [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... " .to_string(); for (n, (retries, name)) in pkgs.iter().enumerate() { let count_clone = fail_counts.clone(); let retries = *retries; let ab = &name[..2]; let cd = &name[2..4]; builder = builder.add_responder(format!("/index/{ab}/{cd}/{name}"), move |req, server| { let mut fail_counts = count_clone.lock().unwrap(); if fail_counts[n] < retries { fail_counts[n] += 1; server.internal_server_error(req) } else { server.index(req) } }); write!(&mut cargo_toml, "{name} = \"1.0.0\"\n").unwrap(); for retry in 0..retries { let remain = 3 - retry; write!( &mut expected, "[WARNING] spurious network error ({remain} tries remaining): \ failed to get successful HTTP response from \ `http://127.0.0.1:[..]/{ab}/{cd}/{name}` (127.0.0.1), got 500\n\ body:\n\ internal server error\n" ) .unwrap(); } write!( &mut expected, "\ [DOWNLOADED] {name} v1.0.0 (registry `dummy-registry`) " ) .unwrap(); } write!( &mut expected, "\ [LOCKING] 93 packages to latest compatible versions " ) .unwrap(); let _server = builder.build(); for (_, name) in &pkgs { Package::new(name, "1.0.0").publish(); } let p = project() .file("Cargo.toml", &cargo_toml) .file("src/lib.rs", "") .build(); p.cargo("fetch") .with_stderr_data(IntoData::unordered(expected)) .run(); } #[cargo_test] fn dl_retry_single() { // Tests retry behavior of downloading a package. // This tests a single package which exercises the code path that causes // it to block. let fail_count = Mutex::new(0); let _server = RegistryBuilder::new() .http_index() .add_responder("/dl/bar/1.0.0/download", move |req, server| { let mut fail_count = fail_count.lock().unwrap(); if *fail_count < 2 { *fail_count += 1; server.internal_server_error(req) } else { server.dl(req) } }) .build(); Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch").with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [WARNING] spurious network error (3 tries remaining): failed to get successful HTTP response from `http://127.0.0.1:[..]/dl/bar/1.0.0/download` (127.0.0.1), got 500 body: internal server error [WARNING] spurious network error (2 tries remaining): failed to get successful HTTP response from `http://127.0.0.1:[..]/dl/bar/1.0.0/download` (127.0.0.1), got 500 body: internal server error [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) "#]]).run(); } /// Creates a random prefix to randomly spread out the package names /// to somewhat evenly distribute the different failures at different /// points. fn rand_prefix() -> String { use rand::Rng; const CHARS: &[u8] = b"abcdefghijklmnopqrstuvwxyz"; let mut rng = rand::thread_rng(); (0..5) .map(|_| CHARS[rng.gen_range(0..CHARS.len())] as char) .collect() } #[cargo_test] fn dl_retry_multiple() { // Tests retry behavior of downloading lots of packages with various // failure rates. // The index is the number of retries, the value is the number of packages // that retry that number of times. Thus 50 packages succeed on first try, // 25 on second, etc. const RETRIES: &[u32] = &[50, 25, 12, 6]; let pkgs: Vec<_> = RETRIES .iter() .enumerate() .flat_map(|(retries, num)| { (0..*num) .into_iter() .map(move |n| (retries as u32, format!("{}-{n}-{retries}", rand_prefix()))) }) .collect(); let mut builder = RegistryBuilder::new().http_index(); let fail_counts: Arc>> = Arc::new(Mutex::new(vec![0; pkgs.len()])); let mut cargo_toml = r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] "# .to_string(); // The expected stderr output. let mut expected = "\ [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... " .to_string(); for (n, (retries, name)) in pkgs.iter().enumerate() { let count_clone = fail_counts.clone(); let retries = *retries; builder = builder.add_responder(format!("/dl/{name}/1.0.0/download"), move |req, server| { let mut fail_counts = count_clone.lock().unwrap(); if fail_counts[n] < retries { fail_counts[n] += 1; server.internal_server_error(req) } else { server.dl(req) } }); write!(&mut cargo_toml, "{name} = \"1.0.0\"\n").unwrap(); for retry in 0..retries { let remain = 3 - retry; write!( &mut expected, "[WARNING] spurious network error ({remain} tries remaining): \ failed to get successful HTTP response from \ `http://127.0.0.1:[..]/dl/{name}/1.0.0/download` (127.0.0.1), got 500\n\ body:\n\ internal server error\n" ) .unwrap(); } write!( &mut expected, "[DOWNLOADED] {name} v1.0.0 (registry `dummy-registry`)\n" ) .unwrap(); } write!( &mut expected, "[LOCKING] 93 packages to latest compatible versions\n" ) .unwrap(); let _server = builder.build(); for (_, name) in &pkgs { Package::new(name, "1.0.0").publish(); } let p = project() .file("Cargo.toml", &cargo_toml) .file("src/lib.rs", "") .build(); p.cargo("fetch") .with_stderr_data(IntoData::unordered(expected)) .run(); } #[cargo_test] fn deleted_entry() { // Checks the behavior when a package is removed from the index. // This is done occasionally on crates.io to handle things like // copyright takedowns. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1" "#, ) .file("src/lib.rs", "") .build(); // First, test removing a single version, but leaving an older version. Package::new("bar", "0.1.0").publish(); let bar_path = Path::new("3/b/bar"); let bar_reg_path = registry_path().join(&bar_path); let old_index = fs::read_to_string(&bar_reg_path).unwrap(); Package::new("bar", "0.1.1").publish(); p.cargo("tree") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.1 (registry `dummy-registry`) "#]]) .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar v0.1.1 "#]]) .run(); // Remove 0.1.1 fs::remove_file(paths::root().join("dl/bar/0.1.1/download")).unwrap(); let repo = git2::Repository::open(registry_path()).unwrap(); let mut index = repo.index().unwrap(); fs::write(&bar_reg_path, &old_index).unwrap(); index.add_path(&bar_path).unwrap(); index.write().unwrap(); git::commit(&repo); // With `Cargo.lock` unchanged, it shouldn't have an impact. p.cargo("tree") .with_stderr_data("") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar v0.1.1 "#]]) .run(); // Regenerating Cargo.lock should switch to old version. fs::remove_file(p.root().join("Cargo.lock")).unwrap(); p.cargo("tree") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0 (registry `dummy-registry`) "#]]) .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar v0.1.0 "#]]) .run(); // Remove the package entirely. fs::remove_file(paths::root().join("dl/bar/0.1.0/download")).unwrap(); let mut index = repo.index().unwrap(); index.remove(&bar_path, 0).unwrap(); index.write().unwrap(); git::commit(&repo); fs::remove_file(&bar_reg_path).unwrap(); // With `Cargo.lock` unchanged, it shouldn't have an impact. p.cargo("tree") .with_stderr_data("") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar v0.1.0 "#]]) .run(); // Regenerating Cargo.lock should fail. fs::remove_file(p.root().join("Cargo.lock")).unwrap(); p.cargo("tree") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] no matching package named `bar` found location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.1.0 ([ROOT]/foo)` "#]]) .with_status(101) .run(); } #[cargo_test] fn corrupted_ok_overwritten() { // Checks what happens if .cargo-ok gets truncated, such as if the file is // created, but the flush/close is interrupted. Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) "#]]) .run(); let ok = glob::glob( paths::home() .join(".cargo/registry/src/*/bar-1.0.0/.cargo-ok") .to_str() .unwrap(), ) .unwrap() .next() .unwrap() .unwrap(); // Simulate cargo being interrupted, or filesystem corruption. fs::write(&ok, "").unwrap(); assert_eq!(fs::read_to_string(&ok).unwrap(), ""); p.cargo("fetch").with_stderr_data("").run(); assert_eq!(fs::read_to_string(&ok).unwrap(), r#"{"v":1}"#); } #[cargo_test] fn not_found_permutations() { // Test for querying permutations for a missing dependency. let misses = Arc::new(Mutex::new(Vec::new())); let misses2 = misses.clone(); let _registry = RegistryBuilder::new() .http_index() .not_found_handler(move |req, _server| { let mut misses = misses2.lock().unwrap(); misses.push(req.url.path().to_string()); Response { code: 404, headers: vec![], body: b"not found".to_vec(), } }) .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a-b_c = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] no matching package named `a-b_c` found location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.0.1 ([ROOT]/foo)` "#]]) .run(); let mut misses = misses.lock().unwrap(); misses.sort(); assert_eq!( &*misses, &[ "/index/a-/b-/a-b-c", "/index/a-/b_/a-b_c", "/index/a_/b_/a_b_c" ] ); } #[cargo_test] fn default_auth_error() { // Check for the error message for an authentication error when default is set. let crates_io = RegistryBuilder::new().http_api().build(); let _alternative = RegistryBuilder::new().http_api().alternative().build(); paths::home().join(".cargo/credentials.toml").rm_rf(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" license = "MIT" description = "foo" "#, ) .file("src/lib.rs", "") .build(); // Test output before setting the default. p.cargo("publish --no-verify") .replace_crates_io(crates_io.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] no token found, please run `cargo login` or use environment variable CARGO_REGISTRY_TOKEN "#]]) .with_status(101) .run(); p.cargo("publish --no-verify --registry alternative") .replace_crates_io(crates_io.index_url()) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [ERROR] no token found for `alternative`, please run `cargo login --registry alternative` or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN "#]]) .with_status(101) .run(); // Test the output with the default. cargo_util::paths::append( &paths::cargo_home().join("config.toml"), br#" [registry] default = "alternative" "#, ) .unwrap(); p.cargo("publish --no-verify") .replace_crates_io(crates_io.index_url()) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [ERROR] no token found for `alternative`, please run `cargo login --registry alternative` or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN "#]]) .with_status(101) .run(); p.cargo("publish --no-verify --registry crates-io") .replace_crates_io(crates_io.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] no token found, please run `cargo login --registry crates-io` or use environment variable CARGO_REGISTRY_TOKEN "#]]) .with_status(101) .run(); } const SAMPLE_HEADERS: &[&str] = &[ "x-amz-cf-pop: SFO53-P2", "x-amz-cf-id: vEc3osJrCAXVaciNnF4Vev-hZFgnYwmNZtxMKRJ5bF6h9FTOtbTMnA==", "x-cache: Hit from cloudfront", "server: AmazonS3", "x-amz-version-id: pvsJYY_JGsWiSETZvLJKb7DeEW5wWq1W", "x-amz-server-side-encryption: AES256", "content-type: text/plain", "via: 1.1 bcbc5b46216015493e082cfbcf77ef10.cloudfront.net (CloudFront)", ]; #[cargo_test] fn debug_header_message_index() { // The error message should include some headers for debugging purposes. let _server = RegistryBuilder::new() .http_index() .add_responder("/index/3/b/bar", |_, _| Response { code: 503, headers: SAMPLE_HEADERS.iter().map(|s| s.to_string()).collect(), body: b"Please slow down".to_vec(), }) .build(); Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [WARNING] spurious network error (3 tries remaining): failed to get successful HTTP response from `http://127.0.0.1:[..]/index/3/b/bar` (127.0.0.1), got 503 body: Please slow down [WARNING] spurious network error (2 tries remaining): failed to get successful HTTP response from `http://127.0.0.1:[..]/index/3/b/bar` (127.0.0.1), got 503 body: Please slow down [WARNING] spurious network error (1 tries remaining): failed to get successful HTTP response from `http://127.0.0.1:[..]/index/3/b/bar` (127.0.0.1), got 503 body: Please slow down [ERROR] failed to get `bar` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` Caused by: failed to query replaced source registry `crates-io` Caused by: download of 3/b/bar failed Caused by: failed to get successful HTTP response from `http://127.0.0.1:[..]/index/3/b/bar` (127.0.0.1), got 503 debug headers: x-amz-cf-pop: SFO53-P2 x-amz-cf-id: vEc3osJrCAXVaciNnF4Vev-hZFgnYwmNZtxMKRJ5bF6h9FTOtbTMnA== x-cache: Hit from cloudfront body: Please slow down "#]]) .run(); } #[cargo_test] fn debug_header_message_dl() { // Same as debug_header_message_index, but for the dl endpoint which goes // through a completely different code path. let _server = RegistryBuilder::new() .http_index() .add_responder("/dl/bar/1.0.0/download", |_, _| Response { code: 503, headers: SAMPLE_HEADERS.iter().map(|s| s.to_string()).collect(), body: b"Please slow down".to_vec(), }) .build(); Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [WARNING] spurious network error (3 tries remaining): failed to get successful HTTP response from `http://127.0.0.1:[..]/dl/bar/1.0.0/download` (127.0.0.1), got 503 body: Please slow down [WARNING] spurious network error (2 tries remaining): failed to get successful HTTP response from `http://127.0.0.1:[..]/dl/bar/1.0.0/download` (127.0.0.1), got 503 body: Please slow down [WARNING] spurious network error (1 tries remaining): failed to get successful HTTP response from `http://127.0.0.1:[..]/dl/bar/1.0.0/download` (127.0.0.1), got 503 body: Please slow down [ERROR] failed to download from `http://127.0.0.1:[..]/dl/bar/1.0.0/download` Caused by: failed to get successful HTTP response from `http://127.0.0.1:[..]/dl/bar/1.0.0/download` (127.0.0.1), got 503 debug headers: x-amz-cf-pop: SFO53-P2 x-amz-cf-id: vEc3osJrCAXVaciNnF4Vev-hZFgnYwmNZtxMKRJ5bF6h9FTOtbTMnA== x-cache: Hit from cloudfront body: Please slow down "#]]) .run(); } #[cfg(unix)] #[cargo_test] fn set_mask_during_unpacking() { use std::os::unix::fs::MetadataExt; Package::new("bar", "1.0.0") .file_with_mode("example.sh", 0o777, "#!/bin/sh") .file_with_mode("src/lib.rs", 0o666, "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) "#]]) .run(); let src_file_path = |path: &str| { glob::glob( paths::home() .join(".cargo/registry/src/*/bar-1.0.0/") .join(path) .to_str() .unwrap(), ) .unwrap() .next() .unwrap() .unwrap() }; let umask = cargo::util::get_umask(); let metadata = fs::metadata(src_file_path("src/lib.rs")).unwrap(); assert_eq!(metadata.mode() & 0o777, 0o666 & !umask); let metadata = fs::metadata(src_file_path("example.sh")).unwrap(); assert_eq!(metadata.mode() & 0o777, 0o777 & !umask); } #[cargo_test] fn unpack_again_when_cargo_ok_is_unrecognized() { Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) "#]]) .run(); let src_file_path = |path: &str| { glob::glob( paths::home() .join(".cargo/registry/src/*/bar-1.0.0/") .join(path) .to_str() .unwrap(), ) .unwrap() .next() .unwrap() .unwrap() }; // Change permissions to simulate the old behavior not respecting umask. let lib_rs = src_file_path("src/lib.rs"); let cargo_ok = src_file_path(".cargo-ok"); let mut perms = fs::metadata(&lib_rs).unwrap().permissions(); assert!(!perms.readonly()); perms.set_readonly(true); fs::set_permissions(&lib_rs, perms).unwrap(); let ok = fs::read_to_string(&cargo_ok).unwrap(); assert_eq!(&ok, r#"{"v":1}"#); p.cargo("fetch").with_stderr_data("").run(); // Without changing `.cargo-ok`, a unpack won't be triggered. let perms = fs::metadata(&lib_rs).unwrap().permissions(); assert!(perms.readonly()); // Write "ok" to simulate the old behavior and trigger the unpack again. fs::write(&cargo_ok, "ok").unwrap(); p.cargo("fetch").with_stderr_data("").run(); // Permission has been restored and `.cargo-ok` is in the new format. let perms = fs::metadata(lib_rs).unwrap().permissions(); assert!(!perms.readonly()); let ok = fs::read_to_string(&cargo_ok).unwrap(); assert_eq!(&ok, r#"{"v":1}"#); } #[cargo_test] fn differ_only_by_metadata() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] baz = "=0.0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("baz", "0.0.1+b").publish(); Package::new("baz", "0.0.1+c").yanked(true).publish(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] baz v0.0.1+b (registry `dummy-registry`) [CHECKING] baz v0.0.1+b [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); Package::new("baz", "0.0.1+d").publish(); p.cargo("clean").run(); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] baz v0.0.1+b [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn differ_only_by_metadata_with_lockfile() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] baz = "=0.0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("baz", "0.0.1+a").publish(); Package::new("baz", "0.0.1+b").publish(); Package::new("baz", "0.0.1+c").publish(); p.cargo("update --package baz --precise 0.0.1+b") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] baz v0.0.1+c -> v0.0.1+b "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] baz v0.0.1+b (registry `dummy-registry`) [CHECKING] baz v0.0.1+b [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn builtin_source_replacement() { // errors for builtin source replacement of crates.io // should not include mention of source replacement in the error message. let server = RegistryBuilder::new().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bad-cksum = ">= 0.0.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); let pkg = Package::new("bad-cksum", "0.0.1"); pkg.publish(); t!(File::create(&pkg.archive_dst())); p.cargo("check -v") .replace_crates_io(&server.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bad-cksum v0.0.1 [ERROR] failed to verify the checksum of `bad-cksum v0.0.1` "#]]) .run(); } #[cargo_test] fn builtin_source_replacement_no_vendor_error() { // errors for builtin source replacement of crates.io // should not mention outdated vendor dependencies let server = RegistryBuilder::new().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2021" [dependencies] dep = "0.2.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); let pkg = Package::new("dep", "0.1.0"); pkg.publish(); p.cargo("check -v") .replace_crates_io(&server.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] failed to select a version for the requirement `dep = "^0.2.0"` candidate versions found which didn't match: 0.1.0 location searched: crates.io index required by package `foo v0.0.1 ([ROOT]/foo)` "#]]) .run(); } cargo-0.86.0/tests/testsuite/registry_auth.rs000064400000000000000000000374011046102023000174510ustar 00000000000000//! Tests for registry authentication. use cargo_test_support::compare::assert_e2e; use cargo_test_support::prelude::*; use cargo_test_support::registry::{Package, RegistryBuilder, Token}; use cargo_test_support::str; use cargo_test_support::{project, Execs, Project}; fn cargo(p: &Project, s: &str) -> Execs { let mut e = p.cargo(s); e.masquerade_as_nightly_cargo(&["asymmetric-token"]) .arg("-Zasymmetric-token"); e.env( "CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS", "cargo:paseto cargo:token", ); e } fn make_project() -> Project { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] version = "0.0.1" registry = "alternative" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("bar", "0.0.1").alternative(true).publish(); p } #[cargo_test] fn requires_credential_provider() { let _registry = RegistryBuilder::new() .alternative() .auth_required() .http_api() .build(); let p = make_project(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOCKING] 1 package to latest compatible version [ERROR] failed to download `bar v0.0.1 (registry `alternative`)` Caused by: unable to get packages from source Caused by: authenticated registries require a credential-provider to be configured see https://doc.rust-lang.org/cargo/reference/registry-authentication.html for details "#]]) .run(); } #[cargo_test] fn simple() { let _registry = RegistryBuilder::new() .alternative() .auth_required() .http_index() .build(); let p = make_project(); cargo(&p, "build") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `alternative`) [COMPILING] bar v0.0.1 (registry `alternative`) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn simple_with_asymmetric() { let _registry = RegistryBuilder::new() .alternative() .auth_required() .http_index() .token(cargo_test_support::registry::Token::rfc_key()) .build(); let p = make_project(); cargo(&p, "build") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `alternative`) [COMPILING] bar v0.0.1 (registry `alternative`) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn environment_config() { let registry = RegistryBuilder::new() .alternative() .auth_required() .no_configure_registry() .no_configure_token() .http_index() .build(); let p = make_project(); cargo(&p, "build") .env( "CARGO_REGISTRIES_ALTERNATIVE_INDEX", registry.index_url().as_str(), ) .env("CARGO_REGISTRIES_ALTERNATIVE_TOKEN", registry.token()) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `alternative`) [COMPILING] bar v0.0.1 (registry `alternative`) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn environment_token() { let registry = RegistryBuilder::new() .alternative() .auth_required() .no_configure_token() .http_index() .build(); let p = make_project(); cargo(&p, "build") .env("CARGO_REGISTRIES_ALTERNATIVE_TOKEN", registry.token()) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `alternative`) [COMPILING] bar v0.0.1 (registry `alternative`) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn environment_token_with_asymmetric() { let registry = RegistryBuilder::new() .alternative() .auth_required() .no_configure_token() .http_index() .token(cargo_test_support::registry::Token::Keys( "k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36" .to_string(), None, )) .build(); let p = make_project(); cargo(&p, "build") .env("CARGO_REGISTRIES_ALTERNATIVE_SECRET_KEY", registry.key()) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `alternative`) [COMPILING] bar v0.0.1 (registry `alternative`) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn bad_environment_token_with_asymmetric_subject() { let registry = RegistryBuilder::new() .alternative() .auth_required() .no_configure_token() .http_index() .token(cargo_test_support::registry::Token::Keys( "k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36" .to_string(), None, )) .build(); let p = make_project(); cargo(&p, "build") .env("CARGO_REGISTRIES_ALTERNATIVE_SECRET_KEY", registry.key()) .env( "CARGO_REGISTRIES_ALTERNATIVE_SECRET_KEY_SUBJECT", "incorrect", ) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [ERROR] failed to get `bar` as a dependency of package `foo v0.0.1 ([ROOT]/foo)` Caused by: token rejected for `alternative`, please run `cargo login --registry alternative` or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN Caused by: failed to get successful HTTP response from `http://127.0.0.1:[..]/index/config.json`, got 401 body: Unauthorized message from server. "#]]) .with_status(101) .run(); } #[cargo_test] fn bad_environment_token_with_asymmetric_incorrect_subject() { let registry = RegistryBuilder::new() .alternative() .auth_required() .no_configure_token() .http_index() .token(cargo_test_support::registry::Token::rfc_key()) .build(); let p = make_project(); cargo(&p, "build") .env("CARGO_REGISTRIES_ALTERNATIVE_SECRET_KEY", registry.key()) .env( "CARGO_REGISTRIES_ALTERNATIVE_SECRET_KEY_SUBJECT", "incorrect", ) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [ERROR] failed to get `bar` as a dependency of package `foo v0.0.1 ([ROOT]/foo)` Caused by: token rejected for `alternative`, please run `cargo login --registry alternative` or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN Caused by: failed to get successful HTTP response from `http://127.0.0.1:[..]/index/config.json`, got 401 body: Unauthorized message from server. "#]]) .with_status(101) .run(); } #[cargo_test] fn bad_environment_token_with_incorrect_asymmetric() { let _registry = RegistryBuilder::new() .alternative() .auth_required() .no_configure_token() .http_index() .token(cargo_test_support::registry::Token::Keys( "k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36" .to_string(), None, )) .build(); let p = make_project(); cargo(&p, "build") .env( "CARGO_REGISTRIES_ALTERNATIVE_SECRET_KEY", "k3.secret.9Vxr5hVlI_g_orBZN54vPz20bmB4O76wB_MVqUSuJJJqHFLwP8kdn_RY5g6J6pQG", ) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [ERROR] failed to get `bar` as a dependency of package `foo v0.0.1 ([ROOT]/foo)` Caused by: token rejected for `alternative`, please run `cargo login --registry alternative` or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN Caused by: failed to get successful HTTP response from `http://127.0.0.1:[..]/index/config.json`, got 401 body: Unauthorized message from server. "#]]) .with_status(101) .run(); } #[cargo_test] fn missing_token() { let _registry = RegistryBuilder::new() .alternative() .auth_required() .no_configure_token() .http_index() .build(); let p = make_project(); cargo(&p, "build") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [ERROR] failed to get `bar` as a dependency of package `foo v0.0.1 ([ROOT]/foo)` Caused by: no token found for `alternative`, please run `cargo login --registry alternative` or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN "#]]) .run(); } #[cargo_test] fn missing_token_git() { let _registry = RegistryBuilder::new() .alternative() .auth_required() .no_configure_token() .build(); let p = make_project(); cargo(&p, "build") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOCKING] 1 package to latest compatible version [ERROR] failed to download `bar v0.0.1 (registry `alternative`)` Caused by: unable to get packages from source Caused by: no token found for `alternative`, please run `cargo login --registry alternative` or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN "#]]) .run(); } #[cargo_test] fn incorrect_token() { let _registry = RegistryBuilder::new() .alternative() .auth_required() .no_configure_token() .http_index() .build(); let p = make_project(); cargo(&p, "build") .env("CARGO_REGISTRIES_ALTERNATIVE_TOKEN", "incorrect") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [ERROR] failed to get `bar` as a dependency of package `foo v0.0.1 ([ROOT]/foo)` Caused by: token rejected for `alternative`, please run `cargo login --registry alternative` or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN Caused by: failed to get successful HTTP response from `http://127.0.0.1:[..]/index/config.json`, got 401 body: Unauthorized message from server. "#]]) .run(); } #[cargo_test] fn incorrect_token_git() { let _registry = RegistryBuilder::new() .alternative() .auth_required() .no_configure_token() .http_api() .build(); let p = make_project(); cargo(&p, "build") .env("CARGO_REGISTRIES_ALTERNATIVE_TOKEN", "incorrect") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [ERROR] failed to download from `http://127.0.0.1:[..]/dl/bar/0.0.1/download` Caused by: failed to get successful HTTP response from `http://127.0.0.1:[..]/dl/bar/0.0.1/download` (127.0.0.1), got 401 body: Unauthorized message from server. "#]]) .run(); } #[cargo_test] fn anonymous_alt_registry() { // An alternative registry that requires auth, but is not in the config. let registry = RegistryBuilder::new() .alternative() .auth_required() .no_configure_token() .no_configure_registry() .http_index() .build(); let p = make_project(); cargo(&p, &format!("install --index {} bar", registry.index_url())) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `sparse+http://127.0.0.1:[..]/index/` index [ERROR] no token found for `sparse+http://127.0.0.1:[..]/index/` consider setting up an alternate registry in Cargo's configuration as described by https://doc.rust-lang.org/cargo/reference/registries.html [registries] my-registry = { index = "sparse+http://127.0.0.1:[..]/index/" } "#]]) .run(); } #[cargo_test] fn login() { let _registry = RegistryBuilder::new() .alternative() .no_configure_token() .auth_required() .http_index() .build(); let p = make_project(); cargo(&p, "login --registry alternative") .with_stdin("sekrit") .run(); } #[cargo_test] fn login_existing_token() { let _registry = RegistryBuilder::new() .alternative() .auth_required() .http_index() .build(); let p = make_project(); cargo(&p, "login --registry alternative") .with_stdin("sekrit") .run(); } #[cargo_test] fn duplicate_index() { let server = RegistryBuilder::new() .alternative() .no_configure_token() .auth_required() .build(); let p = make_project(); // Two alternative registries with the same index. cargo(&p, "build") .env( "CARGO_REGISTRIES_ALTERNATIVE1_INDEX", server.index_url().as_str(), ) .env( "CARGO_REGISTRIES_ALTERNATIVE2_INDEX", server.index_url().as_str(), ) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [LOCKING] 1 package to latest compatible version [ERROR] failed to download `bar v0.0.1 (registry `alternative`)` Caused by: unable to get packages from source Caused by: multiple registries are configured with the same index url 'registry+[ROOTURL]/alternative-registry': alternative1, alternative2 "#]]) .run(); } #[cargo_test] fn token_not_logged() { // Checks that the token isn't displayed in debug output (for both HTTP // index and registry API). Note that this doesn't fully verify the // correct behavior since we don't have an HTTP2 server, and curl behaves // significantly differently when using HTTP2. let crates_io = RegistryBuilder::new() .http_api() .http_index() .auth_required() .token(Token::Plaintext("a-unique_token".to_string())) .build(); Package::new("bar", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); let output = cargo(&p, "publish") .replace_crates_io(crates_io.index_url()) .env("CARGO_HTTP_DEBUG", "true") .env("CARGO_LOG", "trace") .run(); let log = String::from_utf8(output.stderr).unwrap(); assert_e2e().eq( &log, str![[r#" ... [PUBLISHED] foo v0.1.0 at registry `crates-io` "#]], ); let authorizations: Vec<_> = log .lines() .filter(|line| { line.contains("http-debug:") && line.to_lowercase().contains("authorization") }) .collect(); assert!(authorizations.iter().all(|line| line.contains("REDACTED"))); // Total authorizations: // 1. Initial config.json // 2. /index/3/f/foo // 3. config.json again for verification // 4. /index/3/b/bar // 5. config.json again for verification // 6. /index/3/b/bar // 7. /dl/bar/1.0.0/download // 8. /api/v1/crates/new // 9. config.json again for verification // 10. /index/3/f/foo for the "wait for publish" assert_eq!(authorizations.len(), 10); assert!(!log.contains("a-unique_token")); } cargo-0.86.0/tests/testsuite/registry_overlay.rs000064400000000000000000000206311046102023000201660ustar 00000000000000//! Tests for local-registry sources. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry::{Package, RegistryBuilder, TestRegistry}; use cargo_test_support::str; fn setup() -> (TestRegistry, String) { let alt = RegistryBuilder::new().alternative().build(); ( RegistryBuilder::new().http_index().build(), alt.index_url() .to_file_path() .unwrap() .into_os_string() .into_string() .unwrap(), ) } #[cargo_test] fn overlay_hit() { let (reg, alt_path) = setup(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] baz = "0.1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); // baz is only in the local registry, but it gets found Package::new("baz", "0.1.1") .alternative(true) .local(true) .publish(); p.cargo("check") .overlay_registry(®.index_url(), &alt_path) .run(); } #[cargo_test] fn registry_version_wins() { let (reg, alt_path) = setup(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] baz = "0.1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); // The latest one is in the main registry, so it will get chosen. Package::new("baz", "0.1.1").publish(); Package::new("baz", "0.1.0") .alternative(true) .local(true) .publish(); p.cargo("check") .overlay_registry(®.index_url(), &alt_path) .with_stderr_data(str![[r#" [UPDATING] `sparse+http://127.0.0.1:[..]/index/` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] baz v0.1.1 (registry `sparse+http://127.0.0.1:[..]/index/`) [CHECKING] baz v0.1.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn overlay_version_wins() { let (reg, alt_path) = setup(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] baz = "0.1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); // The latest one is in the overlay registry, so it will get chosen. Package::new("baz", "0.1.0").publish(); Package::new("baz", "0.1.1") .alternative(true) .local(true) .publish(); p.cargo("check") .overlay_registry(®.index_url(), &alt_path) .with_stderr_data(str![[r#" [UPDATING] `sparse+http://127.0.0.1:[..]/index/` index [LOCKING] 1 package to latest compatible version [UNPACKING] baz v0.1.1 (registry `[ROOT]/alternative-registry`) [CHECKING] baz v0.1.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn version_precedence() { let (reg, alt_path) = setup(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] baz = "0.1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); // The one we want is in the main registry. Package::new("baz", "0.1.1").publish(); Package::new("baz", "0.1.1") .alternative(true) .local(true) .publish(); p.cargo("check") .overlay_registry(®.index_url(), &alt_path) .with_stderr_data(str![[r#" [UPDATING] `sparse+http://127.0.0.1:[..]/index/` index [LOCKING] 1 package to latest compatible version [UNPACKING] baz v0.1.1 (registry `[ROOT]/alternative-registry`) [CHECKING] baz v0.1.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn local_depends_on_old_registry_package() { let (reg, alt_path) = setup(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] baz = "0.1.0" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("baz", "0.0.1").publish(); // A new local package can depend on an older version in the registry. Package::new("baz", "0.1.1") .dep("baz", "=0.0.1") .alternative(true) .local(true) .publish(); p.cargo("check") .overlay_registry(®.index_url(), &alt_path) .run(); } #[cargo_test] fn registry_dep_depends_on_new_local_package() { let (reg, alt_path) = setup(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] registry-package = "0.1.0" workspace-package = "0.0.1" "#, ) .file("src/main.rs", "fn main() {}") .build(); Package::new("registry-package", "0.1.0") .dep("workspace-package", "0.1.0") .publish(); // The local overlay contains an updated version of workspace-package Package::new("workspace-package", "0.1.1") .alternative(true) .local(true) .publish(); // The registry contains older versions of workspace-package (one of which // we depend on directly). Package::new("workspace-package", "0.1.0").publish(); Package::new("workspace-package", "0.0.1").publish(); p.cargo("check") .overlay_registry(®.index_url(), &alt_path) .with_stderr_data( str![[r#" [UPDATING] `sparse+http://127.0.0.1:[..]/index/` index [LOCKING] 3 packages to latest compatible versions [ADDING] workspace-package v0.0.1 (available: v0.1.1) [DOWNLOADING] crates ... [UNPACKING] workspace-package v0.1.1 (registry `[ROOT]/alternative-registry`) [DOWNLOADED] registry-package v0.1.0 (registry `sparse+http://127.0.0.1:[..]/index/`) [DOWNLOADED] workspace-package v0.0.1 (registry `sparse+http://127.0.0.1:[..]/index/`) [CHECKING] workspace-package v0.1.1 [CHECKING] workspace-package v0.0.1 [CHECKING] registry-package v0.1.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } // Test that we can overlay on top of alternate registries, not just crates-io. // Since the test framework only supports a single alternate registry, we repurpose // the dummy crates-io as the registry to overlay on top. #[cargo_test] fn alt_registry() { let alt = RegistryBuilder::new().http_index().alternative().build(); let crates_io = RegistryBuilder::new().build(); let crates_io_path = crates_io .index_url() .to_file_path() .unwrap() .into_os_string() .into_string() .unwrap(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] baz = { version = "0.1.0", registry = "alternative" } "#, ) .file("src/main.rs", "fn main() {}") .build(); // This package isn't used, but publishing it forces the creation of the registry index. Package::new("bar", "0.0.1").local(true).publish(); Package::new("baz", "0.1.1").alternative(true).publish(); p.cargo("check") .overlay_registry(&alt.index_url(), &crates_io_path) .run(); } cargo-0.86.0/tests/testsuite/rename_deps.rs000064400000000000000000000241411046102023000170370ustar 00000000000000//! Tests for renaming dependencies. use cargo_test_support::git; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::{self, Package}; use cargo_test_support::{basic_manifest, project, str}; #[cargo_test] fn rename_dependency() { Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.2.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = { version = "0.1.0" } baz = { version = "0.2.0", package = "bar" } "#, ) .file("src/lib.rs", "extern crate bar; extern crate baz;") .build(); p.cargo("build").run(); } #[cargo_test] fn rename_with_different_names() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] baz = { path = "bar", package = "bar" } "#, ) .file("src/lib.rs", "extern crate baz;") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [lib] name = "random_name" "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("build").run(); } #[cargo_test] fn lots_of_names() { registry::alt_init(); Package::new("foo", "0.1.0") .file("src/lib.rs", "pub fn foo1() {}") .publish(); Package::new("foo", "0.2.0") .file("src/lib.rs", "pub fn foo() {}") .publish(); Package::new("foo", "0.1.0") .file("src/lib.rs", "pub fn foo2() {}") .alternative(true) .publish(); let g = git::repo(&paths::root().join("another")) .file("Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("src/lib.rs", "pub fn foo3() {}") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "test" version = "0.1.0" edition = "2015" authors = [] [dependencies] foo = "0.2" foo1 = {{ version = "0.1", package = "foo" }} foo2 = {{ version = "0.1", registry = "alternative", package = "foo" }} foo3 = {{ git = '{}', package = "foo" }} foo4 = {{ path = "foo", package = "foo" }} "#, g.url() ), ) .file( "src/lib.rs", " extern crate foo; extern crate foo1; extern crate foo2; extern crate foo3; extern crate foo4; pub fn foo() { foo::foo(); foo1::foo1(); foo2::foo2(); foo3::foo3(); foo4::foo4(); } ", ) .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/lib.rs", "pub fn foo4() {}") .build(); p.cargo("build -v").run(); } #[cargo_test] fn rename_and_patch() { Package::new("foo", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = { version = "0.1", package = "foo" } [patch.crates-io] foo = { path = "foo" } "#, ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::foo(); }", ) .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/lib.rs", "pub fn foo() {}") .build(); p.cargo("build -v").run(); } #[cargo_test] fn rename_twice() { Package::new("foo", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = { version = "0.1", package = "foo" } [build-dependencies] foo = { version = "0.1" } "#, ) .file("src/lib.rs", "") .build(); p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] foo v0.1.0 (registry `dummy-registry`) [ERROR] the crate `test v0.1.0 ([ROOT]/foo)` depends on crate `foo v0.1.0` multiple times with different names "#]]) .run(); } #[cargo_test] fn rename_affects_fingerprint() { Package::new("foo", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.1.0" edition = "2015" authors = [] [dependencies] foo = { version = "0.1", package = "foo" } "#, ) .file("src/lib.rs", "extern crate foo;") .build(); p.cargo("build -v").run(); p.change_file( "Cargo.toml", r#" [package] name = "test" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = { version = "0.1", package = "foo" } "#, ); p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [FRESH] foo v0.1.0 [DIRTY] test v0.1.0 ([ROOT]/foo): name of dependency changed (foo => bar) [COMPILING] test v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..]` error[E0463]: can't find crate for `foo` ... "#]]) .run(); } #[cargo_test] fn can_run_doc_tests() { Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.2.0").publish(); let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = { version = "0.1.0" } baz = { version = "0.2.0", package = "bar" } "#, ) .file( "src/lib.rs", " extern crate bar; extern crate baz; ", ) .build(); foo.cargo("test -v").with_stderr_data(str![[r#" ... [DOCTEST] foo [RUNNING] `rustdoc [..]--test src/lib.rs [..] --extern bar=[ROOT]/foo/target/debug/deps/libbar-[HASH].rlib --extern baz=[ROOT]/foo/target/debug/deps/libbar-[HASH].rlib [..]` "#]]).run(); } #[cargo_test] fn features_still_work() { Package::new("foo", "0.1.0").publish(); Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.1.0" edition = "2015" authors = [] [dependencies] p1 = { path = 'a', features = ['b'] } p2 = { path = 'b' } "#, ) .file("src/lib.rs", "") .file( "a/Cargo.toml", r#" [package] name = "p1" version = "0.1.0" edition = "2015" authors = [] [dependencies] b = { version = "0.1", package = "foo", optional = true } "#, ) .file("a/src/lib.rs", "extern crate b;") .file( "b/Cargo.toml", r#" [package] name = "p2" version = "0.1.0" edition = "2015" authors = [] [dependencies] b = { version = "0.1", package = "bar", optional = true } [features] default = ['b'] "#, ) .file("b/src/lib.rs", "extern crate b;") .build(); p.cargo("build -v").run(); } #[cargo_test] fn features_not_working() { Package::new("foo", "0.1.0").publish(); Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.1.0" edition = "2015" authors = [] [dependencies] a = { path = 'a', package = 'p1', optional = true } [features] default = ['p1'] "#, ) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("p1", "0.1.0")) .build(); p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `default` includes `p1` which is neither a dependency nor another feature "#]]) .run(); } #[cargo_test] fn rename_with_dash() { let p = project() .file( "Cargo.toml", r#" [package] name = "qwerty" version = "0.1.0" edition = "2015" [dependencies] foo-bar = { path = 'a', package = 'a' } "#, ) .file("src/lib.rs", "extern crate foo_bar;") .file("a/Cargo.toml", &basic_manifest("a", "0.1.0")) .file("a/src/lib.rs", "") .build(); p.cargo("build").run(); } cargo-0.86.0/tests/testsuite/replace.rs000064400000000000000000001163321046102023000161740ustar 00000000000000//! Tests for `[replace]` table source replacement. use cargo_test_support::git; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{basic_manifest, project, str}; #[cargo_test] fn override_simple() { Package::new("bar", "0.1.0").publish(); let bar = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn bar() {}") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [replace] "bar:0.1.0" = {{ git = '{}' }} "#, bar.url() ), ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/override` [LOCKING] 2 packages to latest compatible versions [CHECKING] bar v0.1.0 ([ROOTURL]/override#[..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn override_with_features() { Package::new("bar", "0.1.0").publish(); let bar = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn bar() {}") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [replace] "bar:0.1.0" = {{ git = '{}', features = ["some_feature"] }} "#, bar.url() ), ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); p.cargo("check").with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/override` [LOCKING] 2 packages to latest compatible versions [WARNING] replacement for `bar` uses the features mechanism. default-features and features will not take effect because the replacement dependency does not support this mechanism [CHECKING] bar v0.1.0 ([ROOTURL]/override#[..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn override_with_setting_default_features() { Package::new("bar", "0.1.0").publish(); let bar = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn bar() {}") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [replace] "bar:0.1.0" = {{ git = '{}', default-features = false, features = ["none_default_feature"] }} "#, bar.url() ), ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); p.cargo("check").with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/override` [LOCKING] 2 packages to latest compatible versions [WARNING] replacement for `bar` uses the features mechanism. default-features and features will not take effect because the replacement dependency does not support this mechanism [CHECKING] bar v0.1.0 ([ROOTURL]/override#[..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn missing_version() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [replace] bar = { git = 'https://example.com' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").with_status(101).with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: replacements must specify a version to replace, but `https://github.com/rust-lang/crates.io-index#bar` does not "#]]).run(); } #[cargo_test] fn invalid_semver_version() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" [replace] "bar:*" = { git = 'https://example.com' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: replacements must specify a valid semver version to replace, but `bar:*` does not ... "#]]) .run(); } #[cargo_test] fn different_version() { Package::new("bar", "0.2.0").publish(); Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [replace] "bar:0.1.0" = "0.2.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").with_status(101).with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: replacements cannot specify a version requirement, but found one for `https://github.com/rust-lang/crates.io-index#bar@0.1.0` "#]]).run(); } #[cargo_test] fn transitive() { Package::new("bar", "0.1.0").publish(); Package::new("baz", "0.2.0") .dep("bar", "0.1.0") .file("src/lib.rs", "extern crate bar; fn baz() { bar::bar(); }") .publish(); let foo = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn bar() {}") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] baz = "0.2.0" [replace] "bar:0.1.0" = {{ git = '{}' }} "#, foo.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/override` [LOCKING] 3 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] baz v0.2.0 (registry `dummy-registry`) [CHECKING] bar v0.1.0 ([ROOTURL]/override#[..]) [CHECKING] baz v0.2.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn persists_across_rebuilds() { Package::new("bar", "0.1.0").publish(); let foo = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn bar() {}") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [replace] "bar:0.1.0" = {{ git = '{}' }} "#, foo.url() ), ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/override` [LOCKING] 2 packages to latest compatible versions [CHECKING] bar v0.1.0 ([ROOTURL]/override#[..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn replace_registry_with_path() { Package::new("bar", "0.1.0").publish(); let _ = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn bar() {}") .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [replace] "bar:0.1.0" = { path = "../bar" } "#, ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [CHECKING] bar v0.1.0 ([ROOT]/bar) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn use_a_spec_to_select() { Package::new("baz", "0.1.1") .file("src/lib.rs", "pub fn baz1() {}") .publish(); Package::new("baz", "0.2.0").publish(); Package::new("bar", "0.1.1") .dep("baz", "0.2") .file( "src/lib.rs", "extern crate baz; pub fn bar() { baz::baz3(); }", ) .publish(); let foo = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("baz", "0.2.0")) .file("src/lib.rs", "pub fn baz3() {}") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1" baz = "0.1" [replace] "baz:0.2.0" = {{ git = '{}' }} "#, foo.url() ), ) .file( "src/lib.rs", " extern crate bar; extern crate baz; pub fn local() { baz::baz1(); bar::bar(); } ", ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/override` [LOCKING] 4 packages to latest compatible versions [ADDING] baz v0.1.1 (available: v0.2.0) [DOWNLOADING] crates ... [DOWNLOADED] baz v0.1.1 (registry `dummy-registry`) [DOWNLOADED] bar v0.1.1 (registry `dummy-registry`) [CHECKING] baz v0.2.0 ([ROOTURL]/override#[..]) [CHECKING] baz v0.1.1 [CHECKING] bar v0.1.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn override_adds_some_deps() { Package::new("baz", "0.1.1").publish(); Package::new("bar", "0.1.0").publish(); let foo = git::repo(&paths::root().join("override")) .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] baz = "0.1" "#, ) .file("src/lib.rs", "") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1" [replace] "bar:0.1.0" = {{ git = '{}' }} "#, foo.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/override` [LOCKING] 3 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] baz v0.1.1 (registry `dummy-registry`) [CHECKING] baz v0.1.1 [CHECKING] bar v0.1.0 ([ROOTURL]/override#[..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); Package::new("baz", "0.1.2").publish(); p.cargo("update") .arg(&format!("{}#bar", foo.url())) .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/override` [UPDATING] `dummy-registry` index [LOCKING] 0 packages to latest compatible versions [NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest "#]]) .run(); p.cargo("update https://github.com/rust-lang/crates.io-index#bar") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 0 packages to latest compatible versions [NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn locked_means_locked_yes_no_seriously_i_mean_locked() { // this in theory exercises #2041 Package::new("baz", "0.1.0").publish(); Package::new("baz", "0.2.0").publish(); Package::new("bar", "0.1.0").publish(); let foo = git::repo(&paths::root().join("override")) .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] baz = "*" "#, ) .file("src/lib.rs", "") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1" baz = "0.1" [replace] "bar:0.1.0" = {{ git = '{}' }} "#, foo.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn override_wrong_name() { Package::new("baz", "0.1.0").publish(); let foo = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] baz = "0.1" [replace] "baz:0.1.0" = {{ git = '{}' }} "#, foo.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/override` [ERROR] failed to get `baz` as a dependency of package `foo v0.0.1 ([ROOT]/foo)` Caused by: no matching package for override `https://github.com/rust-lang/crates.io-index#baz@0.1.0` found location searched: [ROOTURL]/override version required: =0.1.0 "#]]) .run(); } #[cargo_test] fn override_with_nothing() { Package::new("bar", "0.1.0").publish(); let foo = git::repo(&paths::root().join("override")) .file("src/lib.rs", "") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1" [replace] "bar:0.1.0" = {{ git = '{}' }} "#, foo.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/override` [ERROR] failed to get `bar` as a dependency of package `foo v0.0.1 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update [ROOTURL]/override Caused by: Could not find Cargo.toml in `[ROOT]/home/.cargo/git/checkouts/override-[HASH]/[..]` "#]]) .run(); } #[cargo_test] fn override_wrong_version() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [replace] "bar:0.1.0" = { git = 'https://example.com', version = '0.2.0' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").with_status(101).with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: replacements cannot specify a version requirement, but found one for `https://github.com/rust-lang/crates.io-index#bar@0.1.0` "#]]).run(); } #[cargo_test] fn multiple_specs() { Package::new("bar", "0.1.0").publish(); let bar = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn bar() {}") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [replace] "bar:0.1.0" = {{ git = '{0}' }} [replace."https://github.com/rust-lang/crates.io-index#bar:0.1.0"] git = '{0}' "#, bar.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/override` [ERROR] failed to get `bar` as a dependency of package `foo v0.0.1 ([ROOT]/foo)` Caused by: overlapping replacement specifications found: * https://github.com/rust-lang/crates.io-index#bar@0.1.0 * https://github.com/rust-lang/crates.io-index#bar@0.1.0 both specifications match: bar v0.1.0 "#]]) .run(); } #[cargo_test] fn test_override_dep() { Package::new("bar", "0.1.0").publish(); let bar = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn bar() {}") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [replace] "bar:0.1.0" = {{ git = '{0}' }} "#, bar.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("test -p bar") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/override` [LOCKING] 2 packages to latest compatible versions [ERROR] There are multiple `bar` packages in your project, and the specification `bar` is ambiguous. Please re-run this command with one of the following specifications: registry+https://github.com/rust-lang/crates.io-index#bar@0.1.0 git+[ROOTURL]/override#bar@0.1.0 "#]]) .run(); } #[cargo_test] fn update() { Package::new("bar", "0.1.0").publish(); let bar = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn bar() {}") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [replace] "bar:0.1.0" = {{ git = '{0}' }} "#, bar.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); p.cargo("update") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/override` [LOCKING] 0 packages to latest compatible versions "#]]) .run(); } // foo -> near -> far // near is overridden with itself #[cargo_test] fn no_override_self() { let deps = git::repo(&paths::root().join("override")) .file("far/Cargo.toml", &basic_manifest("far", "0.1.0")) .file("far/src/lib.rs", "") .file( "near/Cargo.toml", r#" [package] name = "near" version = "0.1.0" edition = "2015" authors = [] [dependencies] far = { path = "../far" } "#, ) .file("near/src/lib.rs", "#![no_std] pub extern crate far;") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] near = {{ git = '{0}' }} [replace] "near:0.1.0" = {{ git = '{0}' }} "#, deps.url() ), ) .file("src/lib.rs", "#![no_std] pub extern crate near;") .build(); p.cargo("check --verbose").run(); } #[cargo_test] fn override_an_override() { Package::new("chrono", "0.2.0") .dep("serde", "< 0.9") .publish(); Package::new("serde", "0.7.0") .file("src/lib.rs", "pub fn serde07() {}") .publish(); Package::new("serde", "0.8.0") .file("src/lib.rs", "pub fn serde08() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] chrono = "0.2" serde = "0.8" [replace] "chrono:0.2.0" = { path = "chrono" } "serde:0.8.0" = { path = "serde" } "#, ) .file( "Cargo.lock", r#" [[package]] name = "foo" version = "0.0.1" dependencies = [ "chrono 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "chrono" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" replace = "chrono 0.2.0" [[package]] name = "chrono" version = "0.2.0" dependencies = [ "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" replace = "serde 0.8.0" [[package]] name = "serde" version = "0.8.0" "#, ) .file( "src/lib.rs", " extern crate chrono; extern crate serde; pub fn foo() { chrono::chrono(); serde::serde08_override(); } ", ) .file( "chrono/Cargo.toml", r#" [package] name = "chrono" version = "0.2.0" edition = "2015" authors = [] [dependencies] serde = "< 0.9" "#, ) .file( "chrono/src/lib.rs", " extern crate serde; pub fn chrono() { serde::serde07(); } ", ) .file("serde/Cargo.toml", &basic_manifest("serde", "0.8.0")) .file("serde/src/lib.rs", "pub fn serde08_override() {}") .build(); p.cargo("check -v").run(); } #[cargo_test] fn overriding_nonexistent_no_spurious() { Package::new("bar", "0.1.0").dep("baz", "0.1").publish(); Package::new("baz", "0.1.0").publish(); let bar = git::repo(&paths::root().join("override")) .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] baz = { path = "baz" } "#, ) .file("src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [replace] "bar:0.1.0" = {{ git = '{url}' }} "baz:0.1.0" = {{ git = '{url}' }} "#, url = bar.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] package replacement is not used: https://github.com/rust-lang/crates.io-index#baz@0.1.0 [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); } #[cargo_test] fn no_warnings_when_replace_is_used_in_another_workspace_member() { Package::new("bar", "0.1.0").publish(); Package::new("baz", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = [ "first_crate", "second_crate"] [replace] "bar:0.1.0" = { path = "local_bar" } "#, ) .file( "first_crate/Cargo.toml", r#" [package] name = "first_crate" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1.0" "#, ) .file("first_crate/src/lib.rs", "") .file( "second_crate/Cargo.toml", &basic_manifest("second_crate", "0.1.0"), ) .file("second_crate/src/lib.rs", "") .file("local_bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("local_bar/src/lib.rs", "") .build(); p.cargo("check") .cwd("first_crate") .with_stdout_data("") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [CHECKING] bar v0.1.0 ([ROOT]/foo/local_bar) [CHECKING] first_crate v0.1.0 ([ROOT]/foo/first_crate) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .cwd("second_crate") .with_stdout_data("") .with_stderr_data(str![[r#" [CHECKING] second_crate v0.1.0 ([ROOT]/foo/second_crate) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn replace_to_path_dep() { Package::new("bar", "0.1.0").dep("baz", "0.1").publish(); Package::new("baz", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [replace] "bar:0.1.0" = { path = "bar" } "#, ) .file("src/lib.rs", "extern crate bar;") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] baz = { path = "baz" } "#, ) .file( "bar/src/lib.rs", "extern crate baz; pub fn bar() { baz::baz(); }", ) .file("bar/baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("bar/baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("check").run(); } #[cargo_test] fn override_with_default_feature() { Package::new("another", "0.1.0").publish(); Package::new("another", "0.1.1").dep("bar", "0.1").publish(); Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = { path = "bar", default-features = false } another = "0.1" another2 = { path = "another2" } [replace] 'bar:0.1.0' = { path = "bar" } "#, ) .file("src/main.rs", "extern crate bar; fn main() { bar::bar(); }") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [features] default = [] "#, ) .file( "bar/src/lib.rs", r#" #[cfg(feature = "default")] pub fn bar() {} "#, ) .file( "another2/Cargo.toml", r#" [package] name = "another2" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = { version = "0.1", default-features = false } "#, ) .file("another2/src/lib.rs", "") .build(); p.cargo("run").run(); } #[cargo_test] fn override_plus_dep() { Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1" [replace] 'bar:0.1.0' = { path = "bar" } "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] foo = { path = ".." } "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] cyclic package dependency: package `bar v0.1.0 ([ROOT]/foo/bar)` depends on itself. Cycle: package `bar v0.1.0 ([ROOT]/foo/bar)` ... which satisfies dependency `bar = "^0.1"` of package `foo v0.0.1 ([ROOT]/foo)` ... which satisfies path dependency `foo` of package `bar v0.1.0 ([ROOT]/foo/bar)` "#]]) .run(); } #[cargo_test] fn override_generic_matching_other_versions() { Package::new("bar", "0.1.0+a").publish(); let bar = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn bar() {}") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [replace] "bar:0.1.0" = {{ git = '{}' }} "#, bar.url() ), ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); p.cargo("check").with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/override` [ERROR] failed to get `bar` as a dependency of package `foo v0.0.1 ([ROOT]/foo)` Caused by: replacement specification `https://github.com/rust-lang/crates.io-index#bar@0.1.0` matched 0.1.0+a and tried to override it with 0.1.0 avoid matching unrelated packages by being more specific "#]]).with_status(101).run(); } #[cargo_test] fn override_respects_spec_metadata() { Package::new("bar", "0.1.0+a").publish(); let bar = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0+a")) .file("src/lib.rs", "pub fn bar() {}") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [replace] "bar:0.1.0+notTheBuild" = {{ git = '{}' }} "#, bar.url() ), ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); p.cargo("check").with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [WARNING] package replacement is not used: https://github.com/rust-lang/crates.io-index#bar@0.1.0+notTheBuild [DOWNLOADING] crates ... [DOWNLOADED] bar v0.1.0+a (registry `dummy-registry`) [CHECKING] bar v0.1.0+a [CHECKING] foo v0.0.1 ([ROOT]/foo) error[E0425]: cannot find function `bar`[..] ... [ERROR] could not compile `foo` (lib) due to 1 previous error "#]]).with_status(101).run(); } #[cargo_test] fn override_spec_metadata_is_optional() { Package::new("bar", "0.1.0+a").publish(); let bar = git::repo(&paths::root().join("override")) .file("Cargo.toml", &basic_manifest("bar", "0.1.0+a")) .file("src/lib.rs", "pub fn bar() {}") .build(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "0.1.0" [replace] "bar:0.1.0" = {{ git = '{}' }} "#, bar.url() ), ) .file( "src/lib.rs", "extern crate bar; pub fn foo() { bar::bar(); }", ) .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] git repository `[ROOTURL]/override` [LOCKING] 2 packages to latest compatible versions [CHECKING] bar v0.1.0+a ([ROOTURL]/override#[..]) [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/required_features.rs000064400000000000000000001256441046102023000203050ustar 00000000000000//! Tests for targets with `required-features`. use cargo_test_support::install::{assert_has_installed_exe, assert_has_not_installed_exe}; use cargo_test_support::is_nightly; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; #[cargo_test] fn build_bin_default_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] default = ["a"] a = [] [[bin]] name = "foo" required-features = ["a"] "#, ) .file( "src/main.rs", r#" extern crate foo; #[cfg(feature = "a")] fn test() { foo::foo(); } fn main() {} "#, ) .file("src/lib.rs", r#"#[cfg(feature = "a")] pub fn foo() {}"#) .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); p.cargo("build --no-default-features").run(); p.cargo("build --bin=foo").run(); assert!(p.bin("foo").is_file()); p.cargo("build --bin=foo --no-default-features") .with_status(101) .with_stderr_data(str![[r#" [ERROR] target `foo` in package `foo` requires the features: `a` Consider enabling them by passing, e.g., `--features="a"` "#]]) .run(); } #[cargo_test] fn build_bin_arg_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] a = [] [[bin]] name = "foo" required-features = ["a"] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("build --features a").run(); assert!(p.bin("foo").is_file()); } #[cargo_test] fn build_bin_multiple_required_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] default = ["a", "b"] a = [] b = ["a"] c = [] [[bin]] name = "foo_1" path = "src/foo_1.rs" required-features = ["b", "c"] [[bin]] name = "foo_2" path = "src/foo_2.rs" required-features = ["a"] "#, ) .file("src/foo_1.rs", "fn main() {}") .file("src/foo_2.rs", "fn main() {}") .build(); p.cargo("build").run(); assert!(!p.bin("foo_1").is_file()); assert!(p.bin("foo_2").is_file()); p.cargo("build --features c").run(); assert!(p.bin("foo_1").is_file()); assert!(p.bin("foo_2").is_file()); p.cargo("build --no-default-features").run(); } #[cargo_test] fn build_example_default_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] default = ["a"] a = [] [[example]] name = "foo" required-features = ["a"] "#, ) .file("examples/foo.rs", "fn main() {}") .build(); p.cargo("build --example=foo").run(); assert!(p.bin("examples/foo").is_file()); p.cargo("build --example=foo --no-default-features") .with_status(101) .with_stderr_data(str![[r#" [ERROR] target `foo` in package `foo` requires the features: `a` Consider enabling them by passing, e.g., `--features="a"` "#]]) .run(); } #[cargo_test] fn build_example_arg_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] a = [] [[example]] name = "foo" required-features = ["a"] "#, ) .file("examples/foo.rs", "fn main() {}") .build(); p.cargo("build --example=foo --features a").run(); assert!(p.bin("examples/foo").is_file()); } #[cargo_test] fn build_example_multiple_required_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] default = ["a", "b"] a = [] b = ["a"] c = [] [[example]] name = "foo_1" required-features = ["b", "c"] [[example]] name = "foo_2" required-features = ["a"] "#, ) .file("examples/foo_1.rs", "fn main() {}") .file("examples/foo_2.rs", "fn main() {}") .build(); p.cargo("build --example=foo_1") .with_status(101) .with_stderr_data(str![[r#" [ERROR] target `foo_1` in package `foo` requires the features: `b`, `c` Consider enabling them by passing, e.g., `--features="b c"` "#]]) .run(); p.cargo("build --example=foo_2").run(); assert!(!p.bin("examples/foo_1").is_file()); assert!(p.bin("examples/foo_2").is_file()); p.cargo("build --example=foo_1 --features c").run(); p.cargo("build --example=foo_2 --features c").run(); assert!(p.bin("examples/foo_1").is_file()); assert!(p.bin("examples/foo_2").is_file()); p.cargo("build --example=foo_1 --no-default-features") .with_status(101) .with_stderr_data(str![[r#" [ERROR] target `foo_1` in package `foo` requires the features: `b`, `c` Consider enabling them by passing, e.g., `--features="b c"` "#]]) .run(); p.cargo("build --example=foo_2 --no-default-features") .with_status(101) .with_stderr_data(str![[r#" [ERROR] target `foo_2` in package `foo` requires the features: `a` Consider enabling them by passing, e.g., `--features="a"` "#]]) .run(); } #[cargo_test] fn test_default_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] default = ["a"] a = [] [[test]] name = "foo" required-features = ["a"] "#, ) .file("tests/foo.rs", "#[test]\nfn test() {}") .build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] tests/foo.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); p.cargo("test --no-default-features") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); p.cargo("test --test=foo") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] tests/foo.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); p.cargo("test --test=foo --no-default-features") .with_status(101) .with_stderr_data(str![[r#" [ERROR] target `foo` in package `foo` requires the features: `a` Consider enabling them by passing, e.g., `--features="a"` "#]]) .run(); } #[cargo_test] fn test_arg_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] a = [] [[test]] name = "foo" required-features = ["a"] "#, ) .file("tests/foo.rs", "#[test]\nfn test() {}") .build(); p.cargo("test --features a") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] tests/foo.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn test_multiple_required_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] default = ["a", "b"] a = [] b = ["a"] c = [] [[test]] name = "foo_1" required-features = ["b", "c"] [[test]] name = "foo_2" required-features = ["a"] "#, ) .file("tests/foo_1.rs", "#[test]\nfn test() {}") .file("tests/foo_2.rs", "#[test]\nfn test() {}") .build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] tests/foo_2.rs (target/debug/deps/foo_2-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); p.cargo("test --features c") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] tests/foo_1.rs (target/debug/deps/foo_1-[HASH][EXE]) [RUNNING] tests/foo_2.rs (target/debug/deps/foo_2-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); p.cargo("test --no-default-features") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_default_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] default = ["a"] a = [] [[bench]] name = "foo" required-features = ["a"] "#, ) .file( "benches/foo.rs", r#" #![feature(test)] extern crate test; #[bench] fn bench(_: &mut test::Bencher) { } "#, ) .build(); p.cargo("bench") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] benches/foo.rs (target/release/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); p.cargo("bench --no-default-features") .with_stderr_data(str![[r#" [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); p.cargo("bench --bench=foo") .with_stderr_data(str![[r#" [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] benches/foo.rs (target/release/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); p.cargo("bench --bench=foo --no-default-features") .with_status(101) .with_stderr_data(str![[r#" [ERROR] target `foo` in package `foo` requires the features: `a` Consider enabling them by passing, e.g., `--features="a"` "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_arg_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] a = [] [[bench]] name = "foo" required-features = ["a"] "#, ) .file( "benches/foo.rs", r#" #![feature(test)] extern crate test; #[bench] fn bench(_: &mut test::Bencher) { } "#, ) .build(); p.cargo("bench --features a") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] benches/foo.rs (target/release/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "bench")] fn bench_multiple_required_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] default = ["a", "b"] a = [] b = ["a"] c = [] [[bench]] name = "foo_1" required-features = ["b", "c"] [[bench]] name = "foo_2" required-features = ["a"] "#, ) .file( "benches/foo_1.rs", r#" #![feature(test)] extern crate test; #[bench] fn bench(_: &mut test::Bencher) { } "#, ) .file( "benches/foo_2.rs", r#" #![feature(test)] extern crate test; #[bench] fn bench(_: &mut test::Bencher) { } "#, ) .build(); p.cargo("bench") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] benches/foo_2.rs (target/release/deps/foo_2-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); p.cargo("bench --features c") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] benches/foo_1.rs (target/release/deps/foo_1-[HASH][EXE]) [RUNNING] benches/foo_2.rs (target/release/deps/foo_2-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); p.cargo("bench --no-default-features") .with_stderr_data(str![[r#" [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); } #[cargo_test] fn install_default_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] default = ["a"] a = [] [[bin]] name = "foo" required-features = ["a"] [[example]] name = "foo" required-features = ["a"] "#, ) .file("src/main.rs", "fn main() {}") .file("examples/foo.rs", "fn main() {}") .build(); p.cargo("install --path .").run(); assert_has_installed_exe(paths::cargo_home(), "foo"); p.cargo("uninstall foo").run(); p.cargo("install --path . --no-default-features") .with_stderr_data(str![[r#" [INSTALLING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [WARNING] none of the package's binaries are available for install using the selected features bin "foo" requires the features: `a` example "foo" requires the features: `a` Consider enabling some of the needed features by passing, e.g., `--features="a"` "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo"); p.cargo("install --path . --bin=foo").run(); assert_has_installed_exe(paths::cargo_home(), "foo"); p.cargo("uninstall foo").run(); p.cargo("install --path . --bin=foo --no-default-features") .with_status(101) .with_stderr_data(str![[r#" [INSTALLING] foo v0.0.1 ([ROOT]/foo) [ERROR] failed to compile `foo v0.0.1 ([ROOT]/foo)`, intermediate artifacts can be found at `[ROOT]/foo/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` Consider enabling them by passing, e.g., `--features="a"` "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo"); p.cargo("install --path . --example=foo").run(); assert_has_installed_exe(paths::cargo_home(), "foo"); p.cargo("uninstall foo").run(); p.cargo("install --path . --example=foo --no-default-features") .with_status(101) .with_stderr_data(str![[r#" [INSTALLING] foo v0.0.1 ([ROOT]/foo) [ERROR] failed to compile `foo v0.0.1 ([ROOT]/foo)`, intermediate artifacts can be found at `[ROOT]/foo/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` Consider enabling them by passing, e.g., `--features="a"` "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo"); } #[cargo_test] fn install_arg_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] a = [] [[bin]] name = "foo" required-features = ["a"] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("install --features a").run(); assert_has_installed_exe(paths::cargo_home(), "foo"); p.cargo("uninstall foo").run(); } #[cargo_test] fn install_multiple_required_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] default = ["a", "b"] a = [] b = ["a"] c = [] [[bin]] name = "foo_1" path = "src/foo_1.rs" required-features = ["b", "c"] [[bin]] name = "foo_2" path = "src/foo_2.rs" required-features = ["a"] [[example]] name = "foo_3" path = "src/foo_3.rs" required-features = ["b", "c"] [[example]] name = "foo_4" path = "src/foo_4.rs" required-features = ["a"] "#, ) .file("src/foo_1.rs", "fn main() {}") .file("src/foo_2.rs", "fn main() {}") .file("src/foo_3.rs", "fn main() {}") .file("src/foo_4.rs", "fn main() {}") .build(); p.cargo("install --path .").run(); assert_has_not_installed_exe(paths::cargo_home(), "foo_1"); assert_has_installed_exe(paths::cargo_home(), "foo_2"); assert_has_not_installed_exe(paths::cargo_home(), "foo_3"); assert_has_not_installed_exe(paths::cargo_home(), "foo_4"); p.cargo("uninstall foo").run(); p.cargo("install --path . --bins --examples").run(); assert_has_not_installed_exe(paths::cargo_home(), "foo_1"); assert_has_installed_exe(paths::cargo_home(), "foo_2"); assert_has_not_installed_exe(paths::cargo_home(), "foo_3"); assert_has_installed_exe(paths::cargo_home(), "foo_4"); p.cargo("uninstall foo").run(); p.cargo("install --path . --features c").run(); assert_has_installed_exe(paths::cargo_home(), "foo_1"); assert_has_installed_exe(paths::cargo_home(), "foo_2"); assert_has_not_installed_exe(paths::cargo_home(), "foo_3"); assert_has_not_installed_exe(paths::cargo_home(), "foo_4"); p.cargo("uninstall foo").run(); p.cargo("install --path . --features c --bins --examples") .run(); assert_has_installed_exe(paths::cargo_home(), "foo_1"); assert_has_installed_exe(paths::cargo_home(), "foo_2"); assert_has_installed_exe(paths::cargo_home(), "foo_3"); assert_has_installed_exe(paths::cargo_home(), "foo_4"); p.cargo("uninstall foo").run(); p.cargo("install --path . --no-default-features") .with_stderr_data(str![[r#" [INSTALLING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [WARNING] none of the package's binaries are available for install using the selected features bin "foo_1" requires the features: `b`, `c` bin "foo_2" requires the features: `a` example "foo_3" requires the features: `b`, `c` example "foo_4" requires the features: `a` Consider enabling some of the needed features by passing, e.g., `--features="b c"` "#]]) .run(); p.cargo("install --path . --no-default-features --bins") .with_stderr_data(str![[r#" [INSTALLING] foo v0.0.1 ([ROOT]/foo) [WARNING] target filter `bins` specified, but no targets matched; this is a no-op [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [WARNING] none of the package's binaries are available for install using the selected features bin "foo_1" requires the features: `b`, `c` bin "foo_2" requires the features: `a` example "foo_3" requires the features: `b`, `c` example "foo_4" requires the features: `a` Consider enabling some of the needed features by passing, e.g., `--features="b c"` "#]]) .run(); p.cargo("install --path . --no-default-features --examples") .with_stderr_data(str![[r#" [INSTALLING] foo v0.0.1 ([ROOT]/foo) [WARNING] target filter `examples` specified, but no targets matched; this is a no-op [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [WARNING] none of the package's binaries are available for install using the selected features bin "foo_1" requires the features: `b`, `c` bin "foo_2" requires the features: `a` example "foo_3" requires the features: `b`, `c` example "foo_4" requires the features: `a` Consider enabling some of the needed features by passing, e.g., `--features="b c"` "#]]) .run(); p.cargo("install --path . --no-default-features --bins --examples") .with_stderr_data(str![[r#" [INSTALLING] foo v0.0.1 ([ROOT]/foo) [WARNING] target filters `bins`, `examples` specified, but no targets matched; this is a no-op [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [WARNING] none of the package's binaries are available for install using the selected features bin "foo_1" requires the features: `b`, `c` bin "foo_2" requires the features: `a` example "foo_3" requires the features: `b`, `c` example "foo_4" requires the features: `a` Consider enabling some of the needed features by passing, e.g., `--features="b c"` "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo_1"); assert_has_not_installed_exe(paths::cargo_home(), "foo_2"); assert_has_not_installed_exe(paths::cargo_home(), "foo_3"); assert_has_not_installed_exe(paths::cargo_home(), "foo_4"); } #[cargo_test] fn dep_feature_in_toml() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = { path = "bar", features = ["a"] } [[bin]] name = "foo" required-features = ["bar/a"] [[example]] name = "foo" required-features = ["bar/a"] [[test]] name = "foo" required-features = ["bar/a"] [[bench]] name = "foo" required-features = ["bar/a"] "#, ) .file("src/main.rs", "fn main() {}") .file("examples/foo.rs", "fn main() {}") .file("tests/foo.rs", "#[test]\nfn test() {}") .file( "benches/foo.rs", r#" #![feature(test)] extern crate test; #[bench] fn bench(_: &mut test::Bencher) { } "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [features] a = [] "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("build").run(); // bin p.cargo("build --bin=foo").run(); assert!(p.bin("foo").is_file()); // example p.cargo("build --example=foo").run(); assert!(p.bin("examples/foo").is_file()); // test p.cargo("test --test=foo") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] tests/foo.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); // bench if is_nightly() { p.cargo("bench --bench=foo") .with_stderr_data(str![[r#" [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] benches/foo.rs (target/release/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } // install p.cargo("install").run(); assert_has_installed_exe(paths::cargo_home(), "foo"); p.cargo("uninstall foo").run(); } #[cargo_test] fn dep_feature_in_cmd_line() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = { path = "bar" } [[bin]] name = "foo" required-features = ["bar/a"] [[example]] name = "foo" required-features = ["bar/a"] [[test]] name = "foo" required-features = ["bar/a"] [[bench]] name = "foo" required-features = ["bar/a"] "#, ) .file("src/main.rs", "fn main() {}") .file("examples/foo.rs", "fn main() {}") .file( "tests/foo.rs", r#" #[test] fn bin_is_built() { let s = format!("target/debug/foo{}", std::env::consts::EXE_SUFFIX); let p = std::path::Path::new(&s); assert!(p.exists(), "foo does not exist"); } "#, ) .file( "benches/foo.rs", r#" #![feature(test)] extern crate test; #[bench] fn bench(_: &mut test::Bencher) { } "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [features] a = [] "#, ) .file("bar/src/lib.rs", "") .build(); // This is a no-op p.cargo("build") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(!p.bin("foo").is_file()); // bin p.cargo("build --bin=foo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] target `foo` in package `foo` requires the features: `bar/a` Consider enabling them by passing, e.g., `--features="bar/a"` "#]]) .run(); p.cargo("build --bin=foo --features bar/a").run(); assert!(p.bin("foo").is_file()); // example p.cargo("build --example=foo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] target `foo` in package `foo` requires the features: `bar/a` Consider enabling them by passing, e.g., `--features="bar/a"` "#]]) .run(); p.cargo("build --example=foo --features bar/a").run(); assert!(p.bin("examples/foo").is_file()); // test // This is a no-op, since no tests are enabled p.cargo("test") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); // Delete the target directory so this can check if the main.rs gets built. p.build_dir().rm_rf(); p.cargo("test --test=foo --features bar/a") .with_stderr_data(str![[r#" [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] tests/foo.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test bin_is_built ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); // bench if is_nightly() { p.cargo("bench") .with_stderr_data(str![[r#" [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s "#]]) .with_stdout_data("") .run(); p.cargo("bench --bench=foo --features bar/a") .with_stderr_data(str![[r#" [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] benches/foo.rs (target/release/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test bench ... bench: [AVG_ELAPSED] ns/iter (+/- [JITTER]) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } // install p.cargo("install --path .") .with_stderr_data(str![[r#" [INSTALLING] foo v0.0.1 ([ROOT]/foo) [LOCKING] 1 package to latest compatible version [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [WARNING] none of the package's binaries are available for install using the selected features bin "foo" requires the features: `bar/a` example "foo" requires the features: `bar/a` Consider enabling some of the needed features by passing, e.g., `--features="bar/a"` "#]]) .run(); assert_has_not_installed_exe(paths::cargo_home(), "foo"); p.cargo("install --features bar/a").run(); assert_has_installed_exe(paths::cargo_home(), "foo"); p.cargo("uninstall foo").run(); } #[cargo_test] fn test_skips_compiling_bin_with_missing_required_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] a = [] [[bin]] name = "bin_foo" path = "src/bin/foo.rs" required-features = ["a"] "#, ) .file("src/bin/foo.rs", "extern crate bar; fn main() {}") .file("tests/foo.rs", "") .file("benches/foo.rs", "") .build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] tests/foo.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); p.cargo("test --features a -j 1") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) error[E0463]: can't find crate for `bar` ... "#]]) .run(); if is_nightly() { p.cargo("bench") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] benches/foo.rs (target/release/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); p.cargo("bench --features a -j 1") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) error[E0463]: can't find crate for `bar` ... "#]]) .run(); } } #[cargo_test] fn run_default() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] default = [] a = [] [[bin]] name = "foo" required-features = ["a"] "#, ) .file("src/lib.rs", "") .file("src/main.rs", "extern crate foo; fn main() {}") .build(); p.cargo("run") .with_status(101) .with_stderr_data(str![[r#" [ERROR] target `foo` in package `foo` requires the features: `a` Consider enabling them by passing, e.g., `--features="a"` "#]]) .run(); p.cargo("run --features a").run(); } #[cargo_test] fn run_default_multiple_required_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] default = ["a"] a = [] b = [] [[bin]] name = "foo1" path = "src/foo1.rs" required-features = ["a"] [[bin]] name = "foo3" path = "src/foo3.rs" required-features = ["b"] [[bin]] name = "foo2" path = "src/foo2.rs" required-features = ["b"] "#, ) .file("src/lib.rs", "") .file("src/foo1.rs", "extern crate foo; fn main() {}") .file("src/foo3.rs", "extern crate foo; fn main() {}") .file("src/foo2.rs", "extern crate foo; fn main() {}") .build(); p.cargo("run") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `cargo run` could not determine which binary to run. Use the `--bin` option to specify a binary, or the `default-run` manifest key. available binaries: foo1, foo2, foo3 "#]]) .run(); } #[cargo_test] fn renamed_required_features() { // Test that required-features uses renamed package feature names. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [[bin]] name = "x" required-features = ["a1/f1"] [dependencies] a1 = {path="a1", package="a"} a2 = {path="a2", package="a"} "#, ) .file( "src/bin/x.rs", r#" fn main() { a1::f(); a2::f(); } "#, ) .file( "a1/Cargo.toml", r#" [package] name = "a" version = "0.1.0" [features] f1 = [] "#, ) .file( "a1/src/lib.rs", r#" pub fn f() { if cfg!(feature="f1") { println!("a1 f1"); } } "#, ) .file( "a2/Cargo.toml", r#" [package] name = "a" version = "0.2.0" [features] f2 = [] "#, ) .file( "a2/src/lib.rs", r#" pub fn f() { if cfg!(feature="f2") { println!("a2 f2"); } } "#, ) .build(); p.cargo("run") .with_status(101) .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [ERROR] target `x` in package `foo` requires the features: `a1/f1` Consider enabling them by passing, e.g., `--features="a1/f1"` "#]]) .run(); p.cargo("build --features a1/f1").run(); p.rename_run("x", "x_with_f1") .with_stdout_data(str![[r#" a1 f1 "#]]) .run(); p.cargo("build --features a1/f1,a2/f2").run(); p.rename_run("x", "x_with_f1_f2") .with_stdout_data(str![[r#" a1 f1 a2 f2 "#]]) .run(); } #[cargo_test] fn truncated_install_warning_message() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2021" [features] feature1 = [] feature2 = [] feature3 = [] feature4 = [] feature5 = [] [[bin]] name = "foo1" required-features = ["feature1", "feature2", "feature3"] [[bin]] name = "foo2" required-features = ["feature2"] [[bin]] name = "foo3" required-features = ["feature3"] [[bin]] name = "foo4" required-features = ["feature4", "feature1"] [[bin]] name = "foo5" required-features = ["feature1", "feature2", "feature3", "feature4", "feature5"] [[bin]] name = "foo6" required-features = ["feature1", "feature2", "feature3", "feature4", "feature5"] [[bin]] name = "foo7" required-features = ["feature1", "feature2", "feature3", "feature4", "feature5"] [[bin]] name = "foo8" required-features = ["feature1", "feature2", "feature3", "feature4", "feature5"] [[bin]] name = "foo9" required-features = ["feature1", "feature2", "feature3", "feature4", "feature5"] [[bin]] name = "foo10" required-features = ["feature1", "feature2", "feature3", "feature4", "feature5"] [[example]] name = "example1" required-features = ["feature1", "feature2"] "#, ) .file("src/bin/foo1.rs", "fn main() {}") .file("src/bin/foo2.rs", "fn main() {}") .file("src/bin/foo3.rs", "fn main() {}") .file("src/bin/foo4.rs", "fn main() {}") .file("src/bin/foo5.rs", "fn main() {}") .file("src/bin/foo6.rs", "fn main() {}") .file("src/bin/foo7.rs", "fn main() {}") .file("src/bin/foo8.rs", "fn main() {}") .file("src/bin/foo9.rs", "fn main() {}") .file("src/bin/foo10.rs", "fn main() {}") .file("examples/example1.rs", "fn main() {}") .build(); p.cargo("install --path .").with_stderr_data(str![[r#" [INSTALLING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [WARNING] none of the package's binaries are available for install using the selected features bin "foo1" requires the features: `feature1`, `feature2`, `feature3` bin "foo10" requires the features: `feature1`, `feature2`, `feature3`, `feature4`, `feature5` bin "foo2" requires the features: `feature2` bin "foo3" requires the features: `feature3` bin "foo4" requires the features: `feature4`, `feature1` bin "foo5" requires the features: `feature1`, `feature2`, `feature3`, `feature4`, `feature5` bin "foo6" requires the features: `feature1`, `feature2`, `feature3`, `feature4`, `feature5` 4 more targets also requires features not enabled. See them in the Cargo.toml file. Consider enabling some of the needed features by passing, e.g., `--features="feature1 feature2 feature3"` "#]]).run(); } cargo-0.86.0/tests/testsuite/run.rs000064400000000000000000001253651046102023000153730ustar 00000000000000//! Tests for the `cargo run` command. use cargo_test_support::prelude::*; use cargo_test_support::{ basic_bin_manifest, basic_lib_manifest, basic_manifest, project, str, Project, }; use cargo_util::paths::dylib_path_envvar; #[cargo_test] fn simple() { let p = project() .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); p.cargo("run") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .with_stdout_data(str![[r#" hello "#]]) .run(); assert!(p.bin("foo").is_file()); } #[cargo_test] fn quiet_arg() { let p = project() .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); p.cargo("run -q") .with_stderr_data("") .with_stdout_data(str![[r#" hello "#]]) .run(); p.cargo("run --quiet") .with_stderr_data("") .with_stdout_data(str![[r#" hello "#]]) .run(); } #[cargo_test] fn unsupported_silent_arg() { let p = project() .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); p.cargo("run -s") .with_stderr_data(str![[r#" [ERROR] unexpected argument '--silent' found tip: a similar argument exists: '--quiet' Usage: cargo[EXE] run [OPTIONS] [ARGS]... For more information, try '--help'. "#]]) .with_status(1) .run(); p.cargo("run --silent") .with_stderr_data(str![[r#" [ERROR] unexpected argument '--silent' found tip: a similar argument exists: '--quiet' Usage: cargo[EXE] run [OPTIONS] [ARGS]... For more information, try '--help'. "#]]) .with_status(1) .run(); } #[cargo_test] fn quiet_arg_and_verbose_arg() { let p = project() .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); p.cargo("run -q -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot set both --verbose and --quiet "#]]) .run(); } #[cargo_test] fn quiet_arg_and_verbose_config() { let p = project() .file( ".cargo/config.toml", r#" [term] verbose = true "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); p.cargo("run -q") .with_stderr_data("") .with_stdout_data(str![[r#" hello "#]]) .run(); } #[cargo_test] fn verbose_arg_and_quiet_config() { let p = project() .file( ".cargo/config.toml", r#" [term] quiet = true "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); p.cargo("run -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .with_stdout_data(str![[r#" hello "#]]) .run(); } #[cargo_test] fn quiet_config_alone() { let p = project() .file( ".cargo/config.toml", r#" [term] quiet = true "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); p.cargo("run") .with_stderr_data("") .with_stdout_data(str![[r#" hello "#]]) .run(); } #[cargo_test] fn verbose_config_alone() { let p = project() .file( ".cargo/config.toml", r#" [term] verbose = true "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); p.cargo("run") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .with_stdout_data(str![[r#" hello "#]]) .run(); } #[cargo_test] fn quiet_config_and_verbose_config() { let p = project() .file( ".cargo/config.toml", r#" [term] verbose = true quiet = true "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); p.cargo("run") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot set both `term.verbose` and `term.quiet` "#]]) .run(); } #[cargo_test] fn simple_with_args() { let p = project() .file( "src/main.rs", r#" fn main() { assert_eq!(std::env::args().nth(1).unwrap(), "hello"); assert_eq!(std::env::args().nth(2).unwrap(), "world"); } "#, ) .build(); p.cargo("run hello world").run(); } #[cfg(unix)] #[cargo_test] fn simple_with_non_utf8_args() { use std::os::unix::ffi::OsStrExt; let p = project() .file( "src/main.rs", r#" use std::ffi::OsStr; use std::os::unix::ffi::OsStrExt; fn main() { assert_eq!(std::env::args_os().nth(1).unwrap(), OsStr::from_bytes(b"hello")); assert_eq!(std::env::args_os().nth(2).unwrap(), OsStr::from_bytes(b"ab\xffcd")); } "#, ) .build(); p.cargo("run") .arg("hello") .arg(std::ffi::OsStr::from_bytes(b"ab\xFFcd")) .run(); } #[cargo_test] fn exit_code() { let p = project() .file("src/main.rs", "fn main() { std::process::exit(2); }") .build(); let expected = if !cfg!(unix) { str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` [ERROR] process didn't exit successfully: `target/debug/foo[EXE]` ([EXIT_STATUS]: 2) "#]] } else { str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo` "#]] }; p.cargo("run") .with_status(2) .with_stderr_data(expected) .run(); } #[cargo_test] fn exit_code_verbose() { let p = project() .file("src/main.rs", "fn main() { std::process::exit(2); }") .build(); let expected = if !cfg!(unix) { str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` [ERROR] process didn't exit successfully: `target/debug/foo[EXE]` ([EXIT_STATUS]: 2) "#]] } else { str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]] }; p.cargo("run -v") .with_status(2) .with_stderr_data(expected) .run(); } #[cargo_test] fn no_main_file() { let p = project().file("src/lib.rs", "").build(); p.cargo("run") .with_status(101) .with_stderr_data(str![[r#" [ERROR] a bin target must be available for `cargo run` "#]]) .run(); } #[cargo_test] fn too_many_bins() { let p = project() .file("src/lib.rs", "") .file("src/bin/a.rs", "") .file("src/bin/b.rs", "") .build(); // Using [..] here because the order is not stable p.cargo("run") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `cargo run` could not determine which binary to run. Use the `--bin` option to specify a binary, or the `default-run` manifest key. available binaries: a, b "#]]) .run(); } #[cargo_test] fn specify_name() { let p = project() .file("src/lib.rs", "") .file( "src/bin/a.rs", r#" #[allow(unused_extern_crates)] extern crate foo; fn main() { println!("hello a.rs"); } "#, ) .file( "src/bin/b.rs", r#" #[allow(unused_extern_crates)] extern crate foo; fn main() { println!("hello b.rs"); } "#, ) .build(); p.cargo("run --bin a -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] src/lib.rs [..]` [RUNNING] `rustc [..] src/bin/a.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/a[EXE]` "#]]) .with_stdout_data(str![[r#" hello a.rs "#]]) .run(); p.cargo("run --bin b -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] src/bin/b.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/b[EXE]` "#]]) .with_stdout_data(str![[r#" hello b.rs "#]]) .run(); } #[cargo_test] fn specify_default_run() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] default-run = "a" "#, ) .file("src/lib.rs", "") .file("src/bin/a.rs", r#"fn main() { println!("hello A"); }"#) .file("src/bin/b.rs", r#"fn main() { println!("hello B"); }"#) .build(); p.cargo("run") .with_stdout_data(str![[r#" hello A "#]]) .run(); p.cargo("run --bin a") .with_stdout_data(str![[r#" hello A "#]]) .run(); p.cargo("run --bin b") .with_stdout_data(str![[r#" hello B "#]]) .run(); } #[cargo_test] fn bogus_default_run() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] default-run = "b" "#, ) .file("src/lib.rs", "") .file("src/bin/a.rs", r#"fn main() { println!("hello A"); }"#) .build(); p.cargo("run") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: default-run target `b` not found Did you mean `a`? "#]]) .run(); } #[cargo_test] fn run_example() { let p = project() .file("src/lib.rs", "") .file("examples/a.rs", r#"fn main() { println!("example"); }"#) .file("src/bin/a.rs", r#"fn main() { println!("bin"); }"#) .build(); p.cargo("run --example a") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/examples/a[EXE]` "#]]) .with_stdout_data(str![[r#" example "#]]) .run(); } #[cargo_test] fn run_library_example() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[example]] name = "bar" crate-type = ["lib"] "#, ) .file("src/lib.rs", "") .file("examples/bar.rs", "fn foo() {}") .build(); p.cargo("run --example bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] example target `bar` is a library and cannot be executed "#]]) .run(); } #[cargo_test] fn run_bin_example() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [[example]] name = "bar" crate-type = ["bin"] "#, ) .file("src/lib.rs", "") .file("examples/bar.rs", r#"fn main() { println!("example"); }"#) .build(); p.cargo("run --example bar") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/examples/bar[EXE]` "#]]) .with_stdout_data(str![[r#" example "#]]) .run(); } fn autodiscover_examples_project(rust_edition: &str, autoexamples: Option) -> Project { let autoexamples = match autoexamples { None => "".to_string(), Some(bool) => format!("autoexamples = {}", bool), }; project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" authors = [] edition = "{rust_edition}" {autoexamples} [features] magic = [] [[example]] name = "do_magic" required-features = ["magic"] "#, rust_edition = rust_edition, autoexamples = autoexamples ), ) .file("examples/a.rs", r#"fn main() { println!("example"); }"#) .file( "examples/do_magic.rs", r#" fn main() { println!("magic example"); } "#, ) .build() } #[cargo_test] fn run_example_autodiscover_2015() { let p = autodiscover_examples_project("2015", None); p.cargo("run --example a") .with_status(101) .with_stderr_data(str![[r#" [WARNING] An explicit [[example]] section is specified in Cargo.toml which currently disables Cargo from automatically inferring other example targets. This inference behavior will change in the Rust 2018 edition and the following files will be included as a example target: * examples/a.rs This is likely to break cargo build or cargo test as these files may not be ready to be compiled as a example target today. You can future-proof yourself and disable this warning by adding `autoexamples = false` to your [package] section. You may also move the files to a location where Cargo would not automatically infer them to be a target, such as in subfolders. For more information on this warning you can consult https://github.com/rust-lang/cargo/issues/5330 [ERROR] no example target named `a`. Available example targets: do_magic "#]]) .run(); } #[cargo_test] fn run_example_autodiscover_2015_with_autoexamples_enabled() { let p = autodiscover_examples_project("2015", Some(true)); p.cargo("run --example a") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/examples/a[EXE]` "#]]) .with_stdout_data(str![[r#" example "#]]) .run(); } #[cargo_test] fn run_example_autodiscover_2015_with_autoexamples_disabled() { let p = autodiscover_examples_project("2015", Some(false)); p.cargo("run --example a") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no example target named `a`. Available example targets: do_magic "#]]) .run(); } #[cargo_test] fn run_example_autodiscover_2018() { let p = autodiscover_examples_project("2018", None); p.cargo("run --example a") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/examples/a[EXE]` "#]]) .with_stdout_data(str![[r#" example "#]]) .run(); } #[cargo_test] fn autobins_disables() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" autobins = false "#, ) .file("src/lib.rs", "pub mod bin;") .file("src/bin/mod.rs", "// empty") .build(); p.cargo("run") .with_status(101) .with_stderr_data(str![[r#" [ERROR] a bin target must be available for `cargo run` "#]]) .run(); } #[cargo_test] fn run_bins() { let p = project() .file("src/lib.rs", "") .file("examples/a.rs", r#"fn main() { println!("example"); }"#) .file("src/bin/a.rs", r#"fn main() { println!("bin"); }"#) .build(); p.cargo("run --bins") .with_status(1) .with_stderr_data(str![[r#" [ERROR] unexpected argument '--bins' found tip: a similar argument exists: '--bin' ... "#]]) .run(); } #[cargo_test] fn run_with_filename() { let p = project() .file("src/lib.rs", "") .file( "src/bin/a.rs", r#" extern crate foo; fn main() { println!("hello a.rs"); } "#, ) .file("examples/a.rs", r#"fn main() { println!("example"); }"#) .build(); p.cargo("run --bin bin.rs") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no bin target named `bin.rs`. Available bin targets: a "#]]) .run(); p.cargo("run --bin a.rs") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no bin target named `a.rs` Did you mean `a`? "#]]) .run(); p.cargo("run --example example.rs") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no example target named `example.rs`. Available example targets: a "#]]) .run(); p.cargo("run --example a.rs") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no example target named `a.rs` Did you mean `a`? "#]]) .run(); } #[cargo_test] fn either_name_or_example() { let p = project() .file("src/bin/a.rs", r#"fn main() { println!("hello a.rs"); }"#) .file("examples/b.rs", r#"fn main() { println!("hello b.rs"); }"#) .build(); p.cargo("run --bin a --example b") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `cargo run` can run at most one executable, but multiple were specified "#]]) .run(); } #[cargo_test] fn one_bin_multiple_examples() { let p = project() .file("src/lib.rs", "") .file( "src/bin/main.rs", r#"fn main() { println!("hello main.rs"); }"#, ) .file("examples/a.rs", r#"fn main() { println!("hello a.rs"); }"#) .file("examples/b.rs", r#"fn main() { println!("hello b.rs"); }"#) .build(); p.cargo("run") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/main[EXE]` "#]]) .with_stdout_data(str![[r#" hello main.rs "#]]) .run(); } #[cargo_test] fn example_with_release_flag() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] version = "*" path = "bar" "#, ) .file( "examples/a.rs", r#" extern crate bar; fn main() { if cfg!(debug_assertions) { println!("slow1") } else { println!("fast1") } bar::baz(); } "#, ) .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file( "bar/src/bar.rs", r#" pub fn baz() { if cfg!(debug_assertions) { println!("slow2") } else { println!("fast2") } } "#, ) .build(); p.cargo("run -v --release --example a") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar --edition=2015 bar/src/bar.rs [..]--crate-type lib --emit=[..]link -C opt-level=3[..] -C metadata=[..] --out-dir [ROOT]/foo/target/release/deps -C strip=debuginfo -L dependency=[ROOT]/foo/target/release/deps` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name a --edition=2015 examples/a.rs [..]--crate-type bin --emit=[..]link -C opt-level=3[..] -C metadata=[..] --out-dir [ROOT]/foo/target/release/examples -C strip=debuginfo -L dependency=[ROOT]/foo/target/release/deps --extern bar=[ROOT]/foo/target/release/deps/libbar-[HASH].rlib` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `target/release/examples/a[EXE]` "#]]) .with_stdout_data(str![[r#" fast1 fast2 "#]]) .run(); p.cargo("run -v --example a") .with_stderr_data(str![[r#" [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [RUNNING] `rustc --crate-name bar --edition=2015 bar/src/bar.rs [..]--crate-type lib --emit=[..]link [..]-C debuginfo=2 [..]-C metadata=[..] --out-dir [ROOT]/foo/target/debug/deps -L dependency=[ROOT]/foo/target/debug/deps` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name a --edition=2015 examples/a.rs [..]--crate-type bin --emit=[..]link [..]-C debuginfo=2 [..]-C metadata=[..] --out-dir [ROOT]/foo/target/debug/examples -L dependency=[ROOT]/foo/target/debug/deps --extern bar=[ROOT]/foo/target/debug/deps/libbar-[HASH].rlib` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/examples/a[EXE]` "#]]) .with_stdout_data(str![[r#" slow1 slow2 "#]]) .run(); } #[cargo_test] fn run_dylib_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "bar" "#, ) .file( "src/main.rs", r#"extern crate bar; fn main() { bar::bar(); }"#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" authors = [] [lib] name = "bar" crate-type = ["dylib"] "#, ) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("run hello world").run(); } #[cargo_test] fn run_with_bin_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies.bar] path = "bar" "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [[bin]] name = "bar" "#, ) .file("bar/src/main.rs", r#"fn main() { println!("bar"); }"#) .build(); p.cargo("run") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [WARNING] foo v0.0.1 ([ROOT]/foo) ignoring invalid dependency `bar` which is missing a lib target [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .with_stdout_data(str![[r#" hello "#]]) .run(); } #[cargo_test] fn run_with_bin_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies.bar1] path = "bar1" [dependencies.bar2] path = "bar2" "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .file( "bar1/Cargo.toml", r#" [package] name = "bar1" version = "0.0.1" edition = "2015" authors = [] [[bin]] name = "bar1" "#, ) .file("bar1/src/main.rs", r#"fn main() { println!("bar1"); }"#) .file( "bar2/Cargo.toml", r#" [package] name = "bar2" version = "0.0.1" edition = "2015" authors = [] [[bin]] name = "bar2" "#, ) .file("bar2/src/main.rs", r#"fn main() { println!("bar2"); }"#) .build(); p.cargo("run") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [WARNING] foo v0.0.1 ([ROOT]/foo) ignoring invalid dependency `bar1` which is missing a lib target [WARNING] foo v0.0.1 ([ROOT]/foo) ignoring invalid dependency `bar2` which is missing a lib target [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .with_stdout_data(str![[r#" hello "#]]) .run(); } #[cargo_test] fn run_with_bin_dep_in_workspace() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo1", "foo2"] "#, ) .file( "foo1/Cargo.toml", r#" [package] name = "foo1" version = "0.0.1" edition = "2015" [dependencies.bar1] path = "bar1" "#, ) .file("foo1/src/main.rs", r#"fn main() { println!("hello"); }"#) .file( "foo1/bar1/Cargo.toml", r#" [package] name = "bar1" version = "0.0.1" edition = "2015" authors = [] [[bin]] name = "bar1" "#, ) .file( "foo1/bar1/src/main.rs", r#"fn main() { println!("bar1"); }"#, ) .file( "foo2/Cargo.toml", r#" [package] name = "foo2" version = "0.0.1" edition = "2015" [dependencies.bar2] path = "bar2" "#, ) .file("foo2/src/main.rs", r#"fn main() { println!("hello"); }"#) .file( "foo2/bar2/Cargo.toml", r#" [package] name = "bar2" version = "0.0.1" edition = "2015" authors = [] [[bin]] name = "bar2" "#, ) .file( "foo2/bar2/src/main.rs", r#"fn main() { println!("bar2"); }"#, ) .build(); p.cargo("run") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `cargo run` could not determine which binary to run. Use the `--bin` option to specify a binary, or the `default-run` manifest key. available binaries: bar1, bar2, foo1, foo2 "#]]) .run(); p.cargo("run --bin foo1") .with_stderr_data(str![[r#" [WARNING] foo1 v0.0.1 ([ROOT]/foo/foo1) ignoring invalid dependency `bar1` which is missing a lib target [WARNING] foo2 v0.0.1 ([ROOT]/foo/foo2) ignoring invalid dependency `bar2` which is missing a lib target [COMPILING] foo1 v0.0.1 ([ROOT]/foo/foo1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo1[EXE]` "#]]) .with_stdout_data(str![[r#" hello "#]]) .run(); } #[cargo_test] fn release_works() { let p = project() .file( "src/main.rs", r#" fn main() { if cfg!(debug_assertions) { panic!() } } "#, ) .build(); p.cargo("run --release") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `target/release/foo[EXE]` "#]]) .run(); assert!(p.release_bin("foo").is_file()); } #[cargo_test] fn release_short_works() { let p = project() .file( "src/main.rs", r#" fn main() { if cfg!(debug_assertions) { panic!() } } "#, ) .build(); p.cargo("run -r") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `target/release/foo[EXE]` "#]]) .run(); assert!(p.release_bin("foo").is_file()); } #[cargo_test] fn run_bin_different_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[bin]] name = "bar" "#, ) .file("src/bar.rs", "fn main() {}") .build(); p.cargo("run").run(); } #[cargo_test] fn dashes_are_forwarded() { let p = project() .file( "src/bin/bar.rs", r#" fn main() { let s: Vec = std::env::args().collect(); assert_eq!(s[1], "--"); assert_eq!(s[2], "a"); assert_eq!(s[3], "--"); assert_eq!(s[4], "b"); } "#, ) .build(); p.cargo("run -- -- a -- b").run(); } #[cargo_test] fn run_from_executable_folder() { let p = project() .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); let cwd = p.root().join("target").join("debug"); p.cargo("build").run(); p.cargo("run") .cwd(cwd) .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `./foo[EXE]` "#]]) .with_stdout_data(str![[r#" hello "#]]) .run(); } #[cargo_test] fn run_with_library_paths() { let p = project(); // Only link search directories within the target output directory are // propagated through to dylib_path_envvar() (see #3366). let mut dir1 = p.target_debug_dir(); dir1.push("foo\\backslash"); let mut dir2 = p.target_debug_dir(); dir2.push("dir=containing=equal=signs"); let p = p .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "build.rs", &format!( r##" fn main() {{ println!(r#"cargo::rustc-link-search=native={}"#); println!(r#"cargo::rustc-link-search={}"#); }} "##, dir1.display(), dir2.display() ), ) .file( "src/main.rs", &format!( r##" fn main() {{ let search_path = std::env::var_os("{}").unwrap(); let paths = std::env::split_paths(&search_path).collect::>(); println!("{{:#?}}", paths); assert!(paths.contains(&r#"{}"#.into())); assert!(paths.contains(&r#"{}"#.into())); }} "##, dylib_path_envvar(), dir1.display(), dir2.display() ), ) .build(); p.cargo("run").run(); } #[cargo_test] fn library_paths_sorted_alphabetically() { let p = project(); let mut dir1 = p.target_debug_dir(); dir1.push("zzzzzzz"); let mut dir2 = p.target_debug_dir(); dir2.push("BBBBBBB"); let mut dir3 = p.target_debug_dir(); dir3.push("aaaaaaa"); let p = p .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file( "build.rs", &format!( r##" fn main() {{ println!(r#"cargo::rustc-link-search=native={}"#); println!(r#"cargo::rustc-link-search=native={}"#); println!(r#"cargo::rustc-link-search=native={}"#); }} "##, dir1.display(), dir2.display(), dir3.display() ), ) .file( "src/main.rs", &format!( r##" fn main() {{ let search_path = std::env::var_os("{}").unwrap(); let paths = std::env::split_paths(&search_path).collect::>(); // ASCII case-sensitive sort assert_eq!("BBBBBBB", paths[0].file_name().unwrap().to_string_lossy()); assert_eq!("aaaaaaa", paths[1].file_name().unwrap().to_string_lossy()); assert_eq!("zzzzzzz", paths[2].file_name().unwrap().to_string_lossy()); }} "##, dylib_path_envvar() ), ) .build(); p.cargo("run").run(); } #[cargo_test] fn fail_no_extra_verbose() { let p = project() .file("src/main.rs", "fn main() { std::process::exit(1); }") .build(); p.cargo("run -q") .with_status(1) .with_stdout_data("") .with_stderr_data("") .run(); } #[cargo_test] fn run_multiple_packages() { let p = project() .no_manifest() .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [workspace] [dependencies] d1 = { path = "d1" } d2 = { path = "d2" } d3 = { path = "../d3" } # outside of the workspace [[bin]] name = "foo" "#, ) .file("foo/src/foo.rs", "fn main() { println!(\"foo\"); }") .file("foo/d1/Cargo.toml", &basic_bin_manifest("d1")) .file("foo/d1/src/lib.rs", "") .file("foo/d1/src/main.rs", "fn main() { println!(\"d1\"); }") .file("foo/d2/Cargo.toml", &basic_bin_manifest("d2")) .file("foo/d2/src/main.rs", "fn main() { println!(\"d2\"); }") .file("d3/Cargo.toml", &basic_bin_manifest("d3")) .file("d3/src/main.rs", "fn main() { println!(\"d2\"); }") .build(); let cargo = || { let mut process_builder = p.cargo("run"); process_builder.cwd("foo"); process_builder }; cargo() .arg("-p") .arg("d1") .with_stdout_data(str![[r#" d1 "#]]) .run(); cargo() .arg("-p") .arg("d2") .arg("--bin") .arg("d2") .with_stdout_data(str![[r#" d2 "#]]) .run(); cargo() .with_stdout_data(str![[r#" foo "#]]) .run(); cargo() .arg("-p") .arg("d1") .arg("-p") .arg("d2") .with_status(1) .with_stderr_data(str![[r#" [ERROR] the argument '--package []' cannot be used multiple times ... "#]]) .run(); cargo() .arg("-p") .arg("d3") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package(s) `d3` not found in workspace `[ROOT]/foo/foo` "#]]) .run(); cargo() .arg("-p") .arg("d*") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `cargo run` does not support glob pattern `d*` on package selection "#]]) .run(); } #[cargo_test] fn explicit_bin_with_args() { let p = project() .file( "src/main.rs", r#" fn main() { assert_eq!(std::env::args().nth(1).unwrap(), "hello"); assert_eq!(std::env::args().nth(2).unwrap(), "world"); } "#, ) .build(); p.cargo("run --bin foo hello world").run(); } #[cargo_test] fn run_workspace() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file("a/Cargo.toml", &basic_bin_manifest("a")) .file("a/src/main.rs", r#"fn main() {println!("run-a");}"#) .file("b/Cargo.toml", &basic_bin_manifest("b")) .file("b/src/main.rs", r#"fn main() {println!("run-b");}"#) .build(); p.cargo("run") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `cargo run` could not determine which binary to run. Use the `--bin` option to specify a binary, or the `default-run` manifest key. available binaries: a, b "#]]) .run(); p.cargo("run --bin a") .with_stdout_data(str![[r#" run-a "#]]) .run(); } #[cargo_test] fn default_run_workspace() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.0.1" edition = "2015" default-run = "a" "#, ) .file("a/src/main.rs", r#"fn main() {println!("run-a");}"#) .file("b/Cargo.toml", &basic_bin_manifest("b")) .file("b/src/main.rs", r#"fn main() {println!("run-b");}"#) .build(); p.cargo("run") .with_stdout_data(str![[r#" run-a "#]]) .run(); } #[cargo_test] fn print_env_verbose() { let p = project() .file("Cargo.toml", &basic_manifest("a", "0.0.1")) .file("src/main.rs", r#"fn main() {println!("run-a");}"#) .build(); p.cargo("run -vv") .with_stderr_data(str![[r#" [COMPILING] a v0.0.1 ([ROOT]/foo) [RUNNING] `[..]CARGO_MANIFEST_DIR=[ROOT]/foo[..] rustc --crate-name a[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[..]CARGO_MANIFEST_DIR=[ROOT]/foo[..] target/debug/a[EXE]` "#]]) .run(); } #[cargo_test] #[cfg(target_os = "macos")] fn run_link_system_path_macos() { use cargo_test_support::paths; use std::fs; // Check that the default system library path is honored. // First, build a shared library that will be accessed from // DYLD_FALLBACK_LIBRARY_PATH. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [lib] crate-type = ["cdylib"] "#, ) .file( "src/lib.rs", "#[no_mangle] pub extern fn something_shared() {}", ) .build(); p.cargo("build").run(); // This is convoluted. Since this test can't modify things in /usr, // this needs to dance around to check that things work. // // The default DYLD_FALLBACK_LIBRARY_PATH is: // $(HOME)/lib:/usr/local/lib:/lib:/usr/lib // // This will make use of ~/lib in the path, but the default cc link // path is /usr/lib:/usr/local/lib. So first need to build in one // location, and then move it to ~/lib. // // 1. Build with rustc-link-search pointing to libfoo so the initial // binary can be linked. // 2. Move the library to ~/lib // 3. Run `cargo run` to make sure it can still find the library in // ~/lib. // // This should be equivalent to having the library in /usr/local/lib. let p2 = project() .at("bar") .file("Cargo.toml", &basic_bin_manifest("bar")) .file( "src/main.rs", r#" extern { fn something_shared(); } fn main() { unsafe { something_shared(); } } "#, ) .file( "build.rs", &format!( r#" fn main() {{ println!("cargo::rustc-link-lib=foo"); println!("cargo::rustc-link-search={}"); }} "#, p.target_debug_dir().display() ), ) .build(); p2.cargo("build").run(); p2.cargo("test").run(); let libdir = paths::home().join("lib"); fs::create_dir(&libdir).unwrap(); fs::rename( p.target_debug_dir().join("libfoo.dylib"), libdir.join("libfoo.dylib"), ) .unwrap(); p.root().rm_rf(); const VAR: &str = "DYLD_FALLBACK_LIBRARY_PATH"; // Reset DYLD_FALLBACK_LIBRARY_PATH so that we don't inherit anything that // was set by the cargo that invoked the test. p2.cargo("run").env_remove(VAR).run(); p2.cargo("test").env_remove(VAR).run(); // Ensure this still works when DYLD_FALLBACK_LIBRARY_PATH has // a value set. p2.cargo("run").env(VAR, &libdir).run(); p2.cargo("test").env(VAR, &libdir).run(); } #[cargo_test] fn run_binary_with_same_name_as_dependency() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [dependencies] foo = { path = "foo" } "#, ) .file( "src/main.rs", r#" fn main() {} "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [lib] name = "foo" path = "foo.rs" "#, ) .file("foo/foo.rs", "") .build(); p.cargo("run").run(); p.cargo("check -p foo@0.5.0").run(); p.cargo("run -p foo@0.5.0").run(); p.cargo("run -p foo@0.5").run(); p.cargo("run -p foo@0.4") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package(s) `foo@0.4` not found in workspace `[ROOT]/foo` "#]]) .run(); } cargo-0.86.0/tests/testsuite/rust_version.rs000064400000000000000000000733541046102023000173310ustar 00000000000000//! Tests for targets with `rust-version`. use cargo_test_support::prelude::*; use cargo_test_support::{cargo_process, project, registry::Package, str}; #[cargo_test] fn rust_version_satisfied() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] rust-version = "1.1.1" [[bin]] name = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check").run(); p.cargo("check --ignore-rust-version").run(); } #[cargo_test] fn rust_version_error() { project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] rust-version = "^1.43" [[bin]] name = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build() .cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] unexpected version requirement, expected a version like "1.32" --> Cargo.toml:7:28 | 7 | rust-version = "^1.43" | ^^^^^^^ | "#]]) .run(); } #[cargo_test] fn rust_version_older_than_edition() { project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] rust-version = "1.1" edition = "2018" [[bin]] name = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build() .cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: rust-version 1.1 is older than first version (1.31.0) required by the specified edition (2018) "#]]) .run(); } #[cargo_test] fn lint_self_incompatible_with_rust_version() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] rust-version = "1.9876.0" [[bin]] name = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] rustc [..] is not supported by the following package: foo@0.0.1 requires rustc 1.9876.0 "#]]) .run(); p.cargo("check --ignore-rust-version").run(); } #[cargo_test] fn lint_dep_incompatible_with_rust_version() { Package::new("too_new_parent", "0.0.1") .dep("too_new_child", "0.0.1") .rust_version("1.2345.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("too_new_child", "0.0.1") .rust_version("1.2345.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("rustc_compatible", "0.0.1") .rust_version("1.60.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" rust-version = "1.50" authors = [] [dependencies] too_new_parent = "0.0.1" rustc_compatible = "0.0.1" "#, ) .file("src/main.rs", "fn main(){}") .build(); p.cargo("generate-lockfile") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 3 packages to latest compatible versions [ADDING] too_new_child v0.0.1 (requires Rust 1.2345.0) [ADDING] too_new_parent v0.0.1 (requires Rust 1.2345.0) "#]]) .run(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] too_new_parent v0.0.1 (registry `dummy-registry`) [DOWNLOADED] too_new_child v0.0.1 (registry `dummy-registry`) [DOWNLOADED] rustc_compatible v0.0.1 (registry `dummy-registry`) [ERROR] rustc [..] is not supported by the following packages: too_new_child@0.0.1 requires rustc 1.2345.0 too_new_parent@0.0.1 requires rustc 1.2345.0 Either upgrade rustc or select compatible dependency versions with `cargo update @ --precise ` where `` is the latest version supporting rustc [..] "#]]) .run(); p.cargo("check --ignore-rust-version").run(); } #[cargo_test] fn resolve_with_rust_version() { Package::new("only-newer", "1.6.0") .rust_version("1.65.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("newer-and-older", "1.5.0") .rust_version("1.55.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("newer-and-older", "1.6.0") .rust_version("1.65.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] rust-version = "1.60.0" [dependencies] only-newer = "1.0.0" newer-and-older = "1.0.0" "#, ) .file("src/main.rs", "fn main(){}") .build(); p.cargo("generate-lockfile --ignore-rust-version") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions "#]]) .run(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) β”œβ”€β”€ newer-and-older v1.6.0 └── only-newer v1.6.0 "#]]) .run(); p.cargo("generate-lockfile") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest Rust 1.60.0 compatible versions [ADDING] newer-and-older v1.5.0 (available: v1.6.0, requires Rust 1.65.0) [ADDING] only-newer v1.6.0 (requires Rust 1.65.0) "#]]) .run(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) β”œβ”€β”€ newer-and-older v1.5.0 └── only-newer v1.6.0 "#]]) .run(); } #[cargo_test] fn resolve_with_rustc() { Package::new("only-newer", "1.6.0") .rust_version("1.2345") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("newer-and-older", "1.5.0") .rust_version("1.55.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("newer-and-older", "1.6.0") .rust_version("1.2345") .file("src/lib.rs", "fn other_stuff() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] rust-version = "1.60.0" [dependencies] only-newer = "1.0.0" newer-and-older = "1.0.0" "#, ) .file("src/main.rs", "fn main(){}") .build(); p.cargo("generate-lockfile --ignore-rust-version") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [ADDING] newer-and-older v1.6.0 (requires Rust 1.2345) [ADDING] only-newer v1.6.0 (requires Rust 1.2345) "#]]) .run(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) β”œβ”€β”€ newer-and-older v1.6.0 └── only-newer v1.6.0 "#]]) .run(); p.cargo("generate-lockfile") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest Rust 1.60.0 compatible versions [ADDING] newer-and-older v1.5.0 (available: v1.6.0, requires Rust 1.2345) [ADDING] only-newer v1.6.0 (requires Rust 1.2345) "#]]) .run(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) β”œβ”€β”€ newer-and-older v1.5.0 └── only-newer v1.6.0 "#]]) .run(); } #[cargo_test] fn resolve_with_backtracking() { Package::new("has-rust-version", "1.6.0") .rust_version("1.65.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("no-rust-version", "2.1.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("no-rust-version", "2.2.0") .file("src/lib.rs", "fn other_stuff() {}") .dep("has-rust-version", "1.6.0") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] rust-version = "1.60.0" [dependencies] no-rust-version = "2" "#, ) .file("src/main.rs", "fn main(){}") .build(); p.cargo("generate-lockfile --ignore-rust-version") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions "#]]) .run(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) └── no-rust-version v2.2.0 └── has-rust-version v1.6.0 "#]]) .run(); // Ideally we'd pick `has-rust-version` 1.6.0 which requires backtracking p.cargo("generate-lockfile") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest Rust 1.60.0 compatible versions [ADDING] has-rust-version v1.6.0 (requires Rust 1.65.0) "#]]) .run(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) └── no-rust-version v2.2.0 └── has-rust-version v1.6.0 "#]]) .run(); } #[cargo_test] fn resolve_with_multiple_rust_versions() { Package::new(&format!("shared-only-newer"), "1.65.0") .rust_version("1.65.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); for ver in ["1.45.0", "1.55.0", "1.65.0"] { Package::new(&format!("shared-newer-and-older"), ver) .rust_version(ver) .file("src/lib.rs", "fn other_stuff() {}") .publish(); } Package::new(&format!("lower-only-newer"), "1.65.0") .rust_version("1.65.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); for ver in ["1.45.0", "1.55.0"] { Package::new(&format!("lower-newer-and-older"), ver) .rust_version(ver) .file("src/lib.rs", "fn other_stuff() {}") .publish(); } Package::new(&format!("higher-only-newer"), "1.65.0") .rust_version("1.65.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); for ver in ["1.55.0", "1.65.0"] { Package::new(&format!("higher-newer-and-older"), ver) .rust_version(ver) .file("src/lib.rs", "fn other_stuff() {}") .publish(); } let p = project() .file( "Cargo.toml", r#" [workspace] members = ["lower"] [package] name = "higher" version = "0.0.1" edition = "2015" authors = [] rust-version = "1.60.0" [dependencies] higher-only-newer = "1" higher-newer-and-older = "1" shared-only-newer = "1" shared-newer-and-older = "1" "#, ) .file("src/main.rs", "fn main() {}") .file( "lower/Cargo.toml", r#" [package] name = "lower" version = "0.0.1" edition = "2015" authors = [] rust-version = "1.50.0" [dependencies] lower-only-newer = "1" lower-newer-and-older = "1" shared-only-newer = "1" shared-newer-and-older = "1" "#, ) .file("lower/src/main.rs", "fn main() {}") .build(); p.cargo("generate-lockfile --ignore-rust-version") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 6 packages to latest compatible versions "#]]) .run(); p.cargo("tree") .with_stdout_data(str![[r#" higher v0.0.1 ([ROOT]/foo) β”œβ”€β”€ higher-newer-and-older v1.65.0 β”œβ”€β”€ higher-only-newer v1.65.0 β”œβ”€β”€ shared-newer-and-older v1.65.0 └── shared-only-newer v1.65.0 "#]]) .run(); p.cargo("generate-lockfile") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 6 packages to latest Rust 1.50.0 compatible versions [ADDING] higher-newer-and-older v1.55.0 (available: v1.65.0, requires Rust 1.65.0) [ADDING] higher-only-newer v1.65.0 (requires Rust 1.65.0) [ADDING] lower-newer-and-older v1.45.0 (available: v1.55.0, requires Rust 1.55.0) [ADDING] lower-only-newer v1.65.0 (requires Rust 1.65.0) [ADDING] shared-newer-and-older v1.45.0 (available: v1.65.0, requires Rust 1.65.0) [ADDING] shared-only-newer v1.65.0 (requires Rust 1.65.0) "#]]) .run(); p.cargo("tree") .with_stdout_data(str![[r#" higher v0.0.1 ([ROOT]/foo) β”œβ”€β”€ higher-newer-and-older v1.55.0 β”œβ”€β”€ higher-only-newer v1.65.0 β”œβ”€β”€ shared-newer-and-older v1.45.0 └── shared-only-newer v1.65.0 "#]]) .run(); } #[cargo_test] fn resolve_edition2024() { Package::new("only-newer", "1.6.0") .rust_version("1.90.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("newer-and-older", "1.5.0") .rust_version("1.80.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("newer-and-older", "1.6.0") .rust_version("1.90.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2024" authors = [] rust-version = "1.85.0" [dependencies] only-newer = "1.0.0" newer-and-older = "1.0.0" "#, ) .file("src/main.rs", "fn main(){}") .build(); // Edition2024 should resolve for MSRV p.cargo("generate-lockfile") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest Rust 1.85.0 compatible versions [ADDING] newer-and-older v1.5.0 (available: v1.6.0, requires Rust 1.90.0) [ADDING] only-newer v1.6.0 (requires Rust 1.90.0) "#]]) .run(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) β”œβ”€β”€ newer-and-older v1.5.0 └── only-newer v1.6.0 "#]]) .run(); // `--ignore-rust-version` has precedence over Edition2024 p.cargo("generate-lockfile --ignore-rust-version") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [ADDING] newer-and-older v1.6.0 (requires Rust 1.90.0) [ADDING] only-newer v1.6.0 (requires Rust 1.90.0) "#]]) .run(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) β”œβ”€β”€ newer-and-older v1.6.0 └── only-newer v1.6.0 "#]]) .run(); // config has precedence over Edition2024 p.cargo("generate-lockfile") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "allow") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [ADDING] newer-and-older v1.6.0 (requires Rust 1.90.0) [ADDING] only-newer v1.6.0 (requires Rust 1.90.0) "#]]) .run(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) β”œβ”€β”€ newer-and-older v1.6.0 └── only-newer v1.6.0 "#]]) .run(); } #[cargo_test] fn resolve_v3() { Package::new("only-newer", "1.6.0") .rust_version("1.90.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("newer-and-older", "1.5.0") .rust_version("1.80.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("newer-and-older", "1.6.0") .rust_version("1.90.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] rust-version = "1.85.0" resolver = "3" [dependencies] only-newer = "1.0.0" newer-and-older = "1.0.0" "#, ) .file("src/main.rs", "fn main(){}") .build(); // v3 should resolve for MSRV p.cargo("generate-lockfile") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest Rust 1.85.0 compatible versions [ADDING] newer-and-older v1.5.0 (available: v1.6.0, requires Rust 1.90.0) [ADDING] only-newer v1.6.0 (requires Rust 1.90.0) "#]]) .run(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) β”œβ”€β”€ newer-and-older v1.5.0 └── only-newer v1.6.0 "#]]) .run(); // `--ignore-rust-version` has precedence over v3 p.cargo("generate-lockfile --ignore-rust-version") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [ADDING] newer-and-older v1.6.0 (requires Rust 1.90.0) [ADDING] only-newer v1.6.0 (requires Rust 1.90.0) "#]]) .run(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) β”œβ”€β”€ newer-and-older v1.6.0 └── only-newer v1.6.0 "#]]) .run(); // config has precedence over v3 p.cargo("generate-lockfile") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "allow") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [ADDING] newer-and-older v1.6.0 (requires Rust 1.90.0) [ADDING] only-newer v1.6.0 (requires Rust 1.90.0) "#]]) .run(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) β”œβ”€β”€ newer-and-older v1.6.0 └── only-newer v1.6.0 "#]]) .run(); } #[cargo_test] fn update_msrv_resolve() { Package::new("bar", "1.5.0") .rust_version("1.55.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("bar", "1.6.0") .rust_version("1.65.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] rust-version = "1.60.0" [dependencies] bar = "1.0.0" "#, ) .file("src/main.rs", "fn main(){}") .build(); p.cargo("update") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest Rust 1.60.0 compatible version [ADDING] bar v1.5.0 (available: v1.6.0, requires Rust 1.65.0) "#]]) .run(); p.cargo("update --ignore-rust-version") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] bar v1.5.0 -> v1.6.0 "#]]) .run(); } #[cargo_test] fn update_precise_overrides_msrv_resolver() { Package::new("bar", "1.5.0") .rust_version("1.55.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("bar", "1.6.0") .rust_version("1.65.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] rust-version = "1.60.0" [dependencies] bar = "1.0.0" "#, ) .file("src/main.rs", "fn main(){}") .build(); p.cargo("update") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest Rust 1.60.0 compatible version [ADDING] bar v1.5.0 (available: v1.6.0, requires Rust 1.65.0) "#]]) .run(); p.cargo("update --precise 1.6.0 bar") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] bar v1.5.0 -> v1.6.0 (requires Rust 1.65.0) "#]]) .run(); } #[cargo_test] fn check_msrv_resolve() { Package::new("only-newer", "1.6.0") .rust_version("1.65.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("newer-and-older", "1.5.0") .rust_version("1.55.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("newer-and-older", "1.6.0") .rust_version("1.65.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] rust-version = "1.60.0" [dependencies] only-newer = "1.0.0" newer-and-older = "1.0.0" "#, ) .file("src/main.rs", "fn main(){}") .build(); p.cargo("check --ignore-rust-version") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] only-newer v1.6.0 (registry `dummy-registry`) [DOWNLOADED] newer-and-older v1.6.0 (registry `dummy-registry`) [CHECKING] only-newer v1.6.0 [CHECKING] newer-and-older v1.6.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) β”œβ”€β”€ newer-and-older v1.6.0 └── only-newer v1.6.0 "#]]) .run(); std::fs::remove_file(p.root().join("Cargo.lock")).unwrap(); p.cargo("check") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest Rust 1.60.0 compatible versions [ADDING] newer-and-older v1.5.0 (available: v1.6.0, requires Rust 1.65.0) [ADDING] only-newer v1.6.0 (requires Rust 1.65.0) [DOWNLOADING] crates ... [DOWNLOADED] newer-and-older v1.5.0 (registry `dummy-registry`) [CHECKING] newer-and-older v1.5.0 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.0.1 ([ROOT]/foo) β”œβ”€β”€ newer-and-older v1.5.0 └── only-newer v1.6.0 "#]]) .run(); } #[cargo_test] fn cargo_install_ignores_msrv_config() { Package::new("dep", "1.0.0") .rust_version("1.50") .file("src/lib.rs", "fn hello() {}") .publish(); Package::new("dep", "1.1.0") .rust_version("1.70") .file("src/lib.rs", "fn hello() {}") .publish(); Package::new("foo", "0.0.1") .rust_version("1.60") .file("src/main.rs", "fn main() {}") .dep("dep", "1") .publish(); cargo_process("install foo") .env( "CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback", ) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.1 (registry `dummy-registry`) [INSTALLING] foo v0.0.1 [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] dep v1.1.0 (registry `dummy-registry`) [COMPILING] dep v1.1.0 [COMPILING] foo v0.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); } #[cargo_test] fn cargo_install_ignores_resolver_v3_msrv_change() { Package::new("dep", "1.0.0") .rust_version("1.50") .file("src/lib.rs", "fn hello() {}") .publish(); Package::new("dep", "1.1.0") .rust_version("1.70") .file("src/lib.rs", "fn hello() {}") .publish(); Package::new("foo", "0.0.1") .rust_version("1.60") .resolver("3") .file("src/main.rs", "fn main() {}") .dep("dep", "1") .publish(); cargo_process("install foo") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] foo v0.0.1 (registry `dummy-registry`) [INSTALLING] foo v0.0.1 [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] dep v1.1.0 (registry `dummy-registry`) [COMPILING] dep v1.1.0 [COMPILING] foo v0.0.1 [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE] [INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`) [WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries "#]]) .run(); } #[cargo_test] fn report_rust_versions() { Package::new("dep-only-low-compatible", "1.55.0") .rust_version("1.55.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("dep-only-low-incompatible", "1.75.0") .rust_version("1.75.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("dep-only-high-compatible", "1.65.0") .rust_version("1.65.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("dep-only-high-incompatible", "1.75.0") .rust_version("1.75.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("dep-only-unset-unset", "1.0.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("dep-only-unset-compatible", "1.75.0") .rust_version("1.75.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("dep-only-unset-incompatible", "1.2345.0") .rust_version("1.2345.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("dep-shared-compatible", "1.55.0") .rust_version("1.55.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); Package::new("dep-shared-incompatible", "1.75.0") .rust_version("1.75.0") .file("src/lib.rs", "fn other_stuff() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["high", "low", "unset"] "#, ) .file( "high/Cargo.toml", r#" [package] name = "high" edition = "2015" rust-version = "1.70.0" [dependencies] dep-only-high-compatible = "1" dep-only-high-incompatible = "1" dep-shared-compatible = "1" dep-shared-incompatible = "1" "#, ) .file("high/src/main.rs", "fn main(){}") .file( "low/Cargo.toml", r#" [package] name = "low" edition = "2015" rust-version = "1.60.0" [dependencies] dep-only-low-compatible = "1" dep-only-low-incompatible = "1" dep-shared-compatible = "1" dep-shared-incompatible = "1" "#, ) .file("low/src/main.rs", "fn main(){}") .file( "unset/Cargo.toml", r#" [package] name = "unset" edition = "2015" [dependencies] dep-only-unset-unset = "1" dep-only-unset-compatible = "1" dep-only-unset-incompatible = "1" dep-shared-compatible = "1" dep-shared-incompatible = "1" "#, ) .file("unset/src/main.rs", "fn main(){}") .build(); p.cargo("update") .env("CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS", "fallback") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 9 packages to latest Rust 1.60.0 compatible versions [ADDING] dep-only-high-incompatible v1.75.0 (requires Rust 1.75.0) [ADDING] dep-only-low-incompatible v1.75.0 (requires Rust 1.75.0) [ADDING] dep-only-unset-incompatible v1.2345.0 (requires Rust 1.2345.0) [ADDING] dep-shared-incompatible v1.75.0 (requires Rust 1.75.0) "#]]) .run(); } cargo-0.86.0/tests/testsuite/rustc.rs000064400000000000000000000562701046102023000157250ustar 00000000000000//! Tests for the `cargo rustc` command. use cargo_test_support::prelude::*; use cargo_test_support::{basic_bin_manifest, basic_lib_manifest, basic_manifest, project, str}; #[cargo_test] fn build_lib_for_foo() { let p = project() .file("src/main.rs", "fn main() {}") .file("src/lib.rs", r#" "#) .build(); p.cargo("rustc --lib -v").with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C debuginfo=2 [..]-C metadata=[..] [..]--out-dir [ROOT]/foo/target/debug/deps -L dependency=[ROOT]/foo/target/debug/deps` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn lib() { let p = project() .file("src/main.rs", "fn main() {}") .file("src/lib.rs", r#" "#) .build(); p.cargo("rustc --lib -v -- -C debug-assertions=off") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C debuginfo=2 [..]-C metadata=[..] [..]--out-dir [ROOT]/foo/target/debug/deps -L dependency=[ROOT]/foo/target/debug/deps[..]-C debug-assertions=off[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_main_and_allow_unstable_options() { let p = project() .file("src/main.rs", "fn main() {}") .file("src/lib.rs", r#" "#) .build(); p.cargo("rustc -v --bin foo -- -C debug-assertions") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C debuginfo=2 [..]-C metadata=[..] --out-dir [ROOT]/foo/target/debug/deps -L dependency=[ROOT]/foo/target/debug/deps` [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]link[..]-C debuginfo=2 [..]-C metadata=[..] --out-dir [ROOT]/foo/target/debug/deps -L dependency=[ROOT]/foo/target/debug/deps --extern foo=[ROOT]/foo/target/debug/deps/libfoo-[HASH].rlib[..]-C debug-assertions[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn fails_when_trying_to_build_main_and_lib_with_args() { let p = project() .file("src/main.rs", "fn main() {}") .file("src/lib.rs", r#" "#) .build(); p.cargo("rustc -v -- -C debug-assertions") .with_status(101) .with_stderr_data(str![[r#" [ERROR] extra arguments to `rustc` can only be passed to one target, consider filtering the package by passing, e.g., `--lib` or `--bin NAME` to specify a single target "#]]) .run(); } #[cargo_test] fn build_with_args_to_one_of_multiple_binaries() { let p = project() .file("src/bin/foo.rs", "fn main() {}") .file("src/bin/bar.rs", "fn main() {}") .file("src/bin/baz.rs", "fn main() {}") .file("src/lib.rs", r#" "#) .build(); p.cargo("rustc -v --bin bar -- -C debug-assertions") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C debuginfo=2 [..]-C metadata=[..] --out-dir [..]` [RUNNING] `rustc --crate-name bar --edition=2015 src/bin/bar.rs [..]--crate-type bin --emit=[..]link[..]-C debuginfo=2 [..]-C debug-assertions[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn fails_with_args_to_all_binaries() { let p = project() .file("src/bin/foo.rs", "fn main() {}") .file("src/bin/bar.rs", "fn main() {}") .file("src/bin/baz.rs", "fn main() {}") .file("src/lib.rs", r#" "#) .build(); p.cargo("rustc -v -- -C debug-assertions") .with_status(101) .with_stderr_data(str![[r#" [ERROR] extra arguments to `rustc` can only be passed to one target, consider filtering the package by passing, e.g., `--lib` or `--bin NAME` to specify a single target "#]]) .run(); } #[cargo_test] fn fails_with_crate_type_to_multi_binaries() { let p = project() .file("src/bin/foo.rs", "fn main() {}") .file("src/bin/bar.rs", "fn main() {}") .file("src/bin/baz.rs", "fn main() {}") .file("src/lib.rs", r#" "#) .build(); p.cargo("rustc --crate-type lib") .with_status(101) .with_stderr_data(str![[r#" [ERROR] crate types to rustc can only be passed to one target, consider filtering the package by passing, e.g., `--lib` or `--example` to specify a single target "#]]) .run(); } #[cargo_test] fn fails_with_crate_type_to_multi_examples() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[example]] name = "ex1" crate-type = ["rlib"] [[example]] name = "ex2" crate-type = ["rlib"] "#, ) .file("src/lib.rs", "") .file("examples/ex1.rs", "") .file("examples/ex2.rs", "") .build(); p.cargo("rustc -v --example ex1 --example ex2 --crate-type lib,cdylib") .with_status(101) .with_stderr_data(str![[r#" [ERROR] crate types to rustc can only be passed to one target, consider filtering the package by passing, e.g., `--lib` or `--example` to specify a single target "#]]) .run(); } #[cargo_test] fn fails_with_crate_type_to_binary() { let p = project().file("src/bin/foo.rs", "fn main() {}").build(); p.cargo("rustc --crate-type lib") .with_status(101) .with_stderr_data(str![[r#" [ERROR] crate types can only be specified for libraries and example libraries. Binaries, tests, and benchmarks are always the `bin` crate type "#]]) .run(); } #[cargo_test] fn build_with_crate_type_for_foo() { let p = project().file("src/lib.rs", "").build(); p.cargo("rustc -v --crate-type cdylib") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type cdylib [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_with_crate_type_for_foo_with_deps() { let p = project() .file( "src/lib.rs", r#" extern crate a; pub fn foo() { a::hello(); } "#, ) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a" } "#, ) .file("a/Cargo.toml", &basic_manifest("a", "0.1.0")) .file("a/src/lib.rs", "pub fn hello() {}") .build(); p.cargo("rustc -v --crate-type cdylib") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] a v0.1.0 ([ROOT]/foo/a) [RUNNING] `rustc --crate-name a --edition=2015 a/src/lib.rs [..]--crate-type lib [..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type cdylib [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_with_crate_types_for_foo() { let p = project().file("src/lib.rs", "").build(); p.cargo("rustc -v --crate-type lib,cdylib") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --crate-type cdylib [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_with_crate_type_to_example() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[example]] name = "ex" crate-type = ["rlib"] "#, ) .file("src/lib.rs", "") .file("examples/ex.rs", "") .build(); p.cargo("rustc -v --example ex --crate-type cdylib") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib [..]` [RUNNING] `rustc --crate-name ex --edition=2015 examples/ex.rs [..]--crate-type cdylib [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_with_crate_types_to_example() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[example]] name = "ex" crate-type = ["rlib"] "#, ) .file("src/lib.rs", "") .file("examples/ex.rs", "") .build(); p.cargo("rustc -v --example ex --crate-type lib,cdylib") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib [..]` [RUNNING] `rustc --crate-name ex --edition=2015 examples/ex.rs [..]--crate-type lib --crate-type cdylib [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_with_crate_types_to_one_of_multi_examples() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[example]] name = "ex1" crate-type = ["rlib"] [[example]] name = "ex2" crate-type = ["rlib"] "#, ) .file("src/lib.rs", "") .file("examples/ex1.rs", "") .file("examples/ex2.rs", "") .build(); p.cargo("rustc -v --example ex1 --crate-type lib,cdylib") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib [..]` [RUNNING] `rustc --crate-name ex1 --edition=2015 examples/ex1.rs [..]--crate-type lib --crate-type cdylib [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_with_args_to_one_of_multiple_tests() { let p = project() .file("tests/foo.rs", r#" "#) .file("tests/bar.rs", r#" "#) .file("tests/baz.rs", r#" "#) .file("src/lib.rs", r#" "#) .build(); p.cargo("rustc -v --test bar -- -C debug-assertions") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C debuginfo=2 [..]-C metadata=[..] --out-dir [..]` [RUNNING] `rustc --crate-name bar --edition=2015 tests/bar.rs [..]--emit=[..]link[..]-C debuginfo=2 [..]--test[..]-C debug-assertions[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_foo_with_bar_dependency() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" "#, ) .file("src/main.rs", "extern crate bar; fn main() { bar::baz() }") .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("rustc -v -- -C debug-assertions") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.1.0 ([ROOT]/bar) [RUNNING] `rustc --crate-name bar [..] -C debuginfo=2[..]` [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] -C debuginfo=2 [..]-C debug-assertions[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_only_bar_dependency() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" "#, ) .file("src/main.rs", "extern crate bar; fn main() { bar::baz() }") .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("rustc -v -p bar -- -C debug-assertions") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.1.0 ([ROOT]/bar) [RUNNING] `rustc --crate-name bar [..]--crate-type lib [..] -C debug-assertions[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn targets_selected_default() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("rustc -v") // bin .with_stderr_contains( "[RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin \ --emit=[..]link[..]", ) // bench .with_stderr_does_not_contain( "[RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--emit=[..]link \ -C opt-level=3 --test [..]", ) // unit test .with_stderr_does_not_contain( "[RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--emit=[..]link \ -C debuginfo=2 [..]--test [..]", ) .run(); } #[cargo_test] fn targets_selected_all() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("rustc -v --all-targets") // bin and unit test .with_stderr_data( str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--crate-type bin --emit=[..]link[..]` [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]--emit[..]link[..] -C debuginfo=2 [..]--test [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]].unordered() ) .run(); } #[cargo_test] fn fail_with_multiple_packages() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" [dependencies.baz] path = "../baz" "#, ) .file("src/main.rs", "fn main() {}") .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file( "src/main.rs", r#" fn main() { if cfg!(flag = "1") { println!("Yeah from bar!"); } } "#, ) .build(); let _baz = project() .at("baz") .file("Cargo.toml", &basic_manifest("baz", "0.1.0")) .file( "src/main.rs", r#" fn main() { if cfg!(flag = "1") { println!("Yeah from baz!"); } } "#, ) .build(); foo.cargo("rustc -v -p bar -p baz") .with_status(1) .with_stderr_data(str![[r#" [ERROR] the argument '--package []' cannot be used multiple times ... "#]]) .run(); } #[cargo_test] fn fail_with_glob() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() { break_the_build(); }") .build(); p.cargo("rustc -p '*z'") .with_status(101) .with_stderr_data(str![[r#" [ERROR] Glob patterns on package selection are not supported. "#]]) .run(); } #[cargo_test] fn rustc_with_other_profile() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dev-dependencies] a = { path = "a" } "#, ) .file( "src/main.rs", r#" #[cfg(test)] extern crate a; #[test] fn foo() {} "#, ) .file("a/Cargo.toml", &basic_manifest("a", "0.1.0")) .file("a/src/lib.rs", "") .build(); p.cargo("rustc --profile test").run(); } #[cargo_test] fn rustc_fingerprint() { // Verify that the fingerprint includes the rustc args. let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .build(); p.cargo("rustc -v -- -C debug-assertions") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]-C debug-assertions[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("rustc -v -- -C debug-assertions") .with_stderr_data(str![[r#" [FRESH] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("rustc -v") .with_stderr_does_not_contain("-C debug-assertions") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("rustc -v") .with_stderr_data(str![[r#" [FRESH] foo v0.5.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn rustc_test_with_implicit_bin() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" #[cfg(foo)] fn f() { compile_fail!("Foo shouldn't be set."); } fn main() {} "#, ) .file( "tests/test1.rs", r#" #[cfg(not(foo))] fn f() { compile_fail!("Foo should be set."); } "#, ) .build(); p.cargo("rustc --test test1 -v -- --cfg foo") .with_stderr_data( str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name test1 --edition=2015 tests/test1.rs [..] --cfg foo[..]` [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]` ... [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn rustc_with_print_cfg_single_target() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", r#"fn main() {} "#) .build(); p.cargo("rustc -Z unstable-options --target x86_64-pc-windows-msvc --print cfg") .masquerade_as_nightly_cargo(&["print"]) .with_stdout_data( str![[r#" debug_assertions target_arch="x86_64" target_endian="little" target_env="msvc" target_family="windows" target_os="windows" target_pointer_width="64" target_vendor="pc" windows ... "#]] .unordered(), ) .run(); } #[cargo_test] fn rustc_with_print_cfg_multiple_targets() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", r#"fn main() {} "#) .build(); p.cargo("rustc -Z unstable-options --target x86_64-pc-windows-msvc --target i686-unknown-linux-gnu --print cfg") .masquerade_as_nightly_cargo(&["print"]) .with_stdout_data(str![[r#" debug_assertions target_arch="x86" target_endian="little" target_env="gnu" target_family="unix" target_os="linux" target_pointer_width="32" target_vendor="unknown" unix debug_assertions target_arch="x86_64" target_endian="little" target_env="msvc" target_family="windows" target_os="windows" target_pointer_width="64" target_vendor="pc" windows ... "#]].unordered()) .run(); } #[cargo_test] fn rustc_with_print_cfg_rustflags_env_var() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", r#"fn main() {} "#) .build(); p.cargo("rustc -Z unstable-options --target x86_64-pc-windows-msvc --print cfg") .masquerade_as_nightly_cargo(&["print"]) .env("RUSTFLAGS", "-C target-feature=+crt-static") .with_stdout_data( str![[r#" debug_assertions target_arch="x86_64" target_endian="little" target_env="msvc" target_family="windows" target_feature="crt-static" target_os="windows" target_pointer_width="64" target_vendor="pc" windows ... "#]] .unordered(), ) .run(); } #[cargo_test] fn rustc_with_print_cfg_config_toml() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( ".cargo/config.toml", r#" [target.x86_64-pc-windows-msvc] rustflags = ["-C", "target-feature=+crt-static"] "#, ) .file("src/main.rs", r#"fn main() {} "#) .build(); p.cargo("rustc -Z unstable-options --target x86_64-pc-windows-msvc --print cfg") .masquerade_as_nightly_cargo(&["print"]) .env("RUSTFLAGS", "-C target-feature=+crt-static") .with_stdout_data( str![[r#" debug_assertions target_arch="x86_64" target_endian="little" target_env="msvc" target_family="windows" target_feature="crt-static" target_os="windows" target_pointer_width="64" target_vendor="pc" windows ... "#]] .unordered(), ) .run(); } #[cargo_test] fn precedence() { // Ensure that the precedence of cargo-rustc is only lower than RUSTFLAGS, // but higher than most flags set by cargo. // // See rust-lang/cargo#14346 let p = project() .file( "Cargo.toml", r#" [package] name = "foo" edition = "2021" [lints.rust] unexpected_cfgs = "allow" "#, ) .file("src/lib.rs", "") .build(); p.cargo("rustc --release -v -- --cfg cargo_rustc -C strip=symbols") .env("RUSTFLAGS", "--cfg from_rustflags") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.0 ([ROOT]/foo) [RUNNING] `rustc [..]-C strip=debuginfo [..]--cfg cargo_rustc -C strip=symbols --cfg from_rustflags` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/rustc_info_cache.rs000064400000000000000000000147201046102023000200550ustar 00000000000000//! Tests for the cache file for the rustc version info. use std::env; use cargo_test_support::basic_bin_manifest; use cargo_test_support::prelude::*; use cargo_test_support::{basic_manifest, project}; const MISS: &str = "[..] rustc info cache miss[..]"; const HIT: &str = "[..]rustc info cache hit[..]"; const UPDATE: &str = "[..]updated rustc info cache[..]"; #[cargo_test] fn rustc_info_cache() { let p = project() .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); p.cargo("build") .env("CARGO_LOG", "cargo::util::rustc=debug") .with_stderr_contains("[..]failed to read rustc info cache[..]") .with_stderr_contains(MISS) .with_stderr_does_not_contain(HIT) .with_stderr_contains(UPDATE) .run(); p.cargo("build") .env("CARGO_LOG", "cargo::util::rustc=debug") .with_stderr_contains("[..]reusing existing rustc info cache[..]") .with_stderr_contains(HIT) .with_stderr_does_not_contain(MISS) .with_stderr_does_not_contain(UPDATE) .run(); p.cargo("build") .env("CARGO_LOG", "cargo::util::rustc=debug") .env("CARGO_CACHE_RUSTC_INFO", "0") .with_stderr_contains("[..]rustc info cache disabled[..]") .with_stderr_does_not_contain(UPDATE) .run(); let other_rustc = { let p = project() .at("compiler") .file("Cargo.toml", &basic_manifest("compiler", "0.1.0")) .file( "src/main.rs", r#" use std::process::Command; use std::env; fn main() { let mut cmd = Command::new("rustc"); for arg in env::args_os().skip(1) { cmd.arg(arg); } std::process::exit(cmd.status().unwrap().code().unwrap()); } "#, ) .build(); p.cargo("build").run(); p.root() .join("target/debug/compiler") .with_extension(env::consts::EXE_EXTENSION) }; p.cargo("build") .env("CARGO_LOG", "cargo::util::rustc=debug") .env("RUSTC", other_rustc.display().to_string()) .with_stderr_contains("[..]different compiler, creating new rustc info cache[..]") .with_stderr_contains(MISS) .with_stderr_does_not_contain(HIT) .with_stderr_contains(UPDATE) .run(); p.cargo("build") .env("CARGO_LOG", "cargo::util::rustc=debug") .env("RUSTC", other_rustc.display().to_string()) .with_stderr_contains("[..]reusing existing rustc info cache[..]") .with_stderr_contains(HIT) .with_stderr_does_not_contain(MISS) .with_stderr_does_not_contain(UPDATE) .run(); other_rustc.move_into_the_future(); p.cargo("build") .env("CARGO_LOG", "cargo::util::rustc=debug") .env("RUSTC", other_rustc.display().to_string()) .with_stderr_contains("[..]different compiler, creating new rustc info cache[..]") .with_stderr_contains(MISS) .with_stderr_does_not_contain(HIT) .with_stderr_contains(UPDATE) .run(); p.cargo("build") .env("CARGO_LOG", "cargo::util::rustc=debug") .env("RUSTC", other_rustc.display().to_string()) .with_stderr_contains("[..]reusing existing rustc info cache[..]") .with_stderr_contains(HIT) .with_stderr_does_not_contain(MISS) .with_stderr_does_not_contain(UPDATE) .run(); } #[cargo_test] fn rustc_info_cache_with_wrappers() { let wrapper_project = project() .at("wrapper") .file("Cargo.toml", &basic_bin_manifest("wrapper")) .file("src/main.rs", r#"fn main() { }"#) .build(); let wrapper = wrapper_project.bin("wrapper"); let p = project() .file( "Cargo.toml", r#" [package] name = "test" version = "0.0.0" authors = [] [workspace] "#, ) .file("src/main.rs", r#"fn main() { println!("hello"); }"#) .build(); for &wrapper_env in ["RUSTC_WRAPPER", "RUSTC_WORKSPACE_WRAPPER"].iter() { p.cargo("clean").with_status(0).run(); wrapper_project.change_file( "src/main.rs", r#" fn main() { let mut args = std::env::args_os(); let _me = args.next().unwrap(); let rustc = args.next().unwrap(); let status = std::process::Command::new(rustc).args(args).status().unwrap(); std::process::exit(if status.success() { 0 } else { 1 }) } "#, ); wrapper_project.cargo("build").with_status(0).run(); p.cargo("build") .env("CARGO_LOG", "cargo::util::rustc=debug") .env(wrapper_env, &wrapper) .with_stderr_contains("[..]failed to read rustc info cache[..]") .with_stderr_contains(MISS) .with_stderr_contains(UPDATE) .with_stderr_does_not_contain(HIT) .with_status(0) .run(); p.cargo("build") .env("CARGO_LOG", "cargo::util::rustc=debug") .env(wrapper_env, &wrapper) .with_stderr_contains("[..]reusing existing rustc info cache[..]") .with_stderr_contains(HIT) .with_stderr_does_not_contain(UPDATE) .with_stderr_does_not_contain(MISS) .with_status(0) .run(); wrapper_project.change_file("src/main.rs", r#"fn main() { panic!() }"#); wrapper_project.cargo("build").with_status(0).run(); p.cargo("build") .env("CARGO_LOG", "cargo::util::rustc=debug") .env(wrapper_env, &wrapper) .with_stderr_contains("[..]different compiler, creating new rustc info cache[..]") .with_stderr_contains(MISS) .with_stderr_contains(UPDATE) .with_stderr_does_not_contain(HIT) .with_status(101) .run(); p.cargo("build") .env("CARGO_LOG", "cargo::util::rustc=debug") .env(wrapper_env, &wrapper) .with_stderr_contains("[..]reusing existing rustc info cache[..]") .with_stderr_contains(HIT) .with_stderr_does_not_contain(UPDATE) .with_stderr_does_not_contain(MISS) .with_status(101) .run(); } } cargo-0.86.0/tests/testsuite/rustdoc.rs000064400000000000000000000222651046102023000162450ustar 00000000000000//! Tests for the `cargo rustdoc` command. use cargo_test_support::prelude::*; use cargo_test_support::str; use cargo_test_support::{basic_manifest, cross_compile, project}; #[cargo_test] fn rustdoc_simple() { let p = project().file("src/lib.rs", "").build(); p.cargo("rustdoc -v") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustdoc [..] --crate-name foo src/lib.rs -o [ROOT]/foo/target/doc [..] -L dependency=[ROOT]/foo/target/debug/deps [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); } #[cargo_test] fn rustdoc_simple_html() { let p = project().file("src/lib.rs", "").build(); p.cargo("rustdoc --output-format html --open -v") .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `--output-format` flag is unstable, and only available on the nightly channel of Cargo, but this is the `stable` channel See https://doc.rust-lang.org/book/[..].html for more information about Rust release channels. See https://github.com/rust-lang/cargo/issues/12103 for more information about the `--output-format` flag. "#]]) .run(); } #[cargo_test(nightly, reason = "--output-format is unstable")] fn rustdoc_simple_json() { let p = project().file("src/lib.rs", "").build(); p.cargo("rustdoc -Z unstable-options --output-format json -v") .masquerade_as_nightly_cargo(&["rustdoc-output-format"]) .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustdoc [..] --crate-name foo [..]-o [ROOT]/foo/target/doc [..] --output-format=json[..] [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo.json "#]]) .run(); assert!(p.root().join("target/doc/foo.json").is_file()); } #[cargo_test] fn rustdoc_invalid_output_format() { let p = project().file("src/lib.rs", "").build(); p.cargo("rustdoc -Z unstable-options --output-format pdf -v") .masquerade_as_nightly_cargo(&["rustdoc-output-format"]) .with_status(1) .with_stderr_data(str![[r#" [ERROR] invalid value 'pdf' for '--output-format ' [possible values: html, json] For more information, try '--help'. "#]]) .run(); } #[cargo_test] fn rustdoc_json_stable() { let p = project().file("src/lib.rs", "").build(); p.cargo("rustdoc -Z unstable-options --output-format json -v") .with_status(101) .with_stderr_data( str![[r#" [ERROR] the `-Z` flag is only accepted on the nightly channel of Cargo, but this is the `stable` channel See https://doc.rust-lang.org/book/[..].html for more information about Rust release channels. "#]] ) .run(); } #[cargo_test] fn rustdoc_json_without_unstable_options() { let p = project().file("src/lib.rs", "").build(); p.cargo("rustdoc --output-format json -v") .masquerade_as_nightly_cargo(&["rustdoc-output-format"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `--output-format` flag is unstable, pass `-Z unstable-options` to enable it See https://github.com/rust-lang/cargo/issues/12103 for more information about the `--output-format` flag. "#]]) .run(); } #[cargo_test] fn rustdoc_args() { let p = project().file("src/lib.rs", "").build(); p.cargo("rustdoc -v -- --cfg=foo") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustdoc [..] --crate-name foo src/lib.rs -o [ROOT]/foo/target/doc [..]-C metadata=[..] -L dependency=[ROOT]/foo/target/debug/deps [..]--cfg=foo[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); } #[cargo_test] fn rustdoc_binary_args_passed() { let p = project().file("src/main.rs", "").build(); p.cargo("rustdoc -v") .arg("--") .arg("--markdown-no-toc") .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..] --markdown-no-toc[..]` ... "#]]) .run(); } #[cargo_test] fn rustdoc_foo_with_bar_dependency() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" "#, ) .file("src/lib.rs", "extern crate bar; pub fn foo() {}") .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("rustdoc -v -- --cfg=foo") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [CHECKING] bar v0.0.1 ([ROOT]/bar) [RUNNING] `rustc [..] [ROOT]/bar/src/lib.rs [..]` [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustdoc [..] --crate-name foo src/lib.rs -o [ROOT]/foo/target/doc [..]-C metadata=[..] -L dependency=[ROOT]/foo/target/debug/deps --extern [..]--cfg=foo[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); } #[cargo_test] fn rustdoc_only_bar_dependency() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" "#, ) .file("src/main.rs", "extern crate bar; fn main() { bar::baz() }") .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("rustdoc -v -p bar -- --cfg=foo") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [DOCUMENTING] bar v0.0.1 ([ROOT]/bar) [RUNNING] `rustdoc [..] --crate-name bar [ROOT]/bar/src/lib.rs -o [ROOT]/foo/target/doc [..]-C metadata=[..] -L dependency=[ROOT]/foo/target/debug/deps [..]--cfg=foo[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/bar/index.html "#]]) .run(); } #[cargo_test] fn rustdoc_same_name_documents_lib() { let p = project() .file("src/main.rs", "fn main() {}") .file("src/lib.rs", r#" "#) .build(); p.cargo("rustdoc -v -- --cfg=foo") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustdoc [..] --crate-name foo src/lib.rs -o [ROOT]/foo/target/doc [..]-C metadata=[..] -L dependency=[ROOT]/foo/target/debug/deps [..]--cfg=foo[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); } #[cargo_test] fn features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] quux = [] "#, ) .file("src/lib.rs", "") .build(); p.cargo("rustdoc --verbose --features quux") .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..]feature=[..]quux[..]` ... "#]]) .run(); } #[cargo_test] fn proc_macro_crate_type() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] proc-macro = true "#, ) .file("src/lib.rs", "") .build(); p.cargo("rustdoc --verbose") .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc --edition=2015 --crate-type proc-macro [..]` ... "#]]) .run(); } #[cargo_test] fn rustdoc_target() { if cross_compile::disabled() { return; } let p = project().file("src/lib.rs", "").build(); p.cargo("rustdoc --verbose --target") .arg(cross_compile::alternate()) .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustdoc [..]--crate-name foo src/lib.rs [..]--target [ALT_TARGET] -o [ROOT]/foo/target/[ALT_TARGET]/doc [..] -L dependency=[ROOT]/foo/target/[ALT_TARGET]/debug/deps -L dependency=[ROOT]/foo/target/debug/deps[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/[..]/doc/foo/index.html "#]]) .run(); } #[cargo_test] fn fail_with_glob() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() { break_the_build(); }") .build(); p.cargo("rustdoc -p '*z'") .with_status(101) .with_stderr_data(str![[r#" [ERROR] Glob patterns on package selection are not supported. "#]]) .run(); } cargo-0.86.0/tests/testsuite/rustdoc_extern_html.rs000064400000000000000000000373511046102023000206600ustar 00000000000000//! Tests for the -Zrustdoc-map feature. use cargo_test_support::prelude::*; use cargo_test_support::registry::{self, Package}; use cargo_test_support::{paths, project, str, Project}; fn basic_project() -> Project { Package::new("bar", "1.0.0") .file("src/lib.rs", "pub struct Straw;") .publish(); project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] bar = "1.0" "#, ) .file( "src/lib.rs", r#" pub fn myfun() -> Option { None } "#, ) .build() } #[cargo_test] fn ignores_on_stable() { // Requires -Zrustdoc-map to use. let p = basic_project(); p.cargo("doc -v --no-deps") .with_stderr_does_not_contain("[..]--extern-html-root-url[..]") .run(); } #[cargo_test(nightly, reason = "--extern-html-root-url is unstable")] fn simple() { // Basic test that it works with crates.io. let p = basic_project(); p.cargo("doc -v --no-deps -Zrustdoc-map") .masquerade_as_nightly_cargo(&["rustdoc-map"]) .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..]--crate-name foo [..]--extern-html-root-url [..]bar=https://docs.rs/bar/1.0.0/[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); let myfun = p.read_file("target/doc/foo/fn.myfun.html"); assert!(myfun.contains(r#"href="https://docs.rs/bar/1.0.0/bar/struct.Straw.html""#)); } #[ignore = "Broken, temporarily disabled until https://github.com/rust-lang/rust/pull/82776 is resolved."] #[cargo_test] // #[cargo_test(nightly, reason = "--extern-html-root-url is unstable")] fn std_docs() { // Mapping std docs somewhere else. // For local developers, skip this test if docs aren't installed. let docs = std::path::Path::new(&paths::sysroot()).join("share/doc/rust/html"); if !docs.exists() { if cargo_util::is_ci() { panic!("std docs are not installed, check that the rust-docs component is installed"); } else { eprintln!( "documentation not found at {}, \ skipping test (run `rustdoc component add rust-docs` to install", docs.display() ); return; } } let p = basic_project(); p.change_file( ".cargo/config.toml", r#" [doc.extern-map] std = "local" "#, ); p.cargo("doc -v --no-deps -Zrustdoc-map") .masquerade_as_nightly_cargo(&["rustdoc-map"]) .with_stderr_contains("[RUNNING] `rustdoc [..]--crate-name foo [..]std=file://[..]") .run(); let myfun = p.read_file("target/doc/foo/fn.myfun.html"); assert!(myfun.contains(r#"share/doc/rust/html/core/option/enum.Option.html""#)); p.change_file( ".cargo/config.toml", r#" [doc.extern-map] std = "https://example.com/rust/" "#, ); p.cargo("doc -v --no-deps -Zrustdoc-map") .masquerade_as_nightly_cargo(&["rustdoc-map"]) .with_stderr_contains( "[RUNNING] `rustdoc [..]--crate-name foo [..]std=https://example.com/rust/[..]", ) .run(); let myfun = p.read_file("target/doc/foo/fn.myfun.html"); assert!(myfun.contains(r#"href="https://example.com/rust/core/option/enum.Option.html""#)); } #[cargo_test(nightly, reason = "--extern-html-root-url is unstable")] fn renamed_dep() { // Handles renamed dependencies. Package::new("bar", "1.0.0") .file("src/lib.rs", "pub struct Straw;") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] groovy = { version = "1.0", package = "bar" } "#, ) .file( "src/lib.rs", r#" pub fn myfun() -> Option { None } "#, ) .build(); p.cargo("doc -v --no-deps -Zrustdoc-map") .masquerade_as_nightly_cargo(&["rustdoc-map"]) .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..]--crate-name foo [..]--extern-html-root-url [..]bar=https://docs.rs/bar/1.0.0/[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); let myfun = p.read_file("target/doc/foo/fn.myfun.html"); assert!(myfun.contains(r#"href="https://docs.rs/bar/1.0.0/bar/struct.Straw.html""#)); } #[cargo_test(nightly, reason = "--extern-html-root-url is unstable")] fn lib_name() { // Handles lib name != package name. Package::new("bar", "1.0.0") .file( "Cargo.toml", r#" [package] name = "bar" version = "1.0.0" [lib] name = "rumpelstiltskin" "#, ) .file("src/lib.rs", "pub struct Straw;") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = "1.0" "#, ) .file( "src/lib.rs", r#" pub fn myfun() -> Option { None } "#, ) .build(); p.cargo("doc -v --no-deps -Zrustdoc-map") .masquerade_as_nightly_cargo(&["rustdoc-map"]) .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..]--crate-name foo [..]--extern-html-root-url [..]rumpelstiltskin=https://docs.rs/bar/1.0.0/[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); let myfun = p.read_file("target/doc/foo/fn.myfun.html"); assert!(myfun.contains(r#"href="https://docs.rs/bar/1.0.0/rumpelstiltskin/struct.Straw.html""#)); } #[cargo_test(nightly, reason = "--extern-html-root-url is unstable")] fn alt_registry() { // Supports other registry names. registry::alt_init(); Package::new("bar", "1.0.0") .alternative(true) .file( "src/lib.rs", r#" extern crate baz; pub struct Queen; pub use baz::King; "#, ) .registry_dep("baz", "1.0") .publish(); Package::new("baz", "1.0.0") .alternative(true) .file("src/lib.rs", "pub struct King;") .publish(); Package::new("grimm", "1.0.0") .file("src/lib.rs", "pub struct Gold;") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] bar = { version = "1.0", registry="alternative" } grimm = "1.0" "#, ) .file( "src/lib.rs", r#" pub fn queen() -> bar::Queen { bar::Queen } pub fn king() -> bar::King { bar::King } pub fn gold() -> grimm::Gold { grimm::Gold } "#, ) .file( ".cargo/config.toml", r#" [doc.extern-map.registries] alternative = "https://example.com/{pkg_name}/{version}/" crates-io = "https://docs.rs/" "#, ) .build(); p.cargo("doc -v --no-deps -Zrustdoc-map") .masquerade_as_nightly_cargo(&["rustdoc-map"]) .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..]--crate-name foo [..]--extern-html-root-url [..]bar=https://example.com/bar/1.0.0/[..] --extern-html-root-url [..]baz=https://example.com/baz/1.0.0/[..] --extern-html-root-url [..]grimm=https://docs.rs/grimm/1.0.0/[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); let queen = p.read_file("target/doc/foo/fn.queen.html"); assert!(queen.contains(r#"href="https://example.com/bar/1.0.0/bar/struct.Queen.html""#)); let king = p.read_file("target/doc/foo/fn.king.html"); assert!(king.contains(r#"href="https://example.com/baz/1.0.0/baz/struct.King.html""#)); let gold = p.read_file("target/doc/foo/fn.gold.html"); assert!(gold.contains(r#"href="https://docs.rs/grimm/1.0.0/grimm/struct.Gold.html""#)); } #[cargo_test(nightly, reason = "--extern-html-root-url is unstable")] fn multiple_versions() { // What happens when there are multiple versions. // NOTE: This is currently broken behavior. Rustdoc does not provide a way // to match renamed dependencies. Package::new("bar", "1.0.0") .file("src/lib.rs", "pub struct Spin;") .publish(); Package::new("bar", "2.0.0") .file("src/lib.rs", "pub struct Straw;") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] bar = "1.0" bar2 = {version="2.0", package="bar"} "#, ) .file( "src/lib.rs", " pub fn fn1() -> bar::Spin {bar::Spin} pub fn fn2() -> bar2::Straw {bar2::Straw} ", ) .build(); p.cargo("doc -v --no-deps -Zrustdoc-map") .masquerade_as_nightly_cargo(&["rustdoc-map"]) .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..]--crate-name foo [..]--extern-html-root-url [..]bar=https://docs.rs/bar/1.0.0/[..] --extern-html-root-url [..]bar=https://docs.rs/bar/2.0.0/[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); let fn1 = p.read_file("target/doc/foo/fn.fn1.html"); // This should be 1.0.0, rustdoc seems to use the last entry when there // are duplicates. assert!(fn1.contains(r#"href="https://docs.rs/bar/2.0.0/bar/struct.Spin.html""#)); let fn2 = p.read_file("target/doc/foo/fn.fn2.html"); assert!(fn2.contains(r#"href="https://docs.rs/bar/2.0.0/bar/struct.Straw.html""#)); } #[cargo_test(nightly, reason = "--extern-html-root-url is unstable")] fn rebuilds_when_changing() { // Make sure it rebuilds if the map changes. let p = basic_project(); p.cargo("doc -v --no-deps -Zrustdoc-map") .masquerade_as_nightly_cargo(&["rustdoc-map"]) .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..]--extern-html-root-url[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); // This also tests that the map for docs.rs can be overridden. p.change_file( ".cargo/config.toml", r#" [doc.extern-map.registries] crates-io = "https://example.com/" "#, ); p.cargo("doc -v --no-deps -Zrustdoc-map") .masquerade_as_nightly_cargo(&["rustdoc-map"]) .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..]--extern-html-root-url [..]bar=https://example.com/bar/1.0.0/[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); } #[cargo_test(nightly, reason = "--extern-html-root-url is unstable")] fn alt_sparse_registry() { // Supports other registry names. registry::init(); let _registry = registry::RegistryBuilder::new() .http_index() .alternative() .build(); Package::new("bar", "1.0.0") .alternative(true) .file( "src/lib.rs", r#" extern crate baz; pub struct Queen; pub use baz::King; "#, ) .registry_dep("baz", "1.0") .publish(); Package::new("baz", "1.0.0") .alternative(true) .file("src/lib.rs", "pub struct King;") .publish(); Package::new("grimm", "1.0.0") .file("src/lib.rs", "pub struct Gold;") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] bar = { version = "1.0", registry="alternative" } grimm = "1.0" "#, ) .file( "src/lib.rs", r#" pub fn queen() -> bar::Queen { bar::Queen } pub fn king() -> bar::King { bar::King } pub fn gold() -> grimm::Gold { grimm::Gold } "#, ) .file( ".cargo/config.toml", r#" [doc.extern-map.registries] alternative = "https://example.com/{pkg_name}/{version}/" crates-io = "https://docs.rs/" "#, ) .build(); p.cargo("doc -v --no-deps -Zrustdoc-map") .masquerade_as_nightly_cargo(&["rustdoc-map"]) .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..]--crate-name foo [..]--extern-html-root-url [..]bar=https://example.com/bar/1.0.0/[..] --extern-html-root-url [..]baz=https://example.com/baz/1.0.0/[..] --extern-html-root-url [..]grimm=https://docs.rs/grimm/1.0.0/[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); let queen = p.read_file("target/doc/foo/fn.queen.html"); assert!(queen.contains(r#"href="https://example.com/bar/1.0.0/bar/struct.Queen.html""#)); let king = p.read_file("target/doc/foo/fn.king.html"); assert!(king.contains(r#"href="https://example.com/baz/1.0.0/baz/struct.King.html""#)); let gold = p.read_file("target/doc/foo/fn.gold.html"); assert!(gold.contains(r#"href="https://docs.rs/grimm/1.0.0/grimm/struct.Gold.html""#)); } #[cargo_test(nightly, reason = "--extern-html-root-url is unstable")] fn same_deps_multi_occurrence_in_dep_tree() { // rust-lang/cargo#13543 Package::new("baz", "1.0.0") .file("src/lib.rs", "") .publish(); Package::new("bar", "1.0.0") .file("src/lib.rs", "") .dep("baz", "1.0") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" edition = "2018" [dependencies] bar = "1.0" baz = "1.0" "#, ) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [doc.extern-map.registries] crates-io = "https://docs.rs/" "#, ) .build(); p.cargo("doc -v --no-deps -Zrustdoc-map") .masquerade_as_nightly_cargo(&["rustdoc-map"]) .with_stderr_does_not_contain( "[..]--extern-html-root-url[..]bar=https://docs.rs\ [..]--extern-html-root-url[..]baz=https://docs.rs\ [..]--extern-html-root-url[..]baz=https://docs.rs[..]", ) .with_stderr_contains( "[..]--extern-html-root-url[..]bar=https://docs.rs\ [..]--extern-html-root-url[..]baz=https://docs.rs[..]", ) .run(); } cargo-0.86.0/tests/testsuite/rustdocflags.rs000064400000000000000000000146351046102023000172640ustar 00000000000000//! Tests for setting custom rustdoc flags. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::rustc_host; use cargo_test_support::rustc_host_env; use cargo_test_support::str; #[cargo_test] fn parses_env() { let p = project().file("src/lib.rs", "").build(); p.cargo("doc -v") .env("RUSTDOCFLAGS", "--cfg=foo") .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..] --cfg=foo[..]` ... "#]]) .run(); } #[cargo_test] fn parses_config() { let p = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [build] rustdocflags = ["--cfg", "foo"] "#, ) .build(); p.cargo("doc -v") .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..] --cfg foo [..]` ... "#]]) .run(); } #[cargo_test] fn bad_flags() { let p = project().file("src/lib.rs", "").build(); p.cargo("doc") .env("RUSTDOCFLAGS", "--bogus") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] Unrecognized option: 'bogus' ... "#]]) .run(); } #[cargo_test] fn rerun() { let p = project().file("src/lib.rs", "").build(); p.cargo("doc").env("RUSTDOCFLAGS", "--cfg=foo").run(); p.cargo("doc") .env("RUSTDOCFLAGS", "--cfg=foo") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); p.cargo("doc") .env("RUSTDOCFLAGS", "--cfg=bar") .with_stderr_data(str![[r#" [DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [GENERATED] [ROOT]/foo/target/doc/foo/index.html "#]]) .run(); } #[cargo_test] fn rustdocflags_passed_to_rustdoc_through_cargo_test() { let p = project() .file( "src/lib.rs", r#" //! ``` //! assert!(cfg!(do_not_choke)); //! ``` "#, ) .build(); p.cargo("test --doc") .env("RUSTDOCFLAGS", "--cfg do_not_choke") .run(); } #[cargo_test] fn rustdocflags_passed_to_rustdoc_through_cargo_test_only_once() { let p = project().file("src/lib.rs", "").build(); p.cargo("test --doc") .env("RUSTDOCFLAGS", "--markdown-no-toc") .run(); } #[cargo_test] fn rustdocflags_misspelled() { let p = project().file("src/main.rs", "fn main() { }").build(); p.cargo("doc") .env("RUSTDOC_FLAGS", "foo") .with_stderr_data(str![[r#" [WARNING] Cargo does not read `RUSTDOC_FLAGS` environment variable. Did you mean `RUSTDOCFLAGS`? ... "#]]) .run(); } #[cargo_test] fn whitespace() { // Checks behavior of different whitespace characters. let p = project().file("src/lib.rs", "").build(); // "too many operands" p.cargo("doc") .env("RUSTDOCFLAGS", "--crate-version this has spaces") .with_stderr_data(str![[r#" ... [ERROR] could not document `foo` ... "#]]) .with_status(101) .run(); p.cargo("doc") .env_remove("__CARGO_TEST_FORCE_ARGFILE") // Not applicable for argfile. .env( "RUSTDOCFLAGS", "--crate-version 1111\n2222\t3333\u{00a0}4444", ) .run(); let contents = p.read_file("target/doc/foo/index.html"); assert!(contents.contains("1111")); assert!(contents.contains("2222")); assert!(contents.contains("3333")); assert!(contents.contains("4444")); } #[cargo_test] fn not_affected_by_target_rustflags() { let cfg = if cfg!(windows) { "windows" } else { "unix" }; let p = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", &format!( r#" [target.'cfg({cfg})'] rustflags = ["-D", "missing-docs"] [build] rustdocflags = ["--cfg", "foo"] "#, ), ) .build(); // `cargo build` should fail due to missing docs. p.cargo("build -v") .with_status(101) .with_stderr_data(str![[r#" ... [RUNNING] `rustc [..] -D missing-docs` ... "#]]) .run(); // `cargo doc` shouldn't fail. p.cargo("doc -v") .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..] --cfg foo[..]` ... "#]]) .run(); } #[cargo_test] fn target_triple_rustdocflags_works() { let host = rustc_host(); let host_env = rustc_host_env(); let p = project().file("src/lib.rs", "").build(); // target.triple.rustdocflags in env works p.cargo("doc -v") .env( &format!("CARGO_TARGET_{host_env}_RUSTDOCFLAGS"), "--cfg=foo", ) .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc[..]--cfg[..]foo[..]` ... "#]]) .run(); // target.triple.rustdocflags in config works p.cargo("doc -v") .arg("--config") .arg(format!("target.{host}.rustdocflags=['--cfg', 'foo']")) .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc [..] --cfg foo [..]` ... "#]]) .run(); } #[cargo_test] fn target_triple_rustdocflags_works_through_cargo_test() { let host = rustc_host(); let host_env = rustc_host_env(); let p = project() .file( "src/lib.rs", r#" //! ``` //! assert!(cfg!(foo)); //! ``` "#, ) .build(); // target.triple.rustdocflags in env works p.cargo("test --doc -v") .env( &format!("CARGO_TARGET_{host_env}_RUSTDOCFLAGS"), "--cfg=foo", ) .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc[..]--test[..]--cfg[..]foo[..]` "#]]) .with_stdout_data(str![[r#" running 1 test test src/lib.rs - (line 2) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); // target.triple.rustdocflags in config works p.cargo("test --doc -v") .arg("--config") .arg(format!("target.{host}.rustdocflags=['--cfg', 'foo']")) .with_stderr_data(str![[r#" ... [RUNNING] `rustdoc[..]--test[..]--cfg[..]foo[..]` "#]]) .with_stdout_data(str![[r#" running 1 test test src/lib.rs - (line 2) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/rustflags.rs000064400000000000000000001327121046102023000165730ustar 00000000000000//! Tests for setting custom rustc flags. use std::fs; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{ basic_manifest, paths, project, project_in_home, rustc_host, str, RawOutput, }; use snapbox::assert_data_eq; #[cargo_test] fn env_rustflags_normal_source() { let p = project() .file("src/lib.rs", "") .file("src/bin/a.rs", "fn main() {}") .file("examples/b.rs", "fn main() {}") .file("tests/c.rs", "#[test] fn f() { }") .file( "benches/d.rs", r#" #![feature(test)] extern crate test; #[bench] fn run1(_ben: &mut test::Bencher) { } "#, ) .build(); // Use RUSTFLAGS to pass an argument that will generate an error p.cargo("check --lib") .env("RUSTFLAGS", "-Z bogus") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("check --bin=a") .env("RUSTFLAGS", "-Z bogus") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("check --example=b") .env("RUSTFLAGS", "-Z bogus") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("test") .env("RUSTFLAGS", "-Z bogus") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("bench") .env("RUSTFLAGS", "-Z bogus") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); } #[cargo_test] fn env_rustflags_build_script() { // RUSTFLAGS should be passed to rustc for build scripts // when --target is not specified. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { assert!(cfg!(foo)); } "#, ) .build(); p.cargo("check").env("RUSTFLAGS", "--cfg foo").run(); } #[cargo_test] fn env_rustflags_build_script_dep() { // RUSTFLAGS should be passed to rustc for build scripts // when --target is not specified. // In this test if --cfg foo is not passed the build will fail. let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" build = "build.rs" [build-dependencies.bar] path = "../bar" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.0.1")) .file( "src/lib.rs", r#" fn bar() { } #[cfg(not(foo))] fn bar() { } "#, ) .build(); foo.cargo("check").env("RUSTFLAGS", "--cfg foo").run(); } #[cargo_test] fn env_rustflags_normal_source_with_target() { let p = project() .file("src/lib.rs", "") .file("src/bin/a.rs", "fn main() {}") .file("examples/b.rs", "fn main() {}") .file("tests/c.rs", "#[test] fn f() { }") .file( "benches/d.rs", r#" #![feature(test)] extern crate test; #[bench] fn run1(_ben: &mut test::Bencher) { } "#, ) .build(); let host = &rustc_host(); // Use RUSTFLAGS to pass an argument that will generate an error p.cargo("check --lib --target") .arg(host) .env("RUSTFLAGS", "-Z bogus") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("check --bin=a --target") .arg(host) .env("RUSTFLAGS", "-Z bogus") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("check --example=b --target") .arg(host) .env("RUSTFLAGS", "-Z bogus") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("test --target") .arg(host) .env("RUSTFLAGS", "-Z bogus") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("bench --target") .arg(host) .env("RUSTFLAGS", "-Z bogus") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); } #[cargo_test] fn env_rustflags_build_script_with_target() { // RUSTFLAGS should not be passed to rustc for build scripts // when --target is specified. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { assert!(!cfg!(foo)); } "#, ) .build(); let host = rustc_host(); p.cargo("check --target") .arg(host) .env("RUSTFLAGS", "--cfg foo") .run(); } #[cargo_test] fn env_rustflags_build_script_with_target_doesnt_apply_to_host_kind() { // RUSTFLAGS should *not* be passed to rustc for build scripts when --target is specified as the // host triple even if target-applies-to-host-kind is enabled, to match legacy Cargo behavior. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { assert!(!cfg!(foo)); } "#, ) .file( ".cargo/config.toml", r#" target-applies-to-host = true "#, ) .build(); let host = rustc_host(); p.cargo("check --target") .masquerade_as_nightly_cargo(&["target-applies-to-host"]) .arg(host) .arg("-Ztarget-applies-to-host") .env("RUSTFLAGS", "--cfg foo") .run(); } #[cargo_test] fn env_rustflags_build_script_dep_with_target() { // RUSTFLAGS should not be passed to rustc for build scripts // when --target is specified. // In this test if --cfg foo is passed the build will fail. let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" build = "build.rs" [build-dependencies.bar] path = "../bar" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.0.1")) .file( "src/lib.rs", r#" fn bar() { } #[cfg(foo)] fn bar() { } "#, ) .build(); let host = rustc_host(); foo.cargo("check --target") .arg(host) .env("RUSTFLAGS", "--cfg foo") .run(); } #[cargo_test] fn env_rustflags_recompile() { let p = project().file("src/lib.rs", "").build(); p.cargo("check").run(); // Setting RUSTFLAGS forces a recompile p.cargo("check") .env("RUSTFLAGS", "-Z bogus") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); } #[cargo_test] fn env_rustflags_recompile2() { let p = project().file("src/lib.rs", "").build(); p.cargo("check").env("RUSTFLAGS", "--cfg foo").run(); // Setting RUSTFLAGS forces a recompile p.cargo("check") .env("RUSTFLAGS", "-Z bogus") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); } #[cargo_test] fn env_rustflags_no_recompile() { let p = project().file("src/lib.rs", "").build(); p.cargo("check").env("RUSTFLAGS", "--cfg foo").run(); p.cargo("check") .env("RUSTFLAGS", "--cfg foo") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_rustflags_normal_source() { let p = project() .file("src/lib.rs", "") .file("src/bin/a.rs", "fn main() {}") .file("examples/b.rs", "fn main() {}") .file("tests/c.rs", "#[test] fn f() { }") .file( "benches/d.rs", r#" #![feature(test)] extern crate test; #[bench] fn run1(_ben: &mut test::Bencher) { } "#, ) .file( ".cargo/config.toml", r#" [build] rustflags = ["-Z", "bogus"] "#, ) .build(); p.cargo("check --lib") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("check --bin=a") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("check --example=b") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("test") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("bench") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); } #[cargo_test] fn build_rustflags_build_script() { // RUSTFLAGS should be passed to rustc for build scripts // when --target is not specified. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { assert!(cfg!(foo)); } "#, ) .file( ".cargo/config.toml", r#" [build] rustflags = ["--cfg", "foo"] "#, ) .build(); p.cargo("check").run(); } #[cargo_test] fn build_rustflags_build_script_dep() { // RUSTFLAGS should be passed to rustc for build scripts // when --target is not specified. // In this test if --cfg foo is not passed the build will fail. let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" build = "build.rs" [build-dependencies.bar] path = "../bar" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [build] rustflags = ["--cfg", "foo"] "#, ) .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.0.1")) .file( "src/lib.rs", r#" fn bar() { } #[cfg(not(foo))] fn bar() { } "#, ) .build(); foo.cargo("check").run(); } #[cargo_test] fn build_rustflags_normal_source_with_target() { let p = project() .file("src/lib.rs", "") .file("src/bin/a.rs", "fn main() {}") .file("examples/b.rs", "fn main() {}") .file("tests/c.rs", "#[test] fn f() { }") .file( "benches/d.rs", r#" #![feature(test)] extern crate test; #[bench] fn run1(_ben: &mut test::Bencher) { } "#, ) .file( ".cargo/config.toml", r#" [build] rustflags = ["-Z", "bogus"] "#, ) .build(); let host = &rustc_host(); // Use build.rustflags to pass an argument that will generate an error p.cargo("check --lib --target") .arg(host) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("check --bin=a --target") .arg(host) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("check --example=b --target") .arg(host) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("test --target") .arg(host) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("bench --target") .arg(host) .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); } #[cargo_test] fn build_rustflags_build_script_with_target() { // RUSTFLAGS should not be passed to rustc for build scripts // when --target is specified. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" build = "build.rs" "#, ) .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { assert!(!cfg!(foo)); } "#, ) .file( ".cargo/config.toml", r#" [build] rustflags = ["--cfg", "foo"] "#, ) .build(); let host = rustc_host(); p.cargo("check --target").arg(host).run(); } #[cargo_test] fn build_rustflags_build_script_dep_with_target() { // RUSTFLAGS should not be passed to rustc for build scripts // when --target is specified. // In this test if --cfg foo is passed the build will fail. let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" build = "build.rs" [build-dependencies.bar] path = "../bar" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [build] rustflags = ["--cfg", "foo"] "#, ) .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.0.1")) .file( "src/lib.rs", r#" fn bar() { } #[cfg(foo)] fn bar() { } "#, ) .build(); let host = rustc_host(); foo.cargo("check --target").arg(host).run(); } #[cargo_test] fn build_rustflags_recompile() { let p = project().file("src/lib.rs", "").build(); p.cargo("check").run(); // Setting RUSTFLAGS forces a recompile let config = r#" [build] rustflags = ["-Z", "bogus"] "#; let config_file = paths::root().join("foo/.cargo/config.toml"); fs::create_dir_all(config_file.parent().unwrap()).unwrap(); fs::write(config_file, config).unwrap(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); } #[cargo_test] fn build_rustflags_recompile2() { let p = project().file("src/lib.rs", "").build(); p.cargo("check").env("RUSTFLAGS", "--cfg foo").run(); // Setting RUSTFLAGS forces a recompile let config = r#" [build] rustflags = ["-Z", "bogus"] "#; let config_file = paths::root().join("foo/.cargo/config.toml"); fs::create_dir_all(config_file.parent().unwrap()).unwrap(); fs::write(config_file, config).unwrap(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); } #[cargo_test] fn build_rustflags_no_recompile() { let p = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [build] rustflags = ["--cfg", "foo"] "#, ) .build(); p.cargo("check").env("RUSTFLAGS", "--cfg foo").run(); p.cargo("check") .env("RUSTFLAGS", "--cfg foo") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn build_rustflags_with_home_config() { // We need a config file inside the home directory let home = paths::home(); let home_config = home.join(".cargo"); fs::create_dir(&home_config).unwrap(); fs::write( &home_config.join("config"), r#" [build] rustflags = ["-Cllvm-args=-x86-asm-syntax=intel"] "#, ) .unwrap(); // And we need the project to be inside the home directory // so the walking process finds the home project twice. let p = project_in_home("foo").file("src/lib.rs", "").build(); p.cargo("check -v").run(); } #[cargo_test] fn target_rustflags_normal_source() { let p = project() .file("src/lib.rs", "") .file("src/bin/a.rs", "fn main() {}") .file("examples/b.rs", "fn main() {}") .file("tests/c.rs", "#[test] fn f() { }") .file( "benches/d.rs", r#" #![feature(test)] extern crate test; #[bench] fn run1(_ben: &mut test::Bencher) { } "#, ) .file( ".cargo/config.toml", &format!( " [target.{}] rustflags = [\"-Z\", \"bogus\"] ", rustc_host() ), ) .build(); p.cargo("check --lib") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("check --bin=a") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("check --example=b") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("test") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("bench") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); } #[cargo_test] fn target_rustflags_also_for_build_scripts() { let p = project() .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { assert!(cfg!(foo)); } "#, ) .file( ".cargo/config.toml", &format!( " [target.{}] rustflags = [\"--cfg=foo\"] ", rustc_host() ), ) .build(); p.cargo("check").run(); } #[cargo_test] fn target_rustflags_not_for_build_scripts_with_target() { let host = rustc_host(); let p = project() .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { assert!(!cfg!(foo)); } "#, ) .file( ".cargo/config.toml", &format!( " [target.{}] rustflags = [\"--cfg=foo\"] ", host ), ) .build(); p.cargo("check --target").arg(host).run(); // Enabling -Ztarget-applies-to-host should not make a difference without the config setting p.cargo("check --target") .arg(host) .masquerade_as_nightly_cargo(&["target-applies-to-host"]) .arg("-Ztarget-applies-to-host") .run(); // Even with the setting, the rustflags from `target.` should not apply, to match the legacy // Cargo behavior. p.change_file( ".cargo/config.toml", &format!( " target-applies-to-host = true [target.{}] rustflags = [\"--cfg=foo\"] ", host ), ); p.cargo("check --target") .arg(host) .masquerade_as_nightly_cargo(&["target-applies-to-host"]) .arg("-Ztarget-applies-to-host") .run(); } #[cargo_test] fn build_rustflags_for_build_scripts() { let host = rustc_host(); let p = project() .file("src/lib.rs", "") .file( "build.rs", r#" fn main() { assert!(cfg!(foo), "CFG FOO!"); } "#, ) .file( ".cargo/config.toml", " [build] rustflags = [\"--cfg=foo\"] ", ) .build(); // With "legacy" behavior, build.rustflags should apply to build scripts without --target p.cargo("check").run(); // But should _not_ apply _with_ --target p.cargo("check --target") .arg(host) .with_status(101) .with_stderr_data("...\n[..]CFG FOO![..]\n...") .run(); // Enabling -Ztarget-applies-to-host should not make a difference without the config setting p.cargo("check") .masquerade_as_nightly_cargo(&["target-applies-to-host"]) .arg("-Ztarget-applies-to-host") .run(); p.cargo("check --target") .arg(host) .masquerade_as_nightly_cargo(&["target-applies-to-host"]) .arg("-Ztarget-applies-to-host") .with_status(101) .with_stderr_data("...\n[..]CFG FOO![..]\n...") .run(); // When set to false though, the "proper" behavior where host artifacts _only_ pick up on // [host] should be applied. p.change_file( ".cargo/config.toml", " target-applies-to-host = false [build] rustflags = [\"--cfg=foo\"] ", ); p.cargo("check") .masquerade_as_nightly_cargo(&["target-applies-to-host"]) .arg("-Ztarget-applies-to-host") .with_status(101) .with_stderr_data("...\n[..]CFG FOO![..]\n...") .run(); p.cargo("check --target") .arg(host) .masquerade_as_nightly_cargo(&["target-applies-to-host"]) .arg("-Ztarget-applies-to-host") .with_status(101) .with_stderr_data("...\n[..]CFG FOO![..]\n...") .run(); } #[cargo_test] fn host_rustflags_for_build_scripts() { let host = rustc_host(); let p = project() .file("src/lib.rs", "") .file( "build.rs", r#" // Ensure that --cfg=foo is passed. fn main() { assert!(cfg!(foo)); } "#, ) .file( ".cargo/config.toml", &format!( " target-applies-to-host = false [host.{}] rustflags = [\"--cfg=foo\"] ", host ), ) .build(); p.cargo("check --target") .arg(host) .masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"]) .arg("-Ztarget-applies-to-host") .arg("-Zhost-config") .run(); } // target.{}.rustflags takes precedence over build.rustflags #[cargo_test] fn target_rustflags_precedence() { let p = project() .file("src/lib.rs", "") .file("src/bin/a.rs", "fn main() {}") .file("examples/b.rs", "fn main() {}") .file("tests/c.rs", "#[test] fn f() { }") .file( ".cargo/config.toml", &format!( " [build] rustflags = [\"--cfg\", \"foo\"] [target.{}] rustflags = [\"-Z\", \"bogus\"] ", rustc_host() ), ) .build(); p.cargo("check --lib") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("check --bin=a") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("check --example=b") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("test") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); p.cargo("bench") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to run `rustc` to learn about target-specific information Caused by: [..]bogus[..] ... "#]]) .run(); } #[cargo_test] fn cfg_rustflags_normal_source() { let p = project() .file("src/lib.rs", "pub fn t() {}") .file("src/bin/a.rs", "fn main() {}") .file("examples/b.rs", "fn main() {}") .file("tests/c.rs", "#[test] fn f() { }") .file( ".cargo/config.toml", &format!( r#" [target.'cfg({})'] rustflags = ["--cfg", "bar"] "#, if rustc_host().contains("-windows-") { "windows" } else { "not(windows)" } ), ) .build(); p.cargo("build --lib -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] --cfg bar` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build --bin=a -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name a [..] --cfg bar` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build --example=b -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name b [..] --cfg bar` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("test --no-run -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] --cfg bar` [RUNNING] `rustc [..] --cfg bar` [RUNNING] `rustc [..] --cfg bar` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [EXECUTABLE] `[ROOT]/foo/target/debug/deps/a-[HASH][EXE]` [EXECUTABLE] `[ROOT]/foo/target/debug/deps/c-[HASH][EXE]` "#]]) .run(); p.cargo("bench --no-run -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] --cfg bar` [RUNNING] `rustc [..] --cfg bar` [RUNNING] `rustc [..] --cfg bar` [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [EXECUTABLE] `[ROOT]/foo/target/release/deps/foo-[HASH][EXE]` [EXECUTABLE] `[ROOT]/foo/target/release/deps/a-[HASH][EXE]` "#]]) .run(); } // target.'cfg(...)'.rustflags takes precedence over build.rustflags #[cargo_test] fn cfg_rustflags_precedence() { let p = project() .file("src/lib.rs", "pub fn t() {}") .file("src/bin/a.rs", "fn main() {}") .file("examples/b.rs", "fn main() {}") .file("tests/c.rs", "#[test] fn f() { }") .file( ".cargo/config.toml", &format!( r#" [build] rustflags = ["--cfg", "foo"] [target.'cfg({})'] rustflags = ["--cfg", "bar"] "#, if rustc_host().contains("-windows-") { "windows" } else { "not(windows)" } ), ) .build(); p.cargo("build --lib -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] --cfg bar` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build --bin=a -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name a [..] --cfg bar` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build --example=b -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name b [..] --cfg bar` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("test --no-run -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] --cfg bar` [RUNNING] `rustc [..] --cfg bar` [RUNNING] `rustc [..] --cfg bar` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [EXECUTABLE] `[ROOT]/foo/target/debug/deps/a-[HASH][EXE]` [EXECUTABLE] `[ROOT]/foo/target/debug/deps/c-[HASH][EXE]` "#]]) .run(); p.cargo("bench --no-run -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] --cfg bar` [RUNNING] `rustc [..] --cfg bar` [RUNNING] `rustc [..] --cfg bar` [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [EXECUTABLE] `[ROOT]/foo/target/release/deps/foo-[HASH][EXE]` [EXECUTABLE] `[ROOT]/foo/target/release/deps/a-[HASH][EXE]` "#]]) .run(); } #[cargo_test] fn target_rustflags_string_and_array_form1() { let p1 = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [build] rustflags = ["--cfg", "foo"] "#, ) .build(); p1.cargo("check -v") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] --cfg foo` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let p2 = project() .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [build] rustflags = "--cfg foo" "#, ) .build(); p2.cargo("check -v") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] --cfg foo` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn target_rustflags_string_and_array_form2() { let p1 = project() .file( ".cargo/config.toml", &format!( r#" [target.{}] rustflags = ["--cfg", "foo"] "#, rustc_host() ), ) .file("src/lib.rs", "") .build(); p1.cargo("check -v") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] --cfg foo` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); let p2 = project() .file( ".cargo/config.toml", &format!( r#" [target.{}] rustflags = "--cfg foo" "#, rustc_host() ), ) .file("src/lib.rs", "") .build(); p2.cargo("check -v") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo [..] --cfg foo` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn two_matching_in_config() { let p1 = project() .file( ".cargo/config.toml", r#" [target.'cfg(unix)'] rustflags = ["--cfg", 'foo="a"'] [target.'cfg(windows)'] rustflags = ["--cfg", 'foo="a"'] [target.'cfg(target_pointer_width = "32")'] rustflags = ["--cfg", 'foo="b"'] [target.'cfg(target_pointer_width = "64")'] rustflags = ["--cfg", 'foo="b"'] "#, ) .file( "src/main.rs", r#" #![allow(unexpected_cfgs)] fn main() { if cfg!(foo = "a") { println!("a"); } else if cfg!(foo = "b") { println!("b"); } else { panic!() } } "#, ) .build(); p1.cargo("run").run(); p1.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn env_rustflags_misspelled() { let p = project().file("src/main.rs", "fn main() { }").build(); for cmd in &["check", "build", "run", "test", "bench"] { p.cargo(cmd) .env("RUST_FLAGS", "foo") .with_stderr_data( "\ [WARNING] Cargo does not read `RUST_FLAGS` environment variable. Did you mean `RUSTFLAGS`? ... ", ) .run(); } } #[cargo_test] fn env_rustflags_misspelled_build_script() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2021" build = "build.rs" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() { }") .build(); p.cargo("check") .env("RUST_FLAGS", "foo") .with_stderr_data(str![[r#" [WARNING] Cargo does not read `RUST_FLAGS` environment variable. Did you mean `RUSTFLAGS`? [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn remap_path_prefix_works() { // Check that remap-path-prefix works. Package::new("bar", "0.1.0") .file("src/lib.rs", "pub fn f() -> &'static str { file!() }") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = "0.1" "#, ) .file( "src/main.rs", r#" fn main() { println!("{}", bar::f()); } "#, ) .build(); p.cargo("run") .env( "RUSTFLAGS", format!("--remap-path-prefix={}=/foo", paths::root().display()), ) .with_stdout_data(str![[r#" /foo/home/.cargo/registry/src/-[HASH]/bar-0.1.0/src/lib.rs "#]]) .run(); } #[cargo_test] fn rustflags_remap_path_prefix_ignored_for_c_metadata() { let p = project().file("src/lib.rs", "").build(); let build_output = p .cargo("build -v") .env( "RUSTFLAGS", "--remap-path-prefix=/abc=/zoo --remap-path-prefix /spaced=/zoo", ) .run(); let first_c_metadata = dbg!(get_c_metadata(build_output)); p.cargo("clean").run(); let build_output = p .cargo("build -v") .env( "RUSTFLAGS", "--remap-path-prefix=/def=/zoo --remap-path-prefix /earth=/zoo", ) .run(); let second_c_metadata = dbg!(get_c_metadata(build_output)); assert_data_eq!(first_c_metadata, second_c_metadata); } #[cargo_test] fn rustc_remap_path_prefix_ignored_for_c_metadata() { let p = project().file("src/lib.rs", "").build(); let build_output = p .cargo("rustc -v -- --remap-path-prefix=/abc=/zoo --remap-path-prefix /spaced=/zoo") .run(); let first_c_metadata = dbg!(get_c_metadata(build_output)); p.cargo("clean").run(); let build_output = p .cargo("rustc -v -- --remap-path-prefix=/def=/zoo --remap-path-prefix /earth=/zoo") .run(); let second_c_metadata = dbg!(get_c_metadata(build_output)); assert_data_eq!(first_c_metadata, second_c_metadata); } // `--remap-path-prefix` is meant to take two different binaries and make them the same but the // rlib name, including `-Cextra-filename`, can still end up in the binary so it can't change #[cargo_test] fn rustflags_remap_path_prefix_ignored_for_c_extra_filename() { let p = project().file("src/lib.rs", "").build(); let build_output = p .cargo("build -v") .env( "RUSTFLAGS", "--remap-path-prefix=/abc=/zoo --remap-path-prefix /spaced=/zoo", ) .run(); let first_c_extra_filename = dbg!(get_c_extra_filename(build_output)); p.cargo("clean").run(); let build_output = p .cargo("build -v") .env( "RUSTFLAGS", "--remap-path-prefix=/def=/zoo --remap-path-prefix /earth=/zoo", ) .run(); let second_c_extra_filename = dbg!(get_c_extra_filename(build_output)); assert_data_eq!(first_c_extra_filename, second_c_extra_filename); } // `--remap-path-prefix` is meant to take two different binaries and make them the same but the // rlib name, including `-Cextra-filename`, can still end up in the binary so it can't change #[cargo_test] fn rustc_remap_path_prefix_ignored_for_c_extra_filename() { let p = project().file("src/lib.rs", "").build(); let build_output = p .cargo("rustc -v -- --remap-path-prefix=/abc=/zoo --remap-path-prefix /spaced=/zoo") .run(); let first_c_extra_filename = dbg!(get_c_extra_filename(build_output)); p.cargo("clean").run(); let build_output = p .cargo("rustc -v -- --remap-path-prefix=/def=/zoo --remap-path-prefix /earth=/zoo") .run(); let second_c_extra_filename = dbg!(get_c_extra_filename(build_output)); assert_data_eq!(first_c_extra_filename, second_c_extra_filename); } fn get_c_metadata(output: RawOutput) -> String { let get_c_metadata_re = regex::Regex::new(r".* (--crate-name [^ ]+).* (-C ?metadata=[^ ]+).*").unwrap(); let stderr = String::from_utf8(output.stderr).unwrap(); let mut c_metadata = get_c_metadata_re .captures_iter(&stderr) .map(|c| { let (_, [name, c_metadata]) = c.extract(); format!("{name} {c_metadata}") }) .collect::>(); assert!( !c_metadata.is_empty(), "`{get_c_metadata_re:?}` did not match:\n```\n{stderr}\n```" ); c_metadata.sort(); c_metadata.join("\n") } fn get_c_extra_filename(output: RawOutput) -> String { let get_c_extra_filename_re = regex::Regex::new(r".* (--crate-name [^ ]+).* (-C ?extra-filename=[^ ]+).*").unwrap(); let stderr = String::from_utf8(output.stderr).unwrap(); let mut c_extra_filename = get_c_extra_filename_re .captures_iter(&stderr) .map(|c| { let (_, [name, c_extra_filename]) = c.extract(); format!("{name} {c_extra_filename}") }) .collect::>(); assert!( !c_extra_filename.is_empty(), "`{get_c_extra_filename_re:?}` did not match:\n```\n{stderr}\n```" ); c_extra_filename.sort(); c_extra_filename.join("\n") } #[cargo_test] fn host_config_rustflags_with_target() { // regression test for https://github.com/rust-lang/cargo/issues/10206 let p = project() .file("src/lib.rs", "") .file("build.rs", "fn main() { assert!(cfg!(foo)); }") .file(".cargo/config.toml", "target-applies-to-host = false") .build(); p.cargo("check") .masquerade_as_nightly_cargo(&["target-applies-to-host", "host-config"]) .arg("-Zhost-config") .arg("-Ztarget-applies-to-host") .arg("-Zunstable-options") .arg("--config") .arg("host.rustflags=[\"--cfg=foo\"]") .run(); } #[cargo_test] fn target_applies_to_host_rustflags_works() { // Ensures that rustflags are passed to the target when // target_applies_to_host=false let p = project() .file( "src/lib.rs", r#"#[cfg(feature = "flag")] compile_error!("flag passed");"#, ) .build(); // Use RUSTFLAGS to pass an argument that will generate an error. p.cargo("check") .masquerade_as_nightly_cargo(&["target-applies-to-host"]) .arg("-Ztarget-applies-to-host") .env("CARGO_TARGET_APPLIES_TO_HOST", "false") .env("RUSTFLAGS", r#"--cfg feature="flag""#) .with_status(101) .with_stderr_data( "[CHECKING] foo v0.0.1 ([ROOT]/foo) [ERROR] flag passed ...", ) .run(); } #[cargo_test] fn target_applies_to_host_rustdocflags_works() { // Ensures that rustflags are passed to the target when // target_applies_to_host=false let p = project() .file( "src/lib.rs", r#"#[cfg(feature = "flag")] compile_error!("flag passed");"#, ) .build(); // Use RUSTFLAGS to pass an argument that would generate an error // but it is ignored. p.cargo("doc") .masquerade_as_nightly_cargo(&["target-applies-to-host"]) .arg("-Ztarget-applies-to-host") .env("CARGO_TARGET_APPLIES_TO_HOST", "false") .env("RUSTDOCFLAGS", r#"--cfg feature="flag""#) .with_status(101) .with_stderr_data( "[DOCUMENTING] foo v0.0.1 ([ROOT]/foo) [ERROR] flag passed ...", ) .run(); } #[cargo_test] fn host_config_shared_build_dep() { // rust-lang/cargo#14253 Package::new("cc", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bootstrap" edition = "2021" [dependencies] cc = "1.0.0" [build-dependencies] cc = "1.0.0" [profile.dev] debug = 0 "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .file( ".cargo/config.toml", " target-applies-to-host=false [host] rustflags = ['--cfg', 'from_host'] [build] rustflags = ['--cfg', 'from_target'] ", ) .build(); p.cargo("build -v") .masquerade_as_nightly_cargo(&["target-applies-to-host"]) .arg("-Ztarget-applies-to-host") .arg("-Zhost-config") .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] cc v1.0.0 (registry `dummy-registry`) [COMPILING] cc v1.0.0 [RUNNING] `rustc --crate-name cc [..]--cfg from_host[..]` [RUNNING] `rustc --crate-name cc [..]--cfg from_target[..]` [COMPILING] bootstrap v0.0.0 ([ROOT]/foo) [RUNNING] `rustc --crate-name build_script_build [..]--cfg from_host[..]` [RUNNING] `[ROOT]/foo/target/debug/build/bootstrap-[HASH]/build-script-build` [RUNNING] `rustc --crate-name bootstrap[..]--cfg from_target[..]` [FINISHED] `dev` profile [unoptimized] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } cargo-0.86.0/tests/testsuite/rustup.rs000064400000000000000000000215031046102023000161160ustar 00000000000000//! Tests for Cargo's behavior under Rustup. use std::env; use std::env::consts::EXE_EXTENSION; use std::ffi::OsString; use std::fs; use std::path::{Path, PathBuf}; use cargo_test_support::paths::{home, root}; use cargo_test_support::prelude::*; use cargo_test_support::{cargo_process, process, project, str}; /// Helper to generate an executable. fn make_exe(dest: &Path, name: &str, contents: &str, env: &[(&str, PathBuf)]) -> PathBuf { let rs_name = format!("{name}.rs"); fs::write( root().join(&rs_name), &format!("fn main() {{ {contents} }}"), ) .unwrap(); let mut pb = process("rustc"); env.iter().for_each(|(key, value)| { pb.env(key, value); }); pb.arg("--edition=2021") .arg(root().join(&rs_name)) .exec() .unwrap(); let exe = Path::new(name).with_extension(EXE_EXTENSION); let output = dest.join(&exe); fs::rename(root().join(&exe), &output).unwrap(); output } fn prepend_path(path: &Path) -> OsString { let mut paths = vec![path.to_path_buf()]; paths.extend(env::split_paths(&env::var_os("PATH").unwrap_or_default())); env::join_paths(paths).unwrap() } struct RustupEnvironment { /// Path for ~/.cargo/bin cargo_bin: PathBuf, /// Path for ~/.rustup rustup_home: PathBuf, /// Path to the cargo executable in the toolchain directory /// (~/.rustup/toolchain/test-toolchain/bin/cargo.exe). cargo_toolchain_exe: PathBuf, } /// Creates an executable which prints a message and then runs the *real* rustc. fn real_rustc_wrapper(bin_dir: &Path, message: &str) -> PathBuf { let real_rustc = cargo_util::paths::resolve_executable("rustc".as_ref()).unwrap(); // The toolchain rustc needs to call the real rustc. In order to do that, // it needs to restore or clear the RUSTUP environment variables so that // if rustup is installed, it will call the correct rustc. let rustup_toolchain_setup = match std::env::var_os("RUSTUP_TOOLCHAIN") { Some(t) => format!( ".env(\"RUSTUP_TOOLCHAIN\", \"{}\")", t.into_string().unwrap() ), None => format!(".env_remove(\"RUSTUP_TOOLCHAIN\")"), }; let mut env = vec![("CARGO_RUSTUP_TEST_real_rustc", real_rustc)]; let rustup_home_setup = match std::env::var_os("RUSTUP_HOME") { Some(h) => { env.push(("CARGO_RUSTUP_TEST_RUSTUP_HOME", h.into())); format!(".env(\"RUSTUP_HOME\", env!(\"CARGO_RUSTUP_TEST_RUSTUP_HOME\"))") } None => format!(".env_remove(\"RUSTUP_HOME\")"), }; make_exe( bin_dir, "rustc", &format!( r#" eprintln!("{message}"); let r = std::process::Command::new(env!("CARGO_RUSTUP_TEST_real_rustc")) .args(std::env::args_os().skip(1)) {rustup_toolchain_setup} {rustup_home_setup} .status(); std::process::exit(r.unwrap().code().unwrap_or(2)); "# ), &env, ) } /// Creates a simulation of a rustup environment with `~/.cargo/bin` and /// `~/.rustup` directories populated with some executables that simulate /// rustup. fn simulated_rustup_environment() -> RustupEnvironment { // Set up ~/.rustup/toolchains/test-toolchain/bin with a custom rustc and cargo. let rustup_home = home().join(".rustup"); let toolchain_bin = rustup_home .join("toolchains") .join("test-toolchain") .join("bin"); toolchain_bin.mkdir_p(); let rustc_toolchain_exe = real_rustc_wrapper(&toolchain_bin, "real rustc running"); let cargo_toolchain_exe = make_exe( &toolchain_bin, "cargo", r#"panic!("cargo toolchain should not be called");"#, &[], ); // Set up ~/.cargo/bin with a typical set of rustup proxies. let cargo_bin = home().join(".cargo").join("bin"); cargo_bin.mkdir_p(); let rustc_proxy = make_exe( &cargo_bin, "rustc", &format!( r#" match std::env::args().next().unwrap().as_ref() {{ "rustc" => {{}} arg => panic!("proxy only supports rustc, got {{arg:?}}"), }} eprintln!("rustc proxy running"); let r = std::process::Command::new(env!("CARGO_RUSTUP_TEST_rustc_toolchain_exe")) .args(std::env::args_os().skip(1)) .status(); std::process::exit(r.unwrap().code().unwrap_or(2)); "# ), &[("CARGO_RUSTUP_TEST_rustc_toolchain_exe", rustc_toolchain_exe)], ); fs::hard_link( &rustc_proxy, cargo_bin.join("cargo").with_extension(EXE_EXTENSION), ) .unwrap(); fs::hard_link( &rustc_proxy, cargo_bin.join("rustup").with_extension(EXE_EXTENSION), ) .unwrap(); RustupEnvironment { cargo_bin, rustup_home, cargo_toolchain_exe, } } #[cargo_test] fn typical_rustup() { // Test behavior under a typical rustup setup with a normal toolchain. let RustupEnvironment { cargo_bin, rustup_home, cargo_toolchain_exe, } = simulated_rustup_environment(); // Set up a project and run a normal cargo build. let p = project().file("src/lib.rs", "").build(); // The path is modified so that cargo will call `rustc` from // `~/.cargo/bin/rustc to use our custom rustup proxies. let path = prepend_path(&cargo_bin); p.cargo("check") .env("RUSTUP_TOOLCHAIN", "test-toolchain") .env("RUSTUP_HOME", &rustup_home) .env("PATH", &path) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) real rustc running [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Do a similar test, but with a toolchain link that does not have cargo // (which normally would do a fallback to nightly/beta/stable). cargo_toolchain_exe.rm_rf(); p.build_dir().rm_rf(); p.cargo("check") .env("RUSTUP_TOOLCHAIN", "test-toolchain") .env("RUSTUP_HOME", &rustup_home) .env("PATH", &path) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) real rustc running [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } // This doesn't work on Windows because Cargo forces the PATH to contain the // sysroot_libdir, which is actually `bin`, preventing the test from // overriding the bin directory. #[cargo_test(ignore_windows = "PATH can't be overridden on Windows")] fn custom_calls_other_cargo() { // Test behavior when a custom subcommand tries to manipulate PATH to use // a different toolchain. let RustupEnvironment { cargo_bin, rustup_home, cargo_toolchain_exe: _, } = simulated_rustup_environment(); // Create a directory with a custom toolchain (outside of the rustup universe). let custom_bin = root().join("custom-bin"); custom_bin.mkdir_p(); // `cargo` points to the real cargo. let cargo_exe = cargo_test_support::cargo_exe(); fs::hard_link(&cargo_exe, custom_bin.join(cargo_exe.file_name().unwrap())).unwrap(); // `rustc` executes the real rustc. real_rustc_wrapper(&custom_bin, "custom toolchain rustc running"); // A project that cargo-custom will try to build. let p = project().file("src/lib.rs", "").build(); // Create a custom cargo subcommand. // This will modify PATH to a custom toolchain and call cargo from that. make_exe( &cargo_bin, "cargo-custom", r#" use std::env; use std::process::Command; eprintln!("custom command running"); let mut paths = vec![std::path::PathBuf::from(env!("CARGO_RUSTUP_TEST_custom_bin"))]; paths.extend(env::split_paths(&env::var_os("PATH").unwrap_or_default())); let path = env::join_paths(paths).unwrap(); let status = Command::new("cargo") .arg("check") .current_dir(env!("CARGO_RUSTUP_TEST_project_dir")) .env("PATH", path) .status() .unwrap(); assert!(status.success()); "#, &[ ("CARGO_RUSTUP_TEST_custom_bin", custom_bin), ("CARGO_RUSTUP_TEST_project_dir", p.root()), ], ); cargo_process("custom") // Set these to simulate what would happen when running under rustup. // We want to make sure that cargo-custom does not try to use the // rustup proxies. .env("RUSTUP_TOOLCHAIN", "test-toolchain") .env("RUSTUP_HOME", &rustup_home) .with_stderr_data(str![[r#" custom command running [CHECKING] foo v0.0.1 ([ROOT]/foo) custom toolchain rustc running [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/script.rs000064400000000000000000001106401046102023000160610ustar 00000000000000use std::fs; use cargo_test_support::basic_manifest; use cargo_test_support::paths::cargo_home; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; 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::>(); println!("bin: {bin}"); println!("args: {args:?}"); } #[test] fn test () {} "#; #[cfg(unix)] fn path() -> Vec { std::env::split_paths(&std::env::var_os("PATH").unwrap_or_default()).collect() } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE] args: [] "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] echo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE] args: [] "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] echo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/echo[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_data("") .with_stderr_data(str![[r#" [ERROR] no such command: `echo` Did you mean `bench`? View all installed commands with `cargo --list` Find a package to install `echo` with `cargo search cargo-echo` To run the file `echo`, provide a relative path like `./echo` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] #[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_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE] args: [] "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] echo v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] #[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_data("") .with_stderr_data(str![[r#" [WARNING] external subcommand `echo.rs` has the appearance of a manifest-command This was previously accepted but will be phased out when `-Zscript` is stabilized. For more information, see issue #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_data("") .with_stderr_data(str![[r#" [ERROR] running the file `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_data("") .with_stderr_data(str![[r#" [ERROR] running the file `echo.rs` requires `-Zscript` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] fn clean_output_with_edition() { let script = r#"#!/usr/bin/env 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_data(str![[r#" Hello world! "#]]) .with_stderr_data(str![[r#" [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] fn warning_without_edition() { let script = r#"#!/usr/bin/env 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_data(str![[r#" Hello world! "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" msg = undefined "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]` "#]]) .run(); // Verify we don't rebuild p.cargo("-Zscript -v script.rs") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" msg = undefined "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]` "#]]) .run(); // Verify we do rebuild p.cargo("-Zscript -v script.rs") .env("_MESSAGE", "hello") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" msg = hello "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] fn use_cargo_home_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.toml", r#" [build] rustc = "non-existent-rustc" "#, ) .file("script.rs", script) .build(); // Verify that the config from the current directory is used p.cargo("-Zscript script.rs -NotAnArg") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] args: ["-NotAnArg"] "#]]) .run(); // Verify that the config from the parent directory is not used p.cargo("-Zscript ../script/script.rs -NotAnArg") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] args: ["-NotAnArg"] "#]]) .run(); // Write a global config.toml in the cargo home directory let cargo_home = cargo_home(); fs::write( &cargo_home.join("config.toml"), r#" [build] rustc = "non-existent-rustc" "#, ) .unwrap(); // Verify the global config is used p.cargo("-Zscript script.rs -NotAnArg") .masquerade_as_nightly_cargo(&["script"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] could not execute process `non-existent-rustc -vV` (never executed) Caused by: [NOT_FOUND] "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] args: ["-NotAnArg"] "#]]) .with_stderr_data("") .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] args: ["-NotAnArg"] "#]]) .with_stderr_data("") .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" line: 4 "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] args: ["-NotAnArg"] "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] -NotAnArg` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] args: ["-NotAnArg"] "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] -NotAnArg` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] args: ["--help"] "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] --help` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/s-h-w-c-[EXE] args: [] "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] s-h-w-c- v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/s-h-w-c-[EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] fn test_name_has_leading_number() { let script = ECHO_SCRIPT; let p = cargo_test_support::project() .file("42answer.rs", script) .build(); p.cargo("-Zscript -v 42answer.rs") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/answer[EXE] args: [] "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] answer v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/answer[EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] fn test_name_is_number() { let script = ECHO_SCRIPT; let p = cargo_test_support::project().file("42.rs", script).build(); p.cargo("-Zscript -v 42.rs") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/package[EXE] args: [] "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] package v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/package[EXE]` "#]]) .run(); } #[cargo_test] fn script_like_dir() { let p = cargo_test_support::project() .file("foo.rs/foo", "something") .build(); p.cargo("-Zscript -v foo.rs") .masquerade_as_nightly_cargo(&["script"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] no such file or subcommand `foo.rs` `foo.rs` is a directory "#]]) .run(); } #[cargo_test] fn non_existent_rs() { let p = cargo_test_support::project().build(); p.cargo("-Zscript -v foo.rs") .masquerade_as_nightly_cargo(&["script"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] no such file or subcommand `foo.rs` "#]]) .run(); } #[cargo_test] fn non_existent_rs_stable() { let p = cargo_test_support::project().build(); p.cargo("-v foo.rs") .masquerade_as_nightly_cargo(&["script"]) .with_status(101) .with_stdout_data("") .with_stderr_data(str![[r#" [ERROR] no such subcommand `foo.rs` "#]]) .run(); } #[cargo_test] fn did_you_mean_file() { let p = cargo_test_support::project() .file("food.rs", ECHO_SCRIPT) .build(); p.cargo("-Zscript -v foo.rs") .masquerade_as_nightly_cargo(&["script"]) .with_status(101) .with_stdout_data("") .with_stderr_data(str![[r#" [ERROR] no such file or subcommand `foo.rs` Did you mean the file `./food.rs` "#]]) .run(); } #[cargo_test] fn did_you_mean_file_stable() { let p = cargo_test_support::project() .file("food.rs", ECHO_SCRIPT) .build(); p.cargo("-v foo.rs") .masquerade_as_nightly_cargo(&["script"]) .with_status(101) .with_stdout_data("") .with_stderr_data(str![[r#" [ERROR] no such subcommand `foo.rs` Did you mean the file `./food.rs` with `-Zscript` "#]]) .run(); } #[cargo_test] fn did_you_mean_command() { let p = cargo_test_support::project().build(); p.cargo("-Zscript -v build--manifest-path=./Cargo.toml") .masquerade_as_nightly_cargo(&["script"]) .with_status(101) .with_stdout_data("") .with_stderr_data(str![[r#" [ERROR] no such file or subcommand `build--manifest-path=./Cargo.toml` Did you mean the command `build --manifest-path=./Cargo.toml` "#]]) .run(); } #[cargo_test] fn did_you_mean_command_stable() { let p = cargo_test_support::project().build(); p.cargo("-v build--manifest-path=./Cargo.toml") .masquerade_as_nightly_cargo(&["script"]) .with_status(101) .with_stdout_data("") .with_stderr_data(str![[r#" [ERROR] no such subcommand `build--manifest-path=./Cargo.toml` Did you mean the command `build --manifest-path=./Cargo.toml` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] fn test_name_same_as_dependency() { Package::new("script", "1.0.0").publish(); let script = r#"#!/usr/bin/env 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_data(str![[r#" Hello world! "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest Rust [..] compatible version [DOWNLOADING] crates ... [DOWNLOADED] script v1.0.0 (registry `dummy-registry`) [COMPILING] script v1.0.0 [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] --help` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] fn test_path_dep() { let script = r#"#!/usr/bin/env 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_data(str![[r#" Hello world! "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [LOCKING] 1 package to latest Rust [..] compatible version [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] --help` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" Hello world! "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] --help` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" Hello world! "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] --help` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] fn test_no_autolib() { let script = r#"#!/usr/bin/env cargo fn main() { println!("Hello world!"); }"#; let p = cargo_test_support::project() .file("script.rs", script) .file("src/lib.rs", r#"compile_error!{"must not be built"}"#) .build(); p.cargo("-Zscript -v script.rs --help") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" Hello world! "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] --help` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] args: [] "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] args: [] "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/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_data("") .with_stderr_data(str![[r#" [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_data("") .with_stderr_data(str![[r#" [ERROR] embedded manifest `[ROOT]/foo/script.rs` requires `-Zscript` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data("") .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [CHECKING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]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_data("") .with_stderr_data(str![[r#" [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_data("") .with_stderr_data(str![[r#" [ERROR] the manifest-path must be a path to a Cargo.toml file "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data("") .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" running 1 test test test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests script.rs ([ROOT]/home/.cargo/target/[HASH]/debug/deps/script-[HASH][EXE]) "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data("") .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [REMOVED] [FILE_NUM] files, [FILE_SIZE]B total "#]]) .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_data("") .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` "#]]) .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_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2024", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#script@0.0.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/script.rs", "metadata": null, "name": "script", "publish": [], "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2024", "kind": [ "bin" ], "name": "script", "src_path": "[ROOT]/foo/script.rs", "test": true } ], "version": "0.0.0" } ], "resolve": { "nodes": [ { "dependencies": [], "deps": [], "features": [], "id": "path+[ROOTURL]/foo#script@0.0.0" } ], "root": "path+[ROOTURL]/foo#script@0.0.0" }, "target_directory": "[ROOT]/home/.cargo/target/[HASH]", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#script@0.0.0" ], "workspace_members": [ "path+[ROOTURL]/foo#script@0.0.0" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` "#]]) .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_stdout_data( str![[r#" { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2024", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#script@0.0.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/script.rs", "metadata": null, "name": "script", "publish": [], "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "bin" ], "doc": true, "doctest": false, "edition": "2024", "kind": [ "bin" ], "name": "script", "src_path": "[ROOT]/foo/script.rs", "test": true } ], "version": "0.0.0" } "#]] .is_json(), ) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] 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_data(str![[r#" bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] args: [] "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/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_data(str![[r#" script v0.0.0 ([ROOT]/foo) "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` "#]]) .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_data("") .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` "#]]) .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_stdout_data( str![[r#" { "success": "true" } "#]] .is_json(), ) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` "#]]) .run(); } #[cargo_test] fn cmd_pkgid_with_embedded() { let p = cargo_test_support::project() .file("script.rs", ECHO_SCRIPT) .build(); p.cargo("-Zscript pkgid --manifest-path script.rs") .masquerade_as_nightly_cargo(&["script"]) .with_status(101) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [ERROR] [ROOT]/foo/script.rs is unsupported by `cargo pkgid` "#]]) .run(); } #[cargo_test] fn cmd_package_with_embedded() { let p = cargo_test_support::project() .file("script.rs", ECHO_SCRIPT) .build(); p.cargo("-Zscript package --manifest-path script.rs") .masquerade_as_nightly_cargo(&["script"]) .with_status(101) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [ERROR] [ROOT]/foo/script.rs is unsupported by `cargo package` "#]]) .run(); } #[cargo_test] fn cmd_publish_with_embedded() { let p = cargo_test_support::project() .file("script.rs", ECHO_SCRIPT) .build(); p.cargo("-Zscript publish --manifest-path script.rs") .masquerade_as_nightly_cargo(&["script"]) .with_status(101) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [ERROR] [ROOT]/foo/script.rs is unsupported by `cargo publish` "#]]) .run(); } #[cargo_test(nightly, reason = "edition2024 hasn't hit stable yet")] fn manifest_path_env() { let p = cargo_test_support::project() .file( "script.rs", r#"#!/usr/bin/env cargo fn main() { let path = env!("CARGO_MANIFEST_PATH"); println!("CARGO_MANIFEST_PATH: {}", path); } "#, ) .build(); p.cargo("-Zscript -v script.rs") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" CARGO_MANIFEST_PATH: [ROOT]/foo/script.rs "#]]) .with_stderr_data(str![[r#" [WARNING] `package.edition` is unspecified, defaulting to `2024` [COMPILING] script v0.0.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]` "#]]) .run(); } cargo-0.86.0/tests/testsuite/search.rs000064400000000000000000000142561046102023000160300ustar 00000000000000//! Tests for the `cargo search` command. use std::collections::HashSet; use cargo::util::cache_lock::CacheLockMode; use cargo_test_support::cargo_process; use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::{RegistryBuilder, Response}; use cargo_test_support::str; const SEARCH_API_RESPONSE: &[u8] = br#" { "crates": [{ "created_at": "2014-11-16T20:17:35Z", "description": "Design by contract style assertions for Rust", "documentation": null, "downloads": 2, "homepage": null, "id": "hoare", "keywords": [], "license": null, "links": { "owners": "/api/v1/crates/hoare/owners", "reverse_dependencies": "/api/v1/crates/hoare/reverse_dependencies", "version_downloads": "/api/v1/crates/hoare/downloads", "versions": "/api/v1/crates/hoare/versions" }, "max_version": "0.1.1", "name": "hoare", "repository": "https://github.com/nick29581/libhoare", "updated_at": "2014-11-20T21:49:21Z", "versions": null }, { "id": "postgres", "name": "postgres", "updated_at": "2020-05-01T23:17:54.335921+00:00", "versions": null, "keywords": null, "categories": null, "badges": [ { "badge_type": "circle-ci", "attributes": { "repository": "sfackler/rust-postgres", "branch": null } } ], "created_at": "2014-11-24T02:34:44.756689+00:00", "downloads": 535491, "recent_downloads": 88321, "max_version": "0.17.3", "newest_version": "0.17.3", "description": "A native, synchronous PostgreSQL client", "homepage": null, "documentation": null, "repository": "https://github.com/sfackler/rust-postgres", "links": { "version_downloads": "/api/v1/crates/postgres/downloads", "versions": "/api/v1/crates/postgres/versions", "owners": "/api/v1/crates/postgres/owners", "owner_team": "/api/v1/crates/postgres/owner_team", "owner_user": "/api/v1/crates/postgres/owner_user", "reverse_dependencies": "/api/v1/crates/postgres/reverse_dependencies" }, "exact_match": true } ], "meta": { "total": 2 } }"#; const SEARCH_RESULTS: &str = "\ hoare = \"0.1.1\" # Design by contract style assertions for Rust postgres = \"0.17.3\" # A native, synchronous PostgreSQL client "; #[must_use] fn setup() -> RegistryBuilder { RegistryBuilder::new() .http_api() .add_responder("/api/v1/crates", |_, _| Response { code: 200, headers: vec![], body: SEARCH_API_RESPONSE.to_vec(), }) } #[cargo_test] fn not_update() { let registry = setup().build(); use cargo::core::{Shell, SourceId}; use cargo::sources::source::Source; use cargo::sources::RegistrySource; use cargo::util::GlobalContext; let sid = SourceId::for_registry(registry.index_url()).unwrap(); let gctx = GlobalContext::new( Shell::from_write(Box::new(Vec::new())), paths::root(), paths::home().join(".cargo"), ); let lock = gctx .acquire_package_cache_lock(CacheLockMode::DownloadExclusive) .unwrap(); let mut regsrc = RegistrySource::remote(sid, &HashSet::new(), &gctx).unwrap(); regsrc.invalidate_cache(); regsrc.block_until_ready().unwrap(); drop(lock); cargo_process("search postgres") .replace_crates_io(registry.index_url()) .with_stdout_data(SEARCH_RESULTS) // without "Updating ... index" .with_stderr_data(str![[r#" [NOTE] to learn more about a package, run `cargo info ` "#]]) .run(); } #[cargo_test] fn replace_default() { let registry = setup().build(); cargo_process("search postgres") .replace_crates_io(registry.index_url()) .with_stdout_data(SEARCH_RESULTS) .with_stderr_data(str![[r#" [UPDATING] crates.io index [NOTE] to learn more about a package, run `cargo info ` "#]]) .run(); } #[cargo_test] fn simple() { let registry = setup().build(); cargo_process("search postgres --index") .arg(registry.index_url().as_str()) .with_stdout_data(SEARCH_RESULTS) .with_stderr_data(str![[r#" [UPDATING] `[ROOT]/registry` index [NOTE] to learn more about a package, run `cargo info ` "#]]) .run(); } #[cargo_test] fn multiple_query_params() { let registry = setup().build(); cargo_process("search postgres sql --index") .arg(registry.index_url().as_str()) .with_stdout_data(SEARCH_RESULTS) .with_stderr_data(str![[r#" [UPDATING] `[ROOT]/registry` index [NOTE] to learn more about a package, run `cargo info ` "#]]) .run(); } #[cargo_test] fn ignore_quiet() { let registry = setup().build(); cargo_process("search -q postgres") .replace_crates_io(registry.index_url()) .with_stdout_data(SEARCH_RESULTS) .run(); } #[cargo_test] fn colored_results() { let registry = setup().build(); cargo_process("search --color=never postgres") .replace_crates_io(registry.index_url()) .with_stdout_does_not_contain("[..]\x1b[[..]") .run(); cargo_process("search --color=always postgres") .replace_crates_io(registry.index_url()) .with_stdout_data( "\ ... [..]\x1b[[..] ... ", ) .run(); } #[cargo_test] fn auth_required_failure() { let server = setup().auth_required().no_configure_token().build(); cargo_process("search postgres") .replace_crates_io(server.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index [ERROR] no token found, please run `cargo login` or use environment variable CARGO_REGISTRY_TOKEN "#]]) .run(); } #[cargo_test] fn auth_required() { let server = setup().auth_required().build(); cargo_process("search postgres") .replace_crates_io(server.index_url()) .with_stdout_data(SEARCH_RESULTS) .run(); } cargo-0.86.0/tests/testsuite/shell_quoting.rs000064400000000000000000000022301046102023000174250ustar 00000000000000//! This file tests that when the commands being run are shown //! in the output, their arguments are quoted properly //! so that the command can be run in a terminal. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::str; #[cargo_test] fn features_are_quoted() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = ["mikeyhew@example.com"] edition = "2015" [features] some_feature = [] default = ["some_feature"] "#, ) .file("src/main.rs", "fn main() {error}") .build(); p.cargo("check -v") .env("MSYSTEM", "1") .with_status(101) .with_stderr_data(str![[r#" [CHECKING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] --cfg 'feature="default"' --cfg 'feature="some_feature"' [..]` ... [ERROR] could not compile `foo` (bin "foo") due to 1 previous error Caused by: process didn't exit successfully: [..] --cfg 'feature="default"' --cfg 'feature="some_feature"' [..] "#]]) .run(); } cargo-0.86.0/tests/testsuite/source_replacement.rs000064400000000000000000000220521046102023000204330ustar 00000000000000//! Tests for `[source]` table (source replacement). use std::fs; use cargo_test_support::prelude::*; use cargo_test_support::registry::{Package, RegistryBuilder, TestRegistry}; use cargo_test_support::{cargo_process, paths, project, str, t}; fn setup_replacement(config: &str) -> TestRegistry { let crates_io = RegistryBuilder::new() .no_configure_registry() .http_api() .build(); let root = paths::root(); t!(fs::create_dir(&root.join(".cargo"))); t!(fs::write(root.join(".cargo/config.toml"), config,)); crates_io } #[cargo_test] fn crates_io_token_not_sent_to_replacement() { // verifies that the crates.io token is not sent to a replacement registry during publish. let crates_io = setup_replacement( r#" [source.crates-io] replace-with = 'alternative' "#, ); let _alternative = RegistryBuilder::new() .alternative() .http_api() .no_configure_token() .build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish --no-verify --registry crates-io") .replace_crates_io(crates_io.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index ... "#]]) .run(); } #[cargo_test] fn token_sent_to_correct_registry() { // verifies that the crates.io token is not sent to a replacement registry during yank. let crates_io = setup_replacement( r#" [source.crates-io] replace-with = 'alternative' "#, ); let _alternative = RegistryBuilder::new().alternative().http_api().build(); cargo_process("yank foo@0.0.1 --registry crates-io") .replace_crates_io(crates_io.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [YANK] foo@0.0.1 "#]]) .run(); cargo_process("yank foo@0.0.1 --registry alternative") .replace_crates_io(crates_io.index_url()) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [YANK] foo@0.0.1 "#]]) .run(); } #[cargo_test] fn ambiguous_registry() { // verifies that an error is issued when a source-replacement is configured // and no --registry argument is given. let crates_io = setup_replacement( r#" [source.crates-io] replace-with = 'alternative' "#, ); let _alternative = RegistryBuilder::new() .alternative() .http_api() .no_configure_token() .build(); cargo_process("yank foo@0.0.1") .replace_crates_io(crates_io.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] crates-io is replaced with remote registry alternative; include `--registry alternative` or `--registry crates-io` "#]]) .run(); } #[cargo_test] fn yank_with_default_crates_io() { // verifies that no error is given when registry.default is used. let crates_io = setup_replacement( r#" [source.crates-io] replace-with = 'alternative' [registry] default = 'crates-io' "#, ); let _alternative = RegistryBuilder::new().alternative().http_api().build(); cargo_process("yank foo@0.0.1") .replace_crates_io(crates_io.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [YANK] foo@0.0.1 "#]]) .run(); } #[cargo_test] fn yank_with_default_alternative() { // verifies that no error is given when registry.default is an alt registry. let crates_io = setup_replacement( r#" [source.crates-io] replace-with = 'alternative' [registry] default = 'alternative' "#, ); let _alternative = RegistryBuilder::new().alternative().http_api().build(); cargo_process("yank foo@0.0.1") .replace_crates_io(crates_io.index_url()) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [YANK] foo@0.0.1 "#]]) .run(); } #[cargo_test] fn publish_with_replacement() { // verifies that the crates.io token is not sent to a replacement registry during publish. let crates_io = setup_replacement( r#" [source.crates-io] replace-with = 'alternative' "#, ); let _alternative = RegistryBuilder::new() .alternative() .http_api() .no_configure_token() .build(); // Publish bar only to alternative. This tests that the publish verification build // does uses the source replacement. Package::new("bar", "1.0.0").alternative(true).publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] license = "MIT" description = "foo" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); // Verifies that the crates.io index is used to find the publishing endpoint // and that the crate is sent to crates.io. The source replacement is only used // for the verification step. p.cargo("publish --registry crates-io") .replace_crates_io(crates_io.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [WARNING] manifest has no documentation, homepage or repository. See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. [PACKAGING] foo v0.0.1 ([ROOT]/foo) [UPDATING] `alternative` index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.0.1 ([ROOT]/foo) [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `alternative`) [COMPILING] bar v1.0.0 [COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.0.1 ([ROOT]/foo) [UPLOADED] foo v0.0.1 to registry `crates-io` [NOTE] waiting for `foo v0.0.1` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.0.1 at registry `crates-io` "#]]) .run(); } #[cargo_test] fn undefined_default() { // verifies that no error is given when registry.default is used. let crates_io = setup_replacement( r#" [registry] default = 'undefined' "#, ); cargo_process("yank foo@0.0.1") .replace_crates_io(crates_io.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] registry index was not found in any configuration: `undefined` "#]]) .run(); } #[cargo_test] fn source_replacement_with_registry_url() { let alternative = RegistryBuilder::new().alternative().http_api().build(); Package::new("bar", "0.0.1").alternative(true).publish(); let crates_io = setup_replacement(&format!( r#" [source.crates-io] replace-with = 'using-registry-url' [source.using-registry-url] registry = '{}' "#, alternative.index_url() )); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies.bar] version = "0.0.1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .replace_crates_io(crates_io.index_url()) .with_stderr_data(str![[r#" [UPDATING] `using-registry-url` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `using-registry-url`) [CHECKING] bar v0.0.1 [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn source_replacement_with_no_package_in_directoy() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2021" [dependencies] bar = { version = "^0.8.9" } "#, ) .file("src/lib.rs", "") .build(); let root = paths::root(); t!(fs::create_dir(&root.join("vendor"))); let crates_io = setup_replacement(&format!( r#" [source.crates-io] replace-with = "vendored-sources" [source.vendored-sources] directory = "vendor" "# )); p.cargo("build") .replace_crates_io(crates_io.index_url()) .with_status(101) .with_stderr_data(str![[r#" [ERROR] no matching package named `bar` found location searched: directory source `[ROOT]/vendor` (which is replacing registry `crates-io`) required by package `foo v0.1.0 ([ROOT]/foo)` "#]]) .run(); } cargo-0.86.0/tests/testsuite/ssh.rs000064400000000000000000000522721046102023000153600ustar 00000000000000//! Network tests for SSH connections. //! //! Note that these tests will generally require setting `CARGO_CONTAINER_TESTS` //! or `CARGO_PUBLIC_NETWORK_TESTS`. //! //! NOTE: The container tests almost certainly won't work on Windows. use std::fs; use std::io::Write; use std::path::PathBuf; use cargo_test_support::containers::{Container, ContainerHandle, MkFile}; use cargo_test_support::git::cargo_uses_gitoxide; use cargo_test_support::prelude::*; use cargo_test_support::{paths, process, project, str, Project}; fn ssh_repo_url(container: &ContainerHandle, name: &str) -> String { let port = container.port_mappings[&22]; format!("ssh://testuser@127.0.0.1:{port}/repos/{name}.git") } /// The path to the client's private key. fn key_path() -> PathBuf { paths::home().join(".ssh/id_ed25519") } /// Generates the SSH keys for authenticating into the container. fn gen_ssh_keys() -> String { let path = key_path(); process("ssh-keygen") .args(&["-t", "ed25519", "-N", "", "-f"]) .arg(&path) .exec_with_output() .unwrap(); let pub_key = path.with_extension("pub"); fs::read_to_string(pub_key).unwrap() } /// Handler for running ssh-agent for SSH authentication. /// /// Be sure to set `SSH_AUTH_SOCK` when running a process in order to use the /// agent. Keys will need to be copied into the container with the /// `authorized_keys()` method. struct Agent { sock: PathBuf, pid: String, ssh_dir: PathBuf, pub_key: String, } impl Agent { fn launch() -> Agent { let ssh_dir = paths::home().join(".ssh"); fs::create_dir(&ssh_dir).unwrap(); let pub_key = gen_ssh_keys(); let sock = paths::root().join("agent"); let output = process("ssh-agent") .args(&["-s", "-a"]) .arg(&sock) .exec_with_output() .unwrap(); let stdout = std::str::from_utf8(&output.stdout).unwrap(); let start = stdout.find("SSH_AGENT_PID=").unwrap() + 14; let end = &stdout[start..].find(';').unwrap(); let pid = (&stdout[start..start + end]).to_string(); eprintln!("SSH_AGENT_PID={pid}"); process("ssh-add") .arg(key_path()) .env("SSH_AUTH_SOCK", &sock) .exec_with_output() .unwrap(); Agent { sock, pid, ssh_dir, pub_key, } } /// Returns a `MkFile` which can be passed into the `Container` builder to /// copy an `authorized_keys` file containing this agent's public key. fn authorized_keys(&self) -> MkFile { MkFile::path("home/testuser/.ssh/authorized_keys") .contents(self.pub_key.as_bytes()) .mode(0o600) .uid(100) .gid(101) } } impl Drop for Agent { fn drop(&mut self) { if let Err(e) = process("ssh-agent") .args(&["-k", "-a"]) .arg(&self.sock) .env("SSH_AGENT_PID", &self.pid) .exec_with_output() { eprintln!("failed to stop ssh-agent: {e:?}"); } } } /// Common project used for several tests. fn foo_bar_project(url: &str) -> Project { project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = {{ git = "{url}" }} "# ), ) .file("src/lib.rs", "") .build() } #[cargo_test(container_test)] fn no_known_host() { // When host is not known, it should show an error. let sshd = Container::new("sshd").launch(); let url = ssh_repo_url(&sshd, "bar"); let p = foo_bar_project(&url); p.cargo("fetch") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git` [ERROR] failed to get `bar` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update ssh://testuser@127.0.0.1:[..]/repos/bar.git Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/bar-[HASH] Caused by: [ERROR] unknown SSH host key The SSH host key for `[127.0.0.1]:[..]` is not known and cannot be validated. To resolve this issue, add the host key to the `net.ssh.known-hosts` array in your Cargo configuration (such as [ROOT]/home/.cargo/config.toml) or in your OpenSSH known_hosts file at [ROOT]/home/.ssh/known_hosts The key to add is: [127.0.0.1]:[..] ecdsa-sha2-nistp256 AAAA[..] The ECDSA key fingerprint is: SHA256:[..] This fingerprint should be validated with the server administrator that it is correct. See https://doc.rust-lang.org/stable/cargo/appendix/git-authentication.html#ssh-known-hosts for more information. "#]]) .run(); } #[cargo_test(container_test)] fn known_host_works() { // The key displayed in the error message should work when added to known_hosts. let agent = Agent::launch(); let sshd = Container::new("sshd") .file(agent.authorized_keys()) .launch(); let url = ssh_repo_url(&sshd, "bar"); let p = foo_bar_project(&url); let output = p .cargo("fetch") .env("SSH_AUTH_SOCK", &agent.sock) .build_command() .output() .unwrap(); let stderr = std::str::from_utf8(&output.stderr).unwrap(); // Validate the fingerprint while we're here. let fingerprint = stderr .lines() .find_map(|line| line.strip_prefix(" The ECDSA key fingerprint is: ")) .unwrap() .trim(); let finger_out = sshd.exec(&["ssh-keygen", "-l", "-f", "/etc/ssh/ssh_host_ecdsa_key.pub"]); let gen_finger = std::str::from_utf8(&finger_out.stdout).unwrap(); // let gen_finger = gen_finger.split_whitespace().nth(1).unwrap(); assert_eq!(fingerprint, gen_finger); // Add the key to known_hosts, and try again. let key = stderr .lines() .find(|line| line.starts_with(" [127.0.0.1]:")) .unwrap() .trim(); fs::write(agent.ssh_dir.join("known_hosts"), key).unwrap(); p.cargo("fetch") .env("SSH_AUTH_SOCK", &agent.sock) .with_stderr_data(str![[r#" [UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git` [LOCKING] 1 package to latest compatible version "#]]) .run(); } #[cargo_test(container_test)] fn same_key_different_hostname() { // The error message should mention if an identical key was found. let agent = Agent::launch(); let sshd = Container::new("sshd").launch(); let hostkey = sshd.read_file("/etc/ssh/ssh_host_ecdsa_key.pub"); let known_hosts = format!("example.com {hostkey}"); fs::write(agent.ssh_dir.join("known_hosts"), known_hosts).unwrap(); let url = ssh_repo_url(&sshd, "bar"); let p = foo_bar_project(&url); p.cargo("fetch") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git` [ERROR] failed to get `bar` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update ssh://testuser@127.0.0.1:[..]/repos/bar.git Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/bar-[HASH] Caused by: [ERROR] unknown SSH host key The SSH host key for `[127.0.0.1]:[..]` is not known and cannot be validated. To resolve this issue, add the host key to the `net.ssh.known-hosts` array in your Cargo configuration (such as [ROOT]/home/.cargo/config.toml) or in your OpenSSH known_hosts file at [ROOT]/home/.ssh/known_hosts The key to add is: [127.0.0.1]:[..] ecdsa-sha2-nistp256 AAAA[..] The ECDSA key fingerprint is: SHA256:[..] This fingerprint should be validated with the server administrator that it is correct. Note: This host key was found, but is associated with a different host: [ROOT]/home/.ssh/known_hosts line 1: example.com See https://doc.rust-lang.org/stable/cargo/appendix/git-authentication.html#ssh-known-hosts for more information. "#]]) .run(); } #[cargo_test(container_test)] fn known_host_without_port() { // A known_host entry without a port should match a connection to a non-standard port. let agent = Agent::launch(); let sshd = Container::new("sshd") .file(agent.authorized_keys()) .launch(); let hostkey = sshd.read_file("/etc/ssh/ssh_host_ecdsa_key.pub"); // The important part of this test is that this line does not have a port. let known_hosts = format!("127.0.0.1 {hostkey}"); fs::write(agent.ssh_dir.join("known_hosts"), known_hosts).unwrap(); let url = ssh_repo_url(&sshd, "bar"); let p = foo_bar_project(&url); p.cargo("fetch") .env("SSH_AUTH_SOCK", &agent.sock) .with_stderr_data(str![[r#" [UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git` [LOCKING] 1 package to latest compatible version "#]]) .run(); } #[cargo_test(container_test)] fn hostname_case_insensitive() { // hostname checking should be case-insensitive. let agent = Agent::launch(); let sshd = Container::new("sshd") .file(agent.authorized_keys()) .launch(); // Consider using `gethostname-rs` instead? let hostname = process("hostname").exec_with_output().unwrap(); let hostname = std::str::from_utf8(&hostname.stdout).unwrap().trim(); let inv_hostname = if hostname.chars().any(|c| c.is_lowercase()) { hostname.to_uppercase() } else { // There should be *some* chars in the name. assert!(hostname.chars().any(|c| c.is_uppercase())); hostname.to_lowercase() }; eprintln!("converted {hostname} to {inv_hostname}"); let hostkey = sshd.read_file("/etc/ssh/ssh_host_ecdsa_key.pub"); let known_hosts = format!("{inv_hostname} {hostkey}"); fs::write(agent.ssh_dir.join("known_hosts"), known_hosts).unwrap(); let port = sshd.port_mappings[&22]; let url = format!("ssh://testuser@{hostname}:{port}/repos/bar.git"); let p = foo_bar_project(&url); p.cargo("fetch") .env("SSH_AUTH_SOCK", &agent.sock) .with_stderr_data(&format!( "\ [UPDATING] git repository `ssh://testuser@{hostname}:{port}/repos/bar.git` [LOCKING] 1 package to latest compatible version " )) .run(); } #[cargo_test(container_test)] fn invalid_key_error() { // An error when a known_host value doesn't match. let agent = Agent::launch(); let sshd = Container::new("sshd") .file(agent.authorized_keys()) .launch(); let port = sshd.port_mappings[&22]; let known_hosts = format!( "[127.0.0.1]:{port} ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLqLMclVr7MDuaVsm3sEnnq2OrGxTFiHSw90wd6N14BU8xVC9cZldC3rJ58Wmw6bEVKPjk7foNG0lHwS5bCKX+U=\n" ); fs::write(agent.ssh_dir.join("known_hosts"), known_hosts).unwrap(); let url = ssh_repo_url(&sshd, "bar"); let p = foo_bar_project(&url); p.cargo("fetch") .env("SSH_AUTH_SOCK", &agent.sock) .with_status(101) .with_stderr_data(&format!("\ [UPDATING] git repository `ssh://testuser@127.0.0.1:{port}/repos/bar.git` [ERROR] failed to get `bar` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bar` Caused by: Unable to update ssh://testuser@127.0.0.1:{port}/repos/bar.git Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/bar-[HASH] Caused by: [ERROR] SSH host key has changed for `[127.0.0.1]:{port}` ********************************* * WARNING: HOST KEY HAS CHANGED * ********************************* This may be caused by a man-in-the-middle attack, or the server may have changed its host key. The ECDSA fingerprint for the key from the remote host is: SHA256:[..] You are strongly encouraged to contact the server administrator for `[127.0.0.1]:{port}` to verify that this new key is correct. If you can verify that the server has a new key, you can resolve this error by removing the old ecdsa-sha2-nistp256 key for `[127.0.0.1]:{port}` located at [ROOT]/home/.ssh/known_hosts line 1, and adding the new key to the `net.ssh.known-hosts` array in your Cargo configuration (such as [ROOT]/home/.cargo/config.toml) or in your OpenSSH known_hosts file at [ROOT]/home/.ssh/known_hosts The key provided by the remote host is: [127.0.0.1]:{port} ecdsa-sha2-nistp256 [..] See https://doc.rust-lang.org/stable/cargo/appendix/git-authentication.html#ssh-known-hosts for more information. ")) .run(); // Add the key, it should work even with the old key left behind. let hostkey = sshd.read_file("/etc/ssh/ssh_host_ecdsa_key.pub"); let known_hosts_path = agent.ssh_dir.join("known_hosts"); let mut f = fs::OpenOptions::new() .append(true) .open(known_hosts_path) .unwrap(); write!(f, "[127.0.0.1]:{port} {hostkey}").unwrap(); drop(f); p.cargo("fetch") .env("SSH_AUTH_SOCK", &agent.sock) .with_stderr_data(str![[r#" [UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git` [LOCKING] 1 package to latest compatible version "#]]) .run(); } // For unknown reasons, this test occasionally fails on Windows with a // LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE error: // failed to start SSH session: Unable to exchange encryption keys; class=Ssh (23) #[cargo_test(public_network_test, ignore_windows = "test is flaky on windows")] fn invalid_github_key() { // A key for github.com in known_hosts should override the built-in key. // This uses a bogus key which should result in an error. let ssh_dir = paths::home().join(".ssh"); fs::create_dir(&ssh_dir).unwrap(); let known_hosts = "\ github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLqLMclVr7MDuaVsm3sEnnq2OrGxTFiHSw90wd6N14BU8xVC9cZldC3rJ58Wmw6bEVKPjk7foNG0lHwS5bCKX+U=\n\ github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDgi+8rMcyFCBq5y7BXrb2aaYGhMjlU3QDy7YDvtNL5KSecYOsaqQHaXr87Bbx0EEkgbhK4kVMkmThlCoNITQS9Vc3zIMQ+Tg6+O4qXx719uCzywl50Tb5tDqPGMj54jcq3VUiu/dvse0yeehyvzoPNWewgGWLx11KI4A4wOwMnc6guhculEWe9DjGEjUQ34lPbmdfu/Hza7ZVu/RhgF/wc43uzXWB2KpMEqtuY1SgRlCZqTASoEtfKZi0AuM7AEdOwE5aTotS4CQZHWimb1bMFpF4DAq92CZ8Jhrm4rWETbO29WmjviCJEA3KNQyd3oA7H9AE9z/22PJaVEmjiZZ+wyLgwyIpOlsnHYNEdGeQMQ4SgLRkARLwcnKmByv1AAxsBW4LI3Os4FpwxVPdXHcBebydtvxIsbtUVkkq99nbsIlnSRFSTvb0alrdzRuKTdWpHtN1v9hagFqmeCx/kJfH76NXYBbtaWZhSOnxfEbhLYuOb+IS4jYzHAIkzy9FjVuk=\n\ ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEeMB6BUAW6FfvfLxRO3kGASe0yXnrRT4kpqncsup2b2\n"; fs::write(ssh_dir.join("known_hosts"), known_hosts).unwrap(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bitflags = { git = "ssh://git@github.com/rust-lang/bitflags.git", tag = "1.3.2" } "#, ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .with_status(101) .with_stderr_data(if cargo_uses_gitoxide() { str![[r#" ... git@github.com: Permission denied (publickey). ... "#]] } else { str![[r#" ... [ERROR] SSH host key has changed for `github.com` ... "#]] }) .run(); } // For unknown reasons, this test occasionally fails on Windows with a // LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE error: // failed to start SSH session: Unable to exchange encryption keys; class=Ssh (23) #[cargo_test(public_network_test, ignore_windows = "test is flaky on windows")] fn bundled_github_works() { // The bundled key for github.com works. // // Use a bogus auth sock to force an authentication error. // On Windows, if the agent service is running, it could allow a // successful authentication. // // If the bundled hostkey did not work, it would result in an "unknown SSH // host key" instead. let bogus_auth_sock = paths::home().join("ssh_auth_sock"); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bitflags = { git = "ssh://git@github.com/rust-lang/bitflags.git", tag = "1.3.2" } "#, ) .file("src/lib.rs", "") .build(); let expected = if cargo_uses_gitoxide() { str![[r#" [UPDATING] git repository `ssh://git@github.com/rust-lang/bitflags.git` [ERROR] failed to get `bitflags` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bitflags` Caused by: Unable to update ssh://git@github.com/rust-lang/bitflags.git?tag=1.3.2 Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/bitflags-[HASH] Caused by: failed to authenticate when downloading repository * attempted to find username/password via `credential.helper`, but maybe the found credentials were incorrect if the git CLI succeeds then `net.git-fetch-with-cli` may help here https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli Caused by: [CREDENTIAL]s provided for "ssh://git@github.com/rust-lang/bitflags.git" were not accepted by the remote Caused by: git@github.com: Permission denied (publickey). "#]] } else { str![[r#" [UPDATING] git repository `ssh://git@github.com/rust-lang/bitflags.git` [ERROR] failed to get `bitflags` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bitflags` Caused by: Unable to update ssh://git@github.com/rust-lang/bitflags.git?tag=1.3.2 Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/bitflags-[HASH] Caused by: failed to authenticate when downloading repository * attempted ssh-agent authentication, but no usernames succeeded: `git` if the git CLI succeeds then `net.git-fetch-with-cli` may help here https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli Caused by: no authentication methods succeeded "#]] }; p.cargo("fetch") .env("SSH_AUTH_SOCK", &bogus_auth_sock) .with_status(101) .with_stderr_data(expected) .run(); let expected = if cargo_uses_gitoxide() { str![[r#" [UPDATING] git repository `ssh://git@github.com:22/rust-lang/bitflags.git` [ERROR] failed to get `bitflags` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bitflags` Caused by: Unable to update ssh://git@github.com:22/rust-lang/bitflags.git?tag=1.3.2 Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/bitflags-[HASH] Caused by: failed to authenticate when downloading repository * attempted to find username/password via `credential.helper`, but maybe the found credentials were incorrect if the git CLI succeeds then `net.git-fetch-with-cli` may help here https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli Caused by: [CREDENTIAL]s provided for "ssh://git@github.com:22/rust-lang/bitflags.git" were not accepted by the remote Caused by: git@github.com: Permission denied (publickey). "#]] } else { str![[r#" [UPDATING] git repository `ssh://git@github.com:22/rust-lang/bitflags.git` [ERROR] failed to get `bitflags` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `bitflags` Caused by: Unable to update ssh://git@github.com:22/rust-lang/bitflags.git?tag=1.3.2 Caused by: failed to clone into: [ROOT]/home/.cargo/git/db/bitflags-[HASH] Caused by: failed to authenticate when downloading repository * attempted ssh-agent authentication, but no usernames succeeded: `git` if the git CLI succeeds then `net.git-fetch-with-cli` may help here https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli Caused by: no authentication methods succeeded "#]] }; // Explicit :22 should also work with bundled. p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bitflags = { git = "ssh://git@github.com:22/rust-lang/bitflags.git", tag = "1.3.2" } "#, ); p.cargo("fetch") .env("SSH_AUTH_SOCK", &bogus_auth_sock) .with_status(101) .with_stderr_data(expected) .run(); } #[cargo_test(container_test)] fn ssh_key_in_config() { // known_host in config works. let agent = Agent::launch(); let sshd = Container::new("sshd") .file(agent.authorized_keys()) .launch(); let hostkey = sshd.read_file("/etc/ssh/ssh_host_ecdsa_key.pub"); let url = ssh_repo_url(&sshd, "bar"); let p = foo_bar_project(&url); p.change_file( ".cargo/config.toml", &format!( r#" [net.ssh] known-hosts = ['127.0.0.1 {}'] "#, hostkey.trim() ), ); p.cargo("fetch") .env("SSH_AUTH_SOCK", &agent.sock) .with_stderr_data(str![[r#" [UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git` [LOCKING] 1 package to latest compatible version "#]]) .run(); } cargo-0.86.0/tests/testsuite/standard_lib.rs000064400000000000000000000610301046102023000172010ustar 00000000000000//! Tests for building the standard library (-Zbuild-std). //! //! These tests all use a "mock" standard library so that we don't have to //! rebuild the real one. There is a separate integration test `build-std` //! which builds the real thing, but that should be avoided if possible. use std::path::{Path, PathBuf}; use cargo_test_support::prelude::*; use cargo_test_support::registry::{Dependency, Package}; use cargo_test_support::ProjectBuilder; use cargo_test_support::{paths, project, rustc_host, str, Execs}; struct Setup { rustc_wrapper: PathBuf, real_sysroot: String, } fn setup() -> Setup { // Our mock sysroot requires a few packages from crates.io, so make sure // they're "published" to crates.io. Also edit their code a bit to make sure // that they have access to our custom crates with custom apis. Package::new("registry-dep-using-core", "1.0.0") .file( "src/lib.rs", " #![no_std] #[cfg(feature = \"mockbuild\")] pub fn custom_api() { } #[cfg(not(feature = \"mockbuild\"))] pub fn non_sysroot_api() { core::custom_api(); } ", ) .add_dep(Dependency::new("rustc-std-workspace-core", "*").optional(true)) .feature("mockbuild", &["rustc-std-workspace-core"]) .publish(); Package::new("registry-dep-using-alloc", "1.0.0") .file( "src/lib.rs", " #![no_std] extern crate alloc; #[cfg(feature = \"mockbuild\")] pub fn custom_api() { } #[cfg(not(feature = \"mockbuild\"))] pub fn non_sysroot_api() { core::custom_api(); alloc::custom_api(); } ", ) .add_dep(Dependency::new("rustc-std-workspace-core", "*").optional(true)) .add_dep(Dependency::new("rustc-std-workspace-alloc", "*").optional(true)) .feature( "mockbuild", &["rustc-std-workspace-core", "rustc-std-workspace-alloc"], ) .publish(); Package::new("registry-dep-using-std", "1.0.0") .file( "src/lib.rs", " #[cfg(feature = \"mockbuild\")] pub fn custom_api() { } #[cfg(not(feature = \"mockbuild\"))] pub fn non_sysroot_api() { std::custom_api(); } ", ) .add_dep(Dependency::new("rustc-std-workspace-std", "*").optional(true)) .feature("mockbuild", &["rustc-std-workspace-std"]) .publish(); let p = ProjectBuilder::new(paths::root().join("rustc-wrapper")) .file( "src/main.rs", r#" use std::process::Command; use std::env; fn main() { let mut args = env::args().skip(1).collect::>(); let is_sysroot_crate = env::var_os("RUSTC_BOOTSTRAP").is_some(); if is_sysroot_crate { args.push("--sysroot".to_string()); args.push(env::var("REAL_SYSROOT").unwrap()); } else if args.iter().any(|arg| arg == "--target") { // build-std target unit // // This `--sysroot` is here to disable the sysroot lookup, // to ensure nothing is required. // See https://github.com/rust-lang/wg-cargo-std-aware/issues/31 // for more information on this. // // FIXME: this is broken on x86_64-unknown-linux-gnu // due to https://github.com/rust-lang/rust/pull/124129, // because it requires lld in the sysroot. See // https://github.com/rust-lang/rust/issues/125246 for // more information. // args.push("--sysroot".to_string()); // args.push("/path/to/nowhere".to_string()); } else { // host unit, do not use sysroot } let ret = Command::new(&args[0]).args(&args[1..]).status().unwrap(); std::process::exit(ret.code().unwrap_or(1)); } "#, ) .build(); p.cargo("build").run(); Setup { rustc_wrapper: p.bin("foo"), real_sysroot: paths::sysroot(), } } fn enable_build_std(e: &mut Execs, setup: &Setup) { // First up, force Cargo to use our "mock sysroot" which mimics what // libstd looks like upstream. let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/testsuite/mock-std/library"); e.env("__CARGO_TESTS_ONLY_SRC_ROOT", &root); e.masquerade_as_nightly_cargo(&["build-std"]); // We do various shenanigans to ensure our "mock sysroot" actually links // with the real sysroot, so we don't have to actually recompile std for // each test. Perform all that logic here, namely: // // * RUSTC_WRAPPER - uses our shim executable built above to control rustc // * REAL_SYSROOT - used by the shim executable to swap out to the real // sysroot temporarily for some compilations // * RUST{,DOC}FLAGS - an extra `-L` argument to ensure we can always load // crates from the sysroot, but only indirectly through other crates. e.env("RUSTC_WRAPPER", &setup.rustc_wrapper); e.env("REAL_SYSROOT", &setup.real_sysroot); let libdir = format!("/lib/rustlib/{}/lib", rustc_host()); e.env( "RUSTFLAGS", format!("-Ldependency={}{}", setup.real_sysroot, libdir), ); e.env( "RUSTDOCFLAGS", format!("-Ldependency={}{}", setup.real_sysroot, libdir), ); } // Helper methods used in the tests below trait BuildStd: Sized { fn build_std(&mut self, setup: &Setup) -> &mut Self; fn build_std_arg(&mut self, setup: &Setup, arg: &str) -> &mut Self; fn target_host(&mut self) -> &mut Self; } impl BuildStd for Execs { fn build_std(&mut self, setup: &Setup) -> &mut Self { enable_build_std(self, setup); self.arg("-Zbuild-std"); self } fn build_std_arg(&mut self, setup: &Setup, arg: &str) -> &mut Self { enable_build_std(self, setup); self.arg(format!("-Zbuild-std={}", arg)); self } fn target_host(&mut self) -> &mut Self { self.arg("--target").arg(rustc_host()); self } } #[cargo_test(build_std_mock)] fn basic() { let setup = setup(); let p = project() .file( "src/main.rs", " fn main() { std::custom_api(); foo::f(); } #[test] fn smoke_bin_unit() { std::custom_api(); foo::f(); } ", ) .file( "src/lib.rs", " extern crate alloc; extern crate proc_macro; /// ``` /// foo::f(); /// ``` pub fn f() { core::custom_api(); std::custom_api(); alloc::custom_api(); proc_macro::custom_api(); } #[test] fn smoke_lib_unit() { std::custom_api(); f(); } ", ) .file( "tests/smoke.rs", " #[test] fn smoke_integration() { std::custom_api(); foo::f(); } ", ) .build(); p.cargo("check -v").build_std(&setup).target_host().run(); p.cargo("build").build_std(&setup).target_host().run(); p.cargo("run").build_std(&setup).target_host().run(); p.cargo("test").build_std(&setup).target_host().run(); } #[cargo_test(build_std_mock)] fn shared_std_dependency_rebuild() { let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); let setup = setup(); let p = project() .file( "Cargo.toml", format!( " [package] name = \"foo\" version = \"0.1.0\" edition = \"2021\" [build-dependencies] dep_test = {{ path = \"{}/tests/testsuite/mock-std/dep_test\" }} ", manifest_dir ) .as_str(), ) .file( "src/main.rs", r#" fn main() { println!("Hello, World!"); } "#, ) .file( "build.rs", r#" fn main() { println!("cargo::rerun-if-changed=build.rs"); } "#, ) .build(); p.cargo("build -v") .build_std(&setup) .target_host() .with_stderr_data(str![[r#" ... [RUNNING] `[..] rustc --crate-name dep_test [..]` ... [RUNNING] `[..] rustc --crate-name dep_test [..]` ... "#]]) .run(); // TODO: Because of the way in which std is resolved, it's mandatory that this is left commented // out as it will fail. This case should result in `dep_test` only being built once, however // it's still being built twice. This is a bug. // // p.cargo("build -v") // .build_std(&setup) // .with_stderr_does_not_contain(str![[r#" //... //[RUNNING] `[..] rustc --crate-name dep_test [..]` //... //[RUNNING] `[..] rustc --crate-name dep_test [..]` //... //"#]]) // .run(); } #[cargo_test(build_std_mock)] fn simple_lib_std() { let setup = setup(); let p = project().file("src/lib.rs", "").build(); p.cargo("build -v") .build_std(&setup) .target_host() .with_stderr_data(str![[r#" ... [RUNNING] `[..] rustc --crate-name std [..]` ... "#]]) .run(); // Check freshness. p.change_file("src/lib.rs", " "); p.cargo("build -v") .build_std(&setup) .target_host() .with_stderr_data(str![[r#" ... [FRESH] std v0.1.0 ([..]/tests/testsuite/mock-std/library/std) ... "#]]) .run(); } #[cargo_test(build_std_mock)] fn simple_bin_std() { let setup = setup(); let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("run -v").build_std(&setup).target_host().run(); } #[cargo_test(build_std_mock)] fn lib_nostd() { let setup = setup(); let p = project() .file( "src/lib.rs", r#" #![no_std] pub fn foo() { assert_eq!(u8::MIN, 0); } "#, ) .build(); p.cargo("build -v --lib") .build_std_arg(&setup, "core") .target_host() .with_stderr_does_not_contain("[..]libstd[..]") .run(); } #[cargo_test(build_std_mock)] fn check_core() { let setup = setup(); let p = project() .file("src/lib.rs", "#![no_std] fn unused_fn() {}") .build(); p.cargo("check -v") .build_std_arg(&setup, "core") .target_host() .with_stderr_data(str![[r#" ... [WARNING] function `unused_fn` is never used ... "#]]) .run(); } #[cargo_test(build_std_mock)] fn build_std_with_no_arg_for_core_only_target() { let has_rustup_aarch64_unknown_none = std::process::Command::new("rustup") .args(["target", "list", "--installed"]) .output() .ok() .map(|output| { String::from_utf8(output.stdout) .map(|stdout| stdout.contains("aarch64-unknown-none")) .unwrap_or_default() }) .unwrap_or_default(); if !has_rustup_aarch64_unknown_none { let msg = "to run this test, run `rustup target add aarch64-unknown-none --toolchain nightly`"; if cargo_util::is_ci() { panic!("{msg}"); } else { eprintln!("{msg}"); } return; } let setup = setup(); let p = project() .file( "src/lib.rs", r#" #![no_std] pub fn foo() { assert_eq!(u8::MIN, 0); } "#, ) .build(); p.cargo("build -v") .arg("--target=aarch64-unknown-none") .build_std(&setup) .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [DOWNLOADING] crates ... [DOWNLOADED] registry-dep-using-std v1.0.0 (registry `dummy-registry`) [DOWNLOADED] registry-dep-using-core v1.0.0 (registry `dummy-registry`) [DOWNLOADED] registry-dep-using-alloc v1.0.0 (registry `dummy-registry`) [COMPILING] compiler_builtins v0.1.0 ([..]/library/compiler_builtins) [COMPILING] core v0.1.0 ([..]/library/core) [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..] rustc --crate-name compiler_builtins [..]--target aarch64-unknown-none[..]` [RUNNING] `[..] rustc --crate-name core [..]--target aarch64-unknown-none[..]` [RUNNING] `[..] rustc --crate-name foo [..]--target aarch64-unknown-none[..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); p.cargo("clean").run(); // Also work for a mix of std and core-only targets, // though not sure how common it is... // // Note that we don't download std dependencies for the second call // because `-Zbuild-std` downloads them all also when building for core only. p.cargo("build -v") .arg("--target=aarch64-unknown-none") .target_host() .build_std(&setup) .with_stderr_data( str![[r#" [UPDATING] `dummy-registry` index [COMPILING] core v0.1.0 ([..]/library/core) [COMPILING] dep_test v0.1.0 ([..]/dep_test) [COMPILING] compiler_builtins v0.1.0 ([..]/library/compiler_builtins) [COMPILING] proc_macro v0.1.0 ([..]/library/proc_macro) [COMPILING] panic_unwind v0.1.0 ([..]/library/panic_unwind) [COMPILING] rustc-std-workspace-core v1.9.0 ([..]/library/rustc-std-workspace-core) [COMPILING] foo v0.0.1 ([ROOT]/foo) [COMPILING] registry-dep-using-core v1.0.0 [COMPILING] alloc v0.1.0 ([..]/library/alloc) [COMPILING] rustc-std-workspace-alloc v1.9.0 ([..]/library/rustc-std-workspace-alloc) [COMPILING] registry-dep-using-alloc v1.0.0 [COMPILING] std v0.1.0 ([..]/library/std) [RUNNING] `[..]rustc --crate-name compiler_builtins [..]--target aarch64-unknown-none[..]` [RUNNING] `[..]rustc --crate-name core [..]--target aarch64-unknown-none[..]` [RUNNING] `[..]rustc --crate-name foo [..]--target aarch64-unknown-none[..]` [RUNNING] `[..]rustc --crate-name core [..]--target [HOST_TARGET][..]` [RUNNING] `[..]rustc --crate-name dep_test [..]--target [HOST_TARGET][..]` [RUNNING] `[..]rustc --crate-name proc_macro [..]--target [HOST_TARGET][..]` [RUNNING] `[..]rustc --crate-name panic_unwind [..]--target [HOST_TARGET][..]` [RUNNING] `[..]rustc --crate-name compiler_builtins [..]--target [HOST_TARGET][..]` [RUNNING] `[..]rustc --crate-name rustc_std_workspace_core [..]--target [HOST_TARGET][..]` [RUNNING] `[..]rustc --crate-name registry_dep_using_core [..]--target [HOST_TARGET][..]` [RUNNING] `[..]rustc --crate-name alloc [..]--target [HOST_TARGET][..]` [RUNNING] `[..]rustc --crate-name rustc_std_workspace_alloc [..]--target [HOST_TARGET][..]` [RUNNING] `[..]rustc --crate-name registry_dep_using_alloc [..]--target [HOST_TARGET][..]` [RUNNING] `[..]rustc --crate-name std [..]--target [HOST_TARGET][..]` [RUNNING] `[..]rustc --crate-name foo [..]--target [HOST_TARGET][..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test(build_std_mock)] fn depend_same_as_std() { let setup = setup(); let p = project() .file( "src/lib.rs", r#" pub fn f() { registry_dep_using_core::non_sysroot_api(); registry_dep_using_alloc::non_sysroot_api(); registry_dep_using_std::non_sysroot_api(); } "#, ) .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [dependencies] registry-dep-using-core = "1.0" registry-dep-using-alloc = "1.0" registry-dep-using-std = "1.0" "#, ) .build(); p.cargo("build -v").build_std(&setup).target_host().run(); } #[cargo_test(build_std_mock)] fn test() { let setup = setup(); let p = project() .file( "src/lib.rs", r#" #[cfg(test)] mod tests { #[test] fn it_works() { assert_eq!(2 + 2, 4); } } "#, ) .build(); p.cargo("test -v") .build_std(&setup) .target_host() .with_stdout_data(str![[r#" running 1 test test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s ... "#]]) .run(); } #[cargo_test(build_std_mock)] fn target_proc_macro() { let setup = setup(); let p = project() .file( "src/lib.rs", r#" extern crate proc_macro; pub fn f() { let _ts = proc_macro::TokenStream::new(); } "#, ) .build(); p.cargo("build -v").build_std(&setup).target_host().run(); } #[cargo_test(build_std_mock)] fn bench() { let setup = setup(); let p = project() .file( "src/lib.rs", r#" #![feature(test)] extern crate test; #[bench] fn b1(b: &mut test::Bencher) { b.iter(|| ()) } "#, ) .build(); p.cargo("bench -v").build_std(&setup).target_host().run(); } #[cargo_test(build_std_mock)] fn doc() { let setup = setup(); let p = project() .file( "src/lib.rs", r#" /// Doc pub fn f() -> Result<(), ()> {Ok(())} "#, ) .build(); p.cargo("doc -v").build_std(&setup).target_host().run(); } #[cargo_test(build_std_mock)] fn check_std() { let setup = setup(); let p = project() .file( "src/lib.rs", " extern crate core; extern crate alloc; extern crate proc_macro; pub fn f() {} ", ) .file("src/main.rs", "fn main() {}") .file( "tests/t1.rs", r#" #[test] fn t1() { assert_eq!(1, 2); } "#, ) .build(); p.cargo("check -v --all-targets") .build_std(&setup) .target_host() .run(); p.cargo("check -v --all-targets --profile=test") .build_std(&setup) .target_host() .run(); } #[cargo_test(build_std_mock)] fn doctest() { let setup = setup(); let p = project() .file( "src/lib.rs", r#" /// Doc /// ``` /// std::custom_api(); /// ``` pub fn f() {} "#, ) .build(); p.cargo("test --doc -v -Zdoctest-xcompile") .build_std(&setup) .with_stdout_data(str![[r#" running 1 test test src/lib.rs - f (line 3) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .target_host() .run(); } #[cargo_test(build_std_mock)] fn no_implicit_alloc() { // Demonstrate that alloc is not implicitly in scope. let setup = setup(); let p = project() .file( "src/lib.rs", r#" pub fn f() { let _: Vec = alloc::vec::Vec::new(); } "#, ) .build(); p.cargo("build -v") .build_std(&setup) .target_host() .with_stderr_data(str![[r#" ... error[E0433]: failed to resolve: use of undeclared crate or module `alloc` ... "#]]) .with_status(101) .run(); } #[cargo_test(build_std_mock)] fn macro_expanded_shadow() { // This tests a bug caused by the previous use of `--extern` to directly // load sysroot crates. This necessitated the switch to `--sysroot` to // retain existing behavior. See // https://github.com/rust-lang/wg-cargo-std-aware/issues/40 for more // detail. let setup = setup(); let p = project() .file( "src/lib.rs", r#" macro_rules! a { () => (extern crate std as alloc;) } a!(); "#, ) .build(); p.cargo("build -v").build_std(&setup).target_host().run(); } #[cargo_test(build_std_mock)] fn ignores_incremental() { // Incremental is not really needed for std, make sure it is disabled. // Incremental also tends to have bugs that affect std libraries more than // any other crate. let setup = setup(); let p = project().file("src/lib.rs", "").build(); p.cargo("build") .env("CARGO_INCREMENTAL", "1") .build_std(&setup) .target_host() .run(); let incremental: Vec<_> = p .glob(format!("target/{}/debug/incremental/*", rustc_host())) .map(|e| e.unwrap()) .collect(); assert_eq!(incremental.len(), 1); assert!(incremental[0] .file_name() .unwrap() .to_str() .unwrap() .starts_with("foo-")); } #[cargo_test(build_std_mock)] fn cargo_config_injects_compiler_builtins() { let setup = setup(); let p = project() .file( "src/lib.rs", r#" #![no_std] pub fn foo() { assert_eq!(u8::MIN, 0); } "#, ) .file( ".cargo/config.toml", r#" [unstable] build-std = ['core'] "#, ) .build(); let mut build = p.cargo("build -v --lib"); enable_build_std(&mut build, &setup); build .target_host() .with_stderr_does_not_contain("[..]libstd[..]") .run(); } #[cargo_test(build_std_mock)] fn different_features() { let setup = setup(); let p = project() .file( "src/lib.rs", " pub fn foo() { std::conditional_function(); } ", ) .build(); p.cargo("build") .build_std(&setup) .arg("-Zbuild-std-features=feature1") .target_host() .run(); } #[cargo_test(build_std_mock)] fn no_roots() { // Checks for a bug where it would panic if there are no roots. let setup = setup(); let p = project().file("tests/t1.rs", "").build(); p.cargo("build") .build_std(&setup) .target_host() .with_stderr_data(str![[r#" ... [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(build_std_mock)] fn proc_macro_only() { // Checks for a bug where it would panic if building a proc-macro only let setup = setup(); let p = project() .file( "Cargo.toml", r#" [package] name = "pm" version = "0.1.0" [lib] proc-macro = true "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .build_std(&setup) .target_host() .with_stderr_data(str![[r#" ... [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test(build_std_mock)] fn fetch() { let setup = setup(); let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("fetch") .build_std(&setup) .target_host() .with_stderr_contains("[DOWNLOADED] [..]") .run(); p.cargo("build") .build_std(&setup) .target_host() .with_stderr_does_not_contain("[DOWNLOADED] [..]") .run(); } cargo-0.86.0/tests/testsuite/test.rs000064400000000000000000004141141046102023000155370ustar 00000000000000//! Tests for the `cargo test` command. use std::fs; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{ basic_bin_manifest, basic_lib_manifest, basic_manifest, cargo_exe, project, str, }; use cargo_test_support::{cross_compile, paths}; use cargo_test_support::{rustc_host, rustc_host_env, sleep_ms}; use cargo_util::paths::dylib_path_envvar; #[cargo_test] fn cargo_test_simple() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" fn hello() -> &'static str { "hello" } pub fn main() { println!("{}", hello()) } #[test] fn test_hello() { assert_eq!(hello(), "hello") } "#, ) .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" hello "#]]) .run(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/main.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" ... test test_hello ... ok ... "#]]) .run(); } #[cargo_test] fn cargo_test_release() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } "#, ) .file( "src/lib.rs", r#" extern crate bar; pub fn foo() { bar::bar(); } #[test] fn test() { foo(); } "#, ) .file( "tests/test.rs", r#" extern crate foo; #[test] fn test() { foo::foo(); } "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("test -v --release") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [RUNNING] `rustc [..]-C opt-level=3 [..]` [COMPILING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..]-C opt-level=3 [..]` [RUNNING] `rustc [..]-C opt-level=3 [..]` [RUNNING] `rustc [..]-C opt-level=3 [..]` [FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/release/deps/foo-[HASH][EXE]` [RUNNING] `[ROOT]/foo/target/release/deps/test-[HASH][EXE]` [DOCTEST] foo [RUNNING] `rustdoc [..]--test src/lib.rs[..]` "#]]) .with_stdout_data( str![[r#" test test ... ok test test ... ok running 0 tests ... "#]] .unordered(), ) .run(); } #[cargo_test] fn cargo_test_overflow_checks() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = [] [[bin]] name = "foo" [profile.release] overflow-checks = true "#, ) .file( "src/foo.rs", r#" use std::panic; pub fn main() { let r = panic::catch_unwind(|| { [1, i32::MAX].iter().sum::(); }); assert!(r.is_err()); } "#, ) .build(); p.cargo("build --release").run(); assert!(p.release_bin("foo").is_file()); p.process(&p.release_bin("foo")).with_stdout_data("").run(); } #[cargo_test] fn cargo_test_quiet_with_harness() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [[test]] name = "foo" path = "src/foo.rs" harness = true "#, ) .file( "src/foo.rs", r#" fn main() {} #[test] fn test_hello() {} "#, ) .build(); p.cargo("test -q") .with_stdout_data(str![[r#" running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .with_stderr_data("") .run(); } #[cargo_test] fn cargo_test_quiet_no_harness() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [[bin]] name = "foo" test = false [[test]] name = "foo" path = "src/main.rs" harness = false "#, ) .file( "src/main.rs", r#" fn main() {} #[test] fn test_hello() {} "#, ) .build(); p.cargo("test -q") .with_stdout_data("") .with_stderr_data("") .run(); } #[cargo_test] fn cargo_doc_test_quiet() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] "#, ) .file( "src/lib.rs", r#" /// ``` /// let result = foo::add(2, 3); /// assert_eq!(result, 5); /// ``` pub fn add(a: i32, b: i32) -> i32 { a + b } /// ``` /// let result = foo::div(10, 2); /// assert_eq!(result, 5); /// ``` /// /// # Panics /// /// The function panics if the second argument is zero. /// /// ```rust,should_panic /// // panics on division by zero /// foo::div(10, 0); /// ``` pub fn div(a: i32, b: i32) -> i32 { if b == 0 { panic!("Divide-by-zero error"); } a / b } #[test] fn test_hello() {} "#, ) .build(); p.cargo("test -q") .with_stdout_data(str![[r#" running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 3 tests ... test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .with_stderr_data("") .run(); } #[cargo_test] fn cargo_test_verbose() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" fn main() {} #[test] fn test_hello() {} "#, ) .build(); p.cargo("test -v hello") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc [..] src/main.rs [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE] hello` "#]]) .with_stdout_data(str![[r#" ... test test_hello ... ok ... "#]]) .run(); } #[cargo_test] fn many_similar_names() { let p = project() .file( "src/lib.rs", " pub fn foo() {} #[test] fn lib_test() {} ", ) .file( "src/main.rs", " extern crate foo; fn main() {} #[test] fn bin_test() { foo::foo() } ", ) .file( "tests/foo.rs", r#" extern crate foo; #[test] fn test_test() { foo::foo() } "#, ) .build(); p.cargo("test -v") .with_stdout_data( str![[r#" test bin_test ... ok test lib_test ... ok test test_test ... ok ... "#]] .unordered(), ) .run(); } #[cargo_test] fn cargo_test_failing_test_in_bin() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file( "src/main.rs", r#" fn hello() -> &'static str { "hello" } pub fn main() { println!("{}", hello()) } #[test] fn test_hello() { assert_eq!(hello(), "nope", "NOPE!") } "#, ) .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" hello "#]]) .run(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/main.rs (target/debug/deps/foo-[HASH][EXE]) [ERROR] test failed, to rerun pass `--bin foo` "#]]) .with_stdout_data("...\n[..]NOPE![..]\n...") .with_status(101) .run(); } #[cargo_test] fn cargo_test_failing_test_in_test() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/main.rs", r#"pub fn main() { println!("hello"); }"#) .file( "tests/footest.rs", r#"#[test] fn test_hello() { assert!(false, "FALSE!") }"#, ) .build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); p.process(&p.bin("foo")) .with_stdout_data(str![[r#" hello "#]]) .run(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/main.rs (target/debug/deps/foo-[HASH][EXE]) [RUNNING] tests/footest.rs (target/debug/deps/footest-[HASH][EXE]) [ERROR] test failed, to rerun pass `--test footest` "#]]) .with_stdout_data( str![[r#" ... running 0 tests ... running 1 test test test_hello ... FAILED ... [..]FALSE![..] ... "#]] .unordered(), ) .with_status(101) .run(); } #[cargo_test] fn cargo_test_failing_test_in_lib() { let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file( "src/lib.rs", r#"#[test] fn test_hello() { assert!(false, "FALSE!") }"#, ) .build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [ERROR] test failed, to rerun pass `--lib` "#]]) .with_stdout_data(str![[r#" ... test test_hello ... FAILED ... [..]FALSE![..] ... "#]]) .with_status(101) .run(); } #[cargo_test] fn test_with_lib_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[bin]] name = "baz" path = "src/main.rs" "#, ) .file( "src/lib.rs", r#" /// /// ```rust /// extern crate foo; /// fn main() { /// println!("{:?}", foo::foo()); /// } /// ``` /// pub fn foo(){} #[test] fn lib_test() {} "#, ) .file( "src/main.rs", " #[allow(unused_extern_crates)] extern crate foo; fn main() {} #[test] fn bin_test() {} ", ) .build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [RUNNING] unittests src/main.rs (target/debug/deps/baz-[HASH][EXE]) [DOCTEST] foo "#]]) .with_stdout_data( str![[r#" test lib_test ... ok test bin_test ... ok test [..] ... ok ... "#]] .unordered(), ) .run(); } #[cargo_test] fn test_with_deep_lib_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.bar] path = "../bar" "#, ) .file( "src/lib.rs", " #[cfg(test)] extern crate bar; /// ``` /// foo::foo(); /// ``` pub fn foo() {} #[test] fn bar_test() { bar::bar(); } ", ) .build(); let _p2 = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("src/lib.rs", "pub fn bar() {} #[test] fn foo_test() {}") .build(); p.cargo("test") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.0.1 ([ROOT]/bar) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "#]]) .with_stdout_data( str![[r#" test bar_test ... ok test [..] ... ok ... "#]] .unordered(), ) .run(); } #[cargo_test] fn external_test_explicit() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[test]] name = "test" path = "src/test.rs" "#, ) .file( "src/lib.rs", r#" pub fn get_hello() -> &'static str { "Hello" } #[test] fn internal_test() {} "#, ) .file( "src/test.rs", r#" extern crate foo; #[test] fn external_test() { assert_eq!(foo::get_hello(), "Hello") } "#, ) .build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [RUNNING] src/test.rs (target/debug/deps/test-[HASH][EXE]) [DOCTEST] foo "#]]) .with_stdout_data( str![[r#" test internal_test ... ok test external_test ... ok running 0 tests ... "#]] .unordered(), ) .run(); } #[cargo_test] fn external_test_named_test() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[test]] name = "test" "#, ) .file("src/lib.rs", "") .file("tests/test.rs", "#[test] fn foo() {}") .build(); p.cargo("test").run(); } #[cargo_test] fn external_test_implicit() { let p = project() .file( "src/lib.rs", r#" pub fn get_hello() -> &'static str { "Hello" } #[test] fn internal_test() {} "#, ) .file( "tests/external.rs", r#" extern crate foo; #[test] fn external_test() { assert_eq!(foo::get_hello(), "Hello") } "#, ) .build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [RUNNING] tests/external.rs (target/debug/deps/external-[HASH][EXE]) [DOCTEST] foo "#]]) .with_stdout_data( str![[r#" test internal_test ... ok test external_test ... ok running 0 tests ... "#]] .unordered(), ) .run(); } #[cargo_test] fn dont_run_examples() { let p = project() .file("src/lib.rs", "") .file( "examples/dont-run-me-i-will-fail.rs", r#" fn main() { panic!("Examples should not be run by 'cargo test'"); } "#, ) .build(); p.cargo("test").run(); } #[cargo_test] fn pass_through_escaped() { let p = project() .file( "src/lib.rs", " /// ```rust /// assert!(foo::foo()); /// ``` pub fn foo() -> bool { true } /// ```rust /// assert!(!foo::bar()); /// ``` pub fn bar() -> bool { false } #[test] fn test_foo() { assert!(foo()); } #[test] fn test_bar() { assert!(!bar()); } ", ) .build(); p.cargo("test -- bar") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "#]]) .with_stdout_data(str![[r#" ... running 1 test test test_bar ... ok ... "#]]) .run(); p.cargo("test -- foo") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "#]]) .with_stdout_data(str![[r#" ... running 1 test test test_foo ... ok ... "#]]) .run(); p.cargo("test -- foo bar") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "#]]) .with_stdout_data( str![[r#" running 2 tests test test_foo ... ok test test_bar ... ok ... "#]] .unordered(), ) .run(); } // Unlike `pass_through_escaped`, doctests won't run when using `testname` as an optimization #[cargo_test] fn pass_through_testname() { let p = project() .file( "src/lib.rs", " /// ```rust /// assert!(foo::foo()); /// ``` pub fn foo() -> bool { true } /// ```rust /// assert!(!foo::bar()); /// ``` pub fn bar() -> bool { false } #[test] fn test_foo() { assert!(foo()); } #[test] fn test_bar() { assert!(!bar()); } ", ) .build(); p.cargo("test bar") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" ... running 1 test test test_bar ... ok ... "#]]) .run(); p.cargo("test foo") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" ... running 1 test test test_foo ... ok ... "#]]) .run(); p.cargo("test foo -- bar") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data( str![[r#" running 2 tests test test_bar ... ok test test_foo ... ok ... "#]] .unordered(), ) .run(); } // Regression test for running cargo-test twice with // tests in an rlib #[cargo_test] fn cargo_test_twice() { let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file( "src/foo.rs", r#" #![crate_type = "rlib"] #[test] fn dummy_test() { } "#, ) .build(); for _ in 0..2 { p.cargo("test").run(); } } #[cargo_test] fn lib_bin_same_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] name = "foo" [[bin]] name = "foo" "#, ) .file("src/lib.rs", "#[test] fn lib_test() {}") .file( "src/main.rs", " #[allow(unused_extern_crates)] extern crate foo; #[test] fn bin_test() {} ", ) .build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [RUNNING] unittests src/main.rs (target/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "#]]) .with_stdout_data( str![[r#" test lib_test ... ok test bin_test ... ok running 0 tests ... "#]] .unordered(), ) .run(); } #[cargo_test] fn lib_with_standard_name() { let p = project() .file("Cargo.toml", &basic_manifest("syntax", "0.0.1")) .file( "src/lib.rs", " /// ``` /// syntax::foo(); /// ``` pub fn foo() {} #[test] fn foo_test() {} ", ) .file( "tests/test.rs", " extern crate syntax; #[test] fn test() { syntax::foo() } ", ) .build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] syntax v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/syntax-[HASH][EXE]) [RUNNING] tests/test.rs (target/debug/deps/test-[HASH][EXE]) [DOCTEST] syntax "#]]) .with_stdout_data( str![[r#" test foo_test ... ok test test ... ok test [..] ... ok ... "#]] .unordered(), ) .run(); } #[cargo_test] fn lib_with_standard_name2() { let p = project() .file( "Cargo.toml", r#" [package] name = "syntax" version = "0.0.1" edition = "2015" authors = [] [lib] name = "syntax" test = false doctest = false "#, ) .file("src/lib.rs", "pub fn foo() {}") .file( "src/main.rs", " extern crate syntax; fn main() {} #[test] fn test() { syntax::foo() } ", ) .build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] syntax v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/main.rs (target/debug/deps/syntax-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" ... test test ... ok ... "#]]) .run(); } #[cargo_test] fn lib_without_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "syntax" version = "0.0.1" edition = "2015" authors = [] [lib] test = false doctest = false "#, ) .file("src/lib.rs", "pub fn foo() {}") .file( "src/main.rs", " extern crate syntax; fn main() {} #[test] fn test() { syntax::foo() } ", ) .build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] syntax v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/main.rs (target/debug/deps/syntax-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" ... test test ... ok ... "#]]) .run(); } #[cargo_test] fn bin_without_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "syntax" version = "0.0.1" edition = "2015" authors = [] [lib] test = false doctest = false [[bin]] path = "src/main.rs" "#, ) .file("src/lib.rs", "pub fn foo() {}") .file( "src/main.rs", " extern crate syntax; fn main() {} #[test] fn test() { syntax::foo() } ", ) .build(); p.cargo("test") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: binary target bin.name is required "#]]) .run(); } #[cargo_test] fn bench_without_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "syntax" version = "0.0.1" edition = "2015" authors = [] [lib] test = false doctest = false [[bench]] path = "src/bench.rs" "#, ) .file("src/lib.rs", "pub fn foo() {}") .file( "src/main.rs", " extern crate syntax; fn main() {} #[test] fn test() { syntax::foo() } ", ) .file( "src/bench.rs", " #![feature(test)] extern crate syntax; extern crate test; #[bench] fn external_bench(_b: &mut test::Bencher) {} ", ) .build(); p.cargo("test") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: benchmark target bench.name is required "#]]) .run(); } #[cargo_test] fn test_without_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "syntax" version = "0.0.1" edition = "2015" authors = [] [lib] test = false doctest = false [[test]] path = "src/test.rs" "#, ) .file( "src/lib.rs", r#" pub fn foo() {} pub fn get_hello() -> &'static str { "Hello" } "#, ) .file( "src/main.rs", " extern crate syntax; fn main() {} #[test] fn test() { syntax::foo() } ", ) .file( "src/test.rs", r#" extern crate syntax; #[test] fn external_test() { assert_eq!(syntax::get_hello(), "Hello") } "#, ) .build(); p.cargo("test") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: test target test.name is required "#]]) .run(); } #[cargo_test] fn example_without_name() { let p = project() .file( "Cargo.toml", r#" [package] name = "syntax" version = "0.0.1" edition = "2015" authors = [] [lib] test = false doctest = false [[example]] path = "examples/example.rs" "#, ) .file("src/lib.rs", "pub fn foo() {}") .file( "src/main.rs", " extern crate syntax; fn main() {} #[test] fn test() { syntax::foo() } ", ) .file( "examples/example.rs", r#" extern crate syntax; fn main() { println!("example1"); } "#, ) .build(); p.cargo("test") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: example target example.name is required "#]]) .run(); } #[cargo_test] fn bin_there_for_integration() { let p = project() .file( "src/main.rs", " fn main() { std::process::exit(101); } #[test] fn main_test() {} ", ) .file( "tests/foo.rs", r#" use std::process::Command; #[test] fn test_test() { let status = Command::new("target/debug/foo").status().unwrap(); assert_eq!(status.code(), Some(101)); } "#, ) .build(); p.cargo("test -v") .with_stdout_data( str![[r#" test main_test ... ok test test_test ... ok ... "#]] .unordered(), ) .run(); } #[cargo_test] fn test_dylib() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] name = "foo" crate-type = ["dylib"] [dependencies.bar] path = "bar" "#, ) .file( "src/lib.rs", r#" extern crate bar as the_bar; pub fn bar() { the_bar::baz(); } #[test] fn foo() { bar(); } "#, ) .file( "tests/test.rs", r#" extern crate foo as the_foo; #[test] fn foo() { the_foo::bar(); } "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [lib] name = "bar" crate-type = ["dylib"] "#, ) .file("bar/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("test") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [RUNNING] tests/test.rs (target/debug/deps/test-[HASH][EXE]) "#]]) .with_stdout_data( str![[r#" test foo ... ok test foo ... ok ... "#]] .unordered(), ) .run(); p.root().move_into_the_past(); p.cargo("test") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [RUNNING] tests/test.rs (target/debug/deps/test-[HASH][EXE]) "#]]) .with_stdout_data( str![[r#" test foo ... ok test foo ... ok ... "#]] .unordered(), ) .run(); } #[cargo_test] fn test_twice_with_build_cmd() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "#[test] fn foo() {}") .build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "#]]) .with_stdout_data( str![[r#" test foo ... ok running 0 tests ... "#]] .unordered(), ) .run(); p.cargo("test") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "#]]) .with_stdout_data( str![[r#" test foo ... ok running 0 tests ... "#]] .unordered(), ) .run(); } #[cargo_test] fn test_then_build() { let p = project().file("src/lib.rs", "#[test] fn foo() {}").build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "#]]) .with_stdout_data( str![[r#" test foo ... ok running 0 tests ... "#]] .unordered(), ) .run(); p.cargo("build") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn test_no_run() { let p = project() .file("src/lib.rs", "#[test] fn foo() { panic!() }") .build(); p.cargo("test --no-run") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .run(); } #[cargo_test] fn test_no_run_emit_json() { let p = project() .file("src/lib.rs", "#[test] fn foo() { panic!() }") .build(); p.cargo("test --no-run --message-format json") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn test_run_specific_bin_target() { let prj = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[bin]] name="bin1" path="src/bin1.rs" [[bin]] name="bin2" path="src/bin2.rs" "#, ) .file("src/bin1.rs", "#[test] fn test1() { }") .file("src/bin2.rs", "#[test] fn test2() { }") .build(); prj.cargo("test --bin bin2") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/bin2.rs (target/debug/deps/bin2-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" ... test test2 ... ok ... "#]]) .run(); } #[cargo_test] fn test_run_implicit_bin_target() { let prj = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[bin]] name="mybin" path="src/mybin.rs" "#, ) .file( "src/mybin.rs", "#[test] fn test_in_bin() { } fn main() { panic!(\"Don't execute me!\"); }", ) .file("tests/mytest.rs", "#[test] fn test_in_test() { }") .file("benches/mybench.rs", "#[test] fn test_in_bench() { }") .file( "examples/myexm.rs", "#[test] fn test_in_exm() { } fn main() { panic!(\"Don't execute me!\"); }", ) .build(); prj.cargo("test --bins") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/mybin.rs (target/debug/deps/mybin-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" ... test test_in_bin ... ok ... "#]]) .run(); } #[cargo_test] fn test_run_specific_test_target() { let prj = project() .file("src/bin/a.rs", "fn main() { }") .file("src/bin/b.rs", "#[test] fn test_b() { } fn main() { }") .file("tests/a.rs", "#[test] fn test_a() { }") .file("tests/b.rs", "#[test] fn test_b() { }") .build(); prj.cargo("test --test b") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] tests/b.rs (target/debug/deps/b-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" ... test test_b ... ok ... "#]]) .run(); } #[cargo_test] fn test_run_implicit_test_target() { let prj = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[bin]] name="mybin" path="src/mybin.rs" "#, ) .file( "src/mybin.rs", "#[test] fn test_in_bin() { } fn main() { panic!(\"Don't execute me!\"); }", ) .file("tests/mytest.rs", "#[test] fn test_in_test() { }") .file("benches/mybench.rs", "#[test] fn test_in_bench() { }") .file( "examples/myexm.rs", "fn main() { compile_error!(\"Don't build me!\"); }", ) .build(); prj.cargo("test --tests") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/mybin.rs (target/debug/deps/mybin-[HASH][EXE]) [RUNNING] tests/mytest.rs (target/debug/deps/mytest-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" ... test test_in_test ... ok ... "#]]) .run(); } #[cargo_test] fn test_run_implicit_bench_target() { let prj = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[bin]] name="mybin" path="src/mybin.rs" "#, ) .file( "src/mybin.rs", "#[test] fn test_in_bin() { } fn main() { panic!(\"Don't execute me!\"); }", ) .file("tests/mytest.rs", "#[test] fn test_in_test() { }") .file("benches/mybench.rs", "#[test] fn test_in_bench() { }") .file( "examples/myexm.rs", "fn main() { compile_error!(\"Don't build me!\"); }", ) .build(); prj.cargo("test --benches") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/mybin.rs (target/debug/deps/mybin-[HASH][EXE]) [RUNNING] benches/mybench.rs (target/debug/deps/mybench-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" ... test test_in_bench ... ok ... "#]]) .run(); } #[cargo_test] fn test_run_implicit_example_target() { let prj = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[bin]] name = "mybin" path = "src/mybin.rs" [[example]] name = "myexm1" [[example]] name = "myexm2" test = true "#, ) .file( "src/mybin.rs", "#[test] fn test_in_bin() { } fn main() { panic!(\"Don't execute me!\"); }", ) .file("tests/mytest.rs", "#[test] fn test_in_test() { }") .file("benches/mybench.rs", "#[test] fn test_in_bench() { }") .file( "examples/myexm1.rs", "#[test] fn test_in_exm() { } fn main() { panic!(\"Don't execute me!\"); }", ) .file( "examples/myexm2.rs", "#[test] fn test_in_exm() { } fn main() { panic!(\"Don't execute me!\"); }", ) .build(); // Compiles myexm1 as normal, but does not run it. prj.cargo("test -v") .with_stderr_contains("[RUNNING] `rustc [..]myexm1.rs [..]--crate-type bin[..]") .with_stderr_contains("[RUNNING] `rustc [..]myexm2.rs [..]--test[..]") .with_stderr_does_not_contain("[RUNNING] [..]myexm1-[..]") .with_stderr_contains("[RUNNING] [..]target/debug/examples/myexm2-[..]") .run(); // Only tests myexm2. prj.cargo("test --tests") .with_stderr_does_not_contain("[RUNNING] [..]myexm1-[..]") .with_stderr_contains("[RUNNING] [..]target/debug/examples/myexm2-[..]") .run(); // Tests all examples. prj.cargo("test --examples") .with_stderr_data(str![[r#" ... [RUNNING] unittests examples/myexm1.rs (target/debug/examples/myexm1-[HASH][EXE]) [RUNNING] unittests examples/myexm2.rs (target/debug/examples/myexm2-[HASH][EXE]) ... "#]]) .run(); // Test an example, even without `test` set. prj.cargo("test --example myexm1") .with_stderr_data(str![[r#" ... [RUNNING] unittests examples/myexm1.rs (target/debug/examples/myexm1-[HASH][EXE]) ... "#]]) .run(); // Tests all examples. prj.cargo("test --all-targets") .with_stderr_data(str![[r#" ... [RUNNING] unittests examples/myexm1.rs (target/debug/examples/myexm1-[HASH][EXE]) [RUNNING] unittests examples/myexm2.rs (target/debug/examples/myexm2-[HASH][EXE]) ... "#]]) .run(); } #[cargo_test] fn test_filtered_excludes_compiling_examples() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[bin]] name = "mybin" test = false "#, ) .file( "src/lib.rs", "#[cfg(test)] mod tests { #[test] fn test_in_lib() { } }", ) .file( "src/bin/mybin.rs", "#[test] fn test_in_bin() { } fn main() { panic!(\"Don't execute me!\"); }", ) .file("tests/mytest.rs", "#[test] fn test_in_test() { }") .file( "benches/mybench.rs", "#[test] fn test_in_bench() { assert!(false) }", ) .file( "examples/myexm1.rs", "#[test] fn test_in_exm() { assert!(false) } fn main() { panic!(\"Don't execute me!\"); }", ) .build(); p.cargo("test -v test_in_") .with_stdout_data(str![[r#" running 1 test test tests::test_in_lib ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test test_in_test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .with_stderr_data( str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..] --crate-type lib [..]` [RUNNING] `rustc --crate-name foo --edition=2015 src/lib.rs [..] --test [..]` [RUNNING] `rustc --crate-name mybin --edition=2015 src/bin/mybin.rs [..] --crate-type bin [..]` [RUNNING] `rustc --crate-name mytest --edition=2015 tests/mytest.rs [..] --test [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE] test_in_` [RUNNING] `[ROOT]/foo/target/debug/deps/mytest-[HASH][EXE] test_in_` "#]] .unordered(), ) .with_stderr_does_not_contain("[RUNNING][..]rustc[..]myexm1[..]") .with_stderr_does_not_contain("[RUNNING][..]deps/mybin-[..] test_in_") .run(); } #[cargo_test] fn test_no_harness() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [[bin]] name = "foo" test = false [[test]] name = "bar" path = "foo.rs" harness = false "#, ) .file("src/main.rs", "fn main() {}") .file("foo.rs", "fn main() {}") .build(); p.cargo("test -- --nocapture") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] foo.rs (target/debug/deps/bar-[HASH][EXE]) "#]]) .run(); } #[cargo_test] fn selective_testing() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.d1] path = "d1" [dependencies.d2] path = "d2" [lib] name = "foo" doctest = false "#, ) .file("src/lib.rs", "") .file( "d1/Cargo.toml", r#" [package] name = "d1" version = "0.0.1" edition = "2015" authors = [] [lib] name = "d1" doctest = false "#, ) .file("d1/src/lib.rs", "") .file( "d1/src/main.rs", "#[allow(unused_extern_crates)] extern crate d1; fn main() {}", ) .file( "d2/Cargo.toml", r#" [package] name = "d2" version = "0.0.1" edition = "2015" authors = [] [lib] name = "d2" doctest = false "#, ) .file("d2/src/lib.rs", "") .file( "d2/src/main.rs", "#[allow(unused_extern_crates)] extern crate d2; fn main() {}", ); let p = p.build(); println!("d1"); p.cargo("test -p d1") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [COMPILING] d1 v0.0.1 ([ROOT]/foo/d1) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/d1-[HASH][EXE]) [RUNNING] unittests src/main.rs (target/debug/deps/d1-[HASH][EXE]) "#]]) .with_stdout_data( str![[r#" running 0 tests running 0 tests ... "#]] .unordered(), ) .run(); println!("d2"); p.cargo("test -p d2") .with_stderr_data(str![[r#" [COMPILING] d2 v0.0.1 ([ROOT]/foo/d2) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/d2-[HASH][EXE]) [RUNNING] unittests src/main.rs (target/debug/deps/d2-[HASH][EXE]) "#]]) .with_stdout_data( str![[r#" running 0 tests running 0 tests ... "#]] .unordered(), ) .run(); println!("whole"); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" ... running 0 tests ... "#]]) .run(); } #[cargo_test] fn almost_cyclic_but_not_quite() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dev-dependencies.b] path = "b" [dev-dependencies.c] path = "c" "#, ) .file( "src/lib.rs", r#" #[cfg(test)] extern crate b; #[cfg(test)] extern crate c; "#, ) .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.0.1" edition = "2015" authors = [] [dependencies.foo] path = ".." "#, ) .file( "b/src/lib.rs", r#" #[allow(unused_extern_crates)] extern crate foo; "#, ) .file("c/Cargo.toml", &basic_manifest("c", "0.0.1")) .file("c/src/lib.rs", "") .build(); p.cargo("build").run(); p.cargo("test").run(); } #[cargo_test] fn build_then_selective_test() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.b] path = "b" "#, ) .file( "src/lib.rs", "#[allow(unused_extern_crates)] extern crate b;", ) .file( "src/main.rs", r#" #[allow(unused_extern_crates)] extern crate b; #[allow(unused_extern_crates)] extern crate foo; fn main() {} "#, ) .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/lib.rs", "") .build(); p.cargo("build").run(); p.root().move_into_the_past(); p.cargo("test -p b").run(); } #[cargo_test] fn example_dev_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dev-dependencies.bar] path = "bar" "#, ) .file("src/lib.rs", "") .file("examples/e1.rs", "extern crate bar; fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file( "bar/src/lib.rs", r#" // make sure this file takes awhile to compile macro_rules! f0( () => (1) ); macro_rules! f1( () => ({(f0!()) + (f0!())}) ); macro_rules! f2( () => ({(f1!()) + (f1!())}) ); macro_rules! f3( () => ({(f2!()) + (f2!())}) ); macro_rules! f4( () => ({(f3!()) + (f3!())}) ); macro_rules! f5( () => ({(f4!()) + (f4!())}) ); macro_rules! f6( () => ({(f5!()) + (f5!())}) ); macro_rules! f7( () => ({(f6!()) + (f6!())}) ); macro_rules! f8( () => ({(f7!()) + (f7!())}) ); pub fn bar() { f8!(); } "#, ) .build(); p.cargo("test").run(); p.cargo("run --example e1 --release -v").run(); } #[cargo_test] fn selective_testing_with_docs() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.d1] path = "d1" "#, ) .file( "src/lib.rs", r#" /// ``` /// not valid rust /// ``` pub fn foo() {} "#, ) .file( "d1/Cargo.toml", r#" [package] name = "d1" version = "0.0.1" edition = "2015" authors = [] [lib] name = "d1" path = "d1.rs" "#, ) .file("d1/d1.rs", ""); let p = p.build(); p.cargo("test -p d1") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] d1 v0.0.1 ([ROOT]/foo/d1) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests d1.rs (target/debug/deps/d1-[HASH][EXE]) [DOCTEST] d1 "#]]) .with_stdout_data( str![[r#" running 0 tests running 0 tests ... "#]] .unordered(), ) .run(); } #[cargo_test] fn example_bin_same_name() { let p = project() .file("src/bin/foo.rs", r#"fn main() { println!("bin"); }"#) .file("examples/foo.rs", r#"fn main() { println!("example"); }"#) .build(); p.cargo("test --no-run -v") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]` [RUNNING] `rustc [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` "#]]) .run(); assert!(!p.bin("foo").is_file()); assert!(p.bin("examples/foo").is_file()); p.process(&p.bin("examples/foo")) .with_stdout_data(str![[r#" example "#]]) .run(); p.cargo("run") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .with_stdout_data(str![[r#" bin "#]]) .run(); assert!(p.bin("foo").is_file()); } #[cargo_test] fn test_with_example_twice() { let p = project() .file("src/bin/foo.rs", r#"fn main() { println!("bin"); }"#) .file("examples/foo.rs", r#"fn main() { println!("example"); }"#) .build(); println!("first"); p.cargo("test -v").run(); assert!(p.bin("examples/foo").is_file()); println!("second"); p.cargo("test -v").run(); assert!(p.bin("examples/foo").is_file()); } #[cargo_test] fn example_with_dev_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] name = "foo" test = false doctest = false [dev-dependencies.a] path = "a" "#, ) .file("src/lib.rs", "") .file( "examples/ex.rs", "#[allow(unused_extern_crates)] extern crate a; fn main() {}", ) .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/src/lib.rs", "") .build(); p.cargo("test -v") .with_stderr_data( str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] foo v0.0.1 ([ROOT]/foo) [COMPILING] a v0.0.1 ([ROOT]/foo/a) [RUNNING] `rustc --crate-name foo [..]` [RUNNING] `rustc --crate-name a [..]` [RUNNING] `rustc --crate-name ex [..] --extern a=[..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn bin_is_preserved() { let p = project() .file("src/lib.rs", "") .file("src/main.rs", "fn main() {}") .build(); p.cargo("build -v").run(); assert!(p.bin("foo").is_file()); println!("test"); p.cargo("test -v").run(); assert!(p.bin("foo").is_file()); } #[cargo_test] fn bad_example() { let p = project().file("src/lib.rs", ""); let p = p.build(); p.cargo("run --example foo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no example target named `foo`. "#]]) .run(); p.cargo("run --bin foo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] no bin target named `foo`. "#]]) .run(); } #[cargo_test] fn doctest_feature() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [features] bar = [] "#, ) .file( "src/lib.rs", r#" /// ```rust /// assert_eq!(foo::foo(), 1); /// ``` #[cfg(feature = "bar")] pub fn foo() -> i32 { 1 } "#, ) .build(); p.cargo("test --features bar") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "#]]) .with_stdout_data( str![[r#" running 0 tests test [..] ... ok ... "#]] .unordered(), ) .run(); } #[cargo_test] fn dashes_to_underscores() { let p = project() .file("Cargo.toml", &basic_manifest("foo-bar", "0.0.1")) .file( "src/lib.rs", r#" /// ``` /// assert_eq!(foo_bar::foo(), 1); /// ``` pub fn foo() -> i32 { 1 } "#, ) .build(); p.cargo("test -v").run(); } #[cargo_test] fn doctest_dev_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dev-dependencies] b = { path = "b" } "#, ) .file( "src/lib.rs", r#" /// ``` /// extern crate b; /// ``` pub fn foo() {} "#, ) .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/lib.rs", "") .build(); p.cargo("test -v").run(); } #[cargo_test] fn filter_no_doc_tests() { let p = project() .file( "src/lib.rs", r#" /// ``` /// extern crate b; /// ``` pub fn foo() {} "#, ) .file("tests/foo.rs", "") .build(); p.cargo("test --test=foo") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] tests/foo.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" ... running 0 tests ... "#]]) .run(); } #[cargo_test] fn dylib_doctest() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] name = "foo" crate-type = ["rlib", "dylib"] test = false "#, ) .file( "src/lib.rs", r#" /// ``` /// foo::foo(); /// ``` pub fn foo() {} "#, ) .build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [DOCTEST] foo "#]]) .with_stdout_data(str![[r#" ... test [..] ... ok ... "#]]) .run(); } #[cargo_test] fn dylib_doctest2() { // Can't doc-test dylibs, as they're statically linked together. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] name = "foo" crate-type = ["dylib"] test = false "#, ) .file( "src/lib.rs", r#" /// ``` /// foo::foo(); /// ``` pub fn foo() {} "#, ) .build(); p.cargo("test") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn cyclic_dev_dep_doc_test() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dev-dependencies] bar = { path = "bar" } "#, ) .file( "src/lib.rs", r#" //! ``` //! extern crate bar; //! ``` "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] foo = { path = ".." } "#, ) .file( "bar/src/lib.rs", r#" #[allow(unused_extern_crates)] extern crate foo; "#, ) .build(); p.cargo("test") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] foo v0.0.1 ([ROOT]/foo) [COMPILING] bar v0.0.1 ([ROOT]/foo/bar) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "#]]) .with_stdout_data( str![[r#" running 0 tests test [..] ... ok ... "#]] .unordered(), ) .run(); } #[cargo_test] fn dev_dep_with_build_script() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dev-dependencies] bar = { path = "bar" } "#, ) .file("src/lib.rs", "") .file("examples/foo.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] build = "build.rs" "#, ) .file("bar/src/lib.rs", "") .file("bar/build.rs", "fn main() {}") .build(); p.cargo("test").run(); } #[cargo_test] fn no_fail_fast() { let p = project() .file( "src/lib.rs", r#" pub fn add_one(x: i32) -> i32{ x + 1 } /// ```rust /// use foo::sub_one; /// assert_eq!(sub_one(101), 100); /// ``` pub fn sub_one(x: i32) -> i32{ x - 1 } "#, ) .file( "tests/test_add_one.rs", r#" extern crate foo; use foo::*; #[test] fn add_one_test() { assert_eq!(add_one(1), 2); } #[test] fn fail_add_one_test() { assert_eq!(add_one(1), 1); } "#, ) .file( "tests/test_sub_one.rs", r#" extern crate foo; use foo::*; #[test] fn sub_one_test() { assert_eq!(sub_one(1), 0); } "#, ) .build(); p.cargo("test --no-fail-fast") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [RUNNING] tests/test_add_one.rs (target/debug/deps/test_add_one-[HASH][EXE]) [ERROR] test failed, to rerun pass `--test test_add_one` [RUNNING] tests/test_sub_one.rs (target/debug/deps/test_sub_one-[HASH][EXE]) [DOCTEST] foo [ERROR] 1 target failed: `--test test_add_one` "#]]) .with_stdout_data(str![[r#" running 0 tests test add_one_test ... ok test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s test sub_one_test ... ok test [..] ... ok ... "#]].unordered()) .run(); } #[cargo_test] fn test_multiple_packages() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies.d1] path = "d1" [dependencies.d2] path = "d2" [lib] name = "foo" doctest = false "#, ) .file("src/lib.rs", "") .file( "d1/Cargo.toml", r#" [package] name = "d1" version = "0.0.1" edition = "2015" authors = [] [lib] name = "d1" doctest = false "#, ) .file("d1/src/lib.rs", "") .file( "d2/Cargo.toml", r#" [package] name = "d2" version = "0.0.1" edition = "2015" authors = [] [lib] name = "d2" doctest = false "#, ) .file("d2/src/lib.rs", ""); let p = p.build(); p.cargo("test -p d1 -p d2") .with_stderr_data(str![[r#" ... [RUNNING] unittests src/lib.rs (target/debug/deps/d1-[HASH][EXE]) [RUNNING] unittests src/lib.rs (target/debug/deps/d2-[HASH][EXE]) ... "#]]) .with_stdout_data( str![[r#" running 0 tests running 0 tests ... "#]] .unordered(), ) .run(); } #[cargo_test] fn bin_does_not_rebuild_tests() { let p = project() .file("src/lib.rs", "") .file("src/main.rs", "fn main() {}") .file("tests/foo.rs", ""); let p = p.build(); p.cargo("test -v").run(); sleep_ms(1000); fs::write(p.root().join("src/main.rs"), "fn main() { 3; }").unwrap(); p.cargo("test -v --no-run") .with_stderr_data(str![[r#" [DIRTY] foo v0.0.1 ([ROOT]/foo): the file `src/main.rs` has changed ([..]) [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..] src/main.rs [..]` [RUNNING] `rustc [..] src/main.rs [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [EXECUTABLE] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [EXECUTABLE] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` "#]]) .run(); } #[cargo_test] fn selective_test_wonky_profile() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [profile.release] opt-level = 2 [dependencies] a = { path = "a" } "#, ) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/src/lib.rs", ""); let p = p.build(); p.cargo("test -v --no-run --release -p foo -p a").run(); } #[cargo_test] fn selective_test_optional_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a", optional = true } "#, ) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/src/lib.rs", ""); let p = p.build(); p.cargo("test -v --no-run --features a -p a") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [COMPILING] a v0.0.1 ([ROOT]/foo/a) [RUNNING] `rustc [..] a/src/lib.rs [..]` [RUNNING] `rustc [..] a/src/lib.rs [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [EXECUTABLE] `[ROOT]/foo/target/debug/deps/a-[HASH][EXE]` "#]]) .run(); } #[cargo_test] fn only_test_docs() { let p = project() .file( "src/lib.rs", r#" #[test] fn foo() { let a: u32 = "hello"; } /// ``` /// foo::bar(); /// println!("ok"); /// ``` pub fn bar() { } "#, ) .file("tests/foo.rs", "this is not rust"); let p = p.build(); p.cargo("test --doc") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [DOCTEST] foo "#]]) .with_stdout_data(str![[r#" ... test [..] ... ok ... "#]]) .run(); } #[cargo_test] fn doctest_with_library_paths() { let p = project(); // Only link search directories within the target output directory are // propagated through to dylib_path_envvar() (see #3366). let dir1 = p.target_debug_dir().join("foo\\backslash"); let dir2 = p.target_debug_dir().join("dir=containing=equal=signs"); let p = p .file("Cargo.toml", &basic_manifest("foo", "0.0.0")) .file( "build.rs", &format!( r##" fn main() {{ println!(r#"cargo::rustc-link-search=native={}"#); println!(r#"cargo::rustc-link-search={}"#); }} "##, dir1.display(), dir2.display() ), ) .file( "src/lib.rs", &format!( r##" /// ``` /// foo::assert_search_path(); /// ``` pub fn assert_search_path() {{ let search_path = std::env::var_os("{}").unwrap(); let paths = std::env::split_paths(&search_path).collect::>(); assert!(paths.contains(&r#"{}"#.into())); assert!(paths.contains(&r#"{}"#.into())); }} "##, dylib_path_envvar(), dir1.display(), dir2.display() ), ) .build(); p.cargo("test --doc").run(); } #[cargo_test] fn test_panic_abort_with_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = { path = "bar" } [profile.dev] panic = 'abort' "#, ) .file( "src/lib.rs", r#" extern crate bar; #[test] fn foo() {} "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) .file("bar/src/lib.rs", "") .build(); p.cargo("test -v").run(); } #[cargo_test] fn cfg_test_even_with_no_harness() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [lib] harness = false doctest = false "#, ) .file( "src/lib.rs", r#"#[cfg(test)] fn main() { println!("hello!"); }"#, ) .build(); p.cargo("test -v") .with_stdout_data(str![[r#" hello! "#]]) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` "#]]) .run(); } #[cargo_test] fn panic_abort_multiple() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a" } [profile.release] panic = 'abort' "#, ) .file( "src/lib.rs", "#[allow(unused_extern_crates)] extern crate a;", ) .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/src/lib.rs", "") .build(); p.cargo("test --release -v -p foo -p a").run(); } #[cargo_test] fn pass_correct_cfgs_flags_to_rustdoc() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [features] default = ["feature_a/default"] nightly = ["feature_a/nightly"] [dependencies.feature_a] path = "libs/feature_a" default-features = false "#, ) .file( "src/lib.rs", r#" #[cfg(test)] mod tests { #[test] fn it_works() { assert!(true); } } "#, ) .file( "libs/feature_a/Cargo.toml", r#" [package] name = "feature_a" version = "0.1.0" edition = "2015" authors = [] [features] default = ["mock_serde_codegen"] nightly = ["mock_serde_derive"] [dependencies] mock_serde_derive = { path = "../mock_serde_derive", optional = true } [build-dependencies] mock_serde_codegen = { path = "../mock_serde_codegen", optional = true } "#, ) .file( "libs/feature_a/src/lib.rs", r#" #[cfg(feature = "mock_serde_derive")] const MSG: &'static str = "This is safe"; #[cfg(feature = "mock_serde_codegen")] const MSG: &'static str = "This is risky"; pub fn get() -> &'static str { MSG } "#, ) .file( "libs/mock_serde_derive/Cargo.toml", &basic_manifest("mock_serde_derive", "0.1.0"), ) .file("libs/mock_serde_derive/src/lib.rs", "") .file( "libs/mock_serde_codegen/Cargo.toml", &basic_manifest("mock_serde_codegen", "0.1.0"), ) .file("libs/mock_serde_codegen/src/lib.rs", ""); let p = p.build(); p.cargo("test --package feature_a --verbose") .with_stderr_data(str![[r#" ... [DOCTEST] feature_a [RUNNING] `rustdoc [..]--test [..]mock_serde_codegen[..]` ... "#]]) .run(); p.cargo("test --verbose") .with_stderr_data(str![[r#" ... [DOCTEST] foo [RUNNING] `rustdoc [..]--test [..]feature_a[..]` ... "#]]) .run(); } #[cargo_test] fn test_release_ignore_panic() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a" } [profile.test] panic = 'abort' [profile.release] panic = 'abort' "#, ) .file( "src/lib.rs", "#[allow(unused_extern_crates)] extern crate a;", ) .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/src/lib.rs", ""); let p = p.build(); println!("test"); p.cargo("test -v").run(); println!("bench"); p.cargo("bench -v").run(); } #[cargo_test] fn test_many_with_features() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] a = { path = "a" } [features] foo = [] [workspace] "#, ) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) .file("a/src/lib.rs", "") .build(); p.cargo("test -v -p a -p foo --features foo").run(); } #[cargo_test] fn test_all_workspace() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { path = "bar" } [workspace] "#, ) .file("src/main.rs", "#[test] fn foo_test() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "#[test] fn bar_test() {}") .build(); p.cargo("test --workspace") .with_stdout_data( str![[r#" test foo_test ... ok test bar_test ... ok ... "#]] .unordered(), ) .run(); } #[cargo_test] fn test_all_exclude() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["bar", "baz"] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "#[test] pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "#[test] pub fn baz() { assert!(false); }") .build(); p.cargo("test --workspace --exclude baz") .with_stdout_data(str![[r#" ... running 1 test test bar ... ok ... "#]]) .run(); } #[cargo_test] fn test_all_exclude_not_found() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "#[test] pub fn bar() {}") .build(); p.cargo("test --workspace --exclude baz") .with_stderr_data(str![[r#" ... [WARNING] excluded package(s) `baz` not found in workspace `[ROOT]/foo` ... "#]]) .with_stdout_data(str![[r#" ... running 1 test test bar ... ok ... "#]]) .run(); } #[cargo_test] fn test_all_exclude_glob() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["bar", "baz"] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "#[test] pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "#[test] pub fn baz() { assert!(false); }") .build(); p.cargo("test --workspace --exclude '*z'") .with_stdout_data(str![[r#" ... running 1 test test bar ... ok ... "#]]) .run(); } #[cargo_test] fn test_all_exclude_glob_not_found() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "#[test] pub fn bar() {}") .build(); p.cargo("test --workspace --exclude '*z'") .with_stderr_data(str![[r#" ... [WARNING] excluded package pattern(s) `*z` not found in workspace `[ROOT]/foo` ... "#]]) .with_stdout_data(str![[r#" ... running 1 test test bar ... ok ... "#]]) .run(); } #[cargo_test] fn test_all_exclude_broken_glob() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("test --workspace --exclude '[*z'") .with_status(101) .with_stderr_data(str![[r#" ... [ERROR] cannot build glob pattern from `[*z` ... "#]]) .run(); } #[cargo_test] fn test_all_virtual_manifest() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file("a/Cargo.toml", &basic_manifest("a", "0.1.0")) .file("a/src/lib.rs", "#[test] fn a() {}") .file("b/Cargo.toml", &basic_manifest("b", "0.1.0")) .file("b/src/lib.rs", "#[test] fn b() {}") .build(); p.cargo("test --workspace") .with_stdout_data( str![[r#" running 1 test test a ... ok running 1 test test b ... ok ... "#]] .unordered(), ) .run(); } #[cargo_test] fn test_virtual_manifest_all_implied() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file("a/Cargo.toml", &basic_manifest("a", "0.1.0")) .file("a/src/lib.rs", "#[test] fn a() {}") .file("b/Cargo.toml", &basic_manifest("b", "0.1.0")) .file("b/src/lib.rs", "#[test] fn b() {}") .build(); p.cargo("test") .with_stdout_data( str![[r#" running 1 test test a ... ok running 1 test test b ... ok ... "#]] .unordered(), ) .run(); } #[cargo_test] fn test_virtual_manifest_one_project() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "#[test] fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "#[test] fn baz() { assert!(false); }") .build(); p.cargo("test -p bar") .with_stdout_contains("running 1 test\ntest bar ... ok") .with_stdout_does_not_contain("running 1 test\ntest baz ... ok") .run(); } #[cargo_test] fn test_virtual_manifest_glob() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "#[test] fn bar() { assert!(false); }") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "#[test] fn baz() {}") .build(); p.cargo("test -p '*z'") .with_stdout_does_not_contain("running 1 test\ntest bar ... ok") .with_stdout_contains("running 1 test\ntest baz ... ok") .run(); } #[cargo_test] fn test_virtual_manifest_glob_not_found() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "#[test] fn bar() {}") .build(); p.cargo("test -p bar -p '*z'") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package pattern(s) `*z` not found in workspace `[ROOT]/foo` ... "#]]) .run(); } #[cargo_test] fn test_virtual_manifest_broken_glob() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "#[test] fn bar() {}") .build(); p.cargo("test -p '[*z'") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot build glob pattern from `[*z` ... "#]]) .run(); } #[cargo_test] fn test_all_member_dependency_same_name() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" [dependencies] a = "0.1.0" "#, ) .file("a/src/lib.rs", "#[test] fn a() {}") .build(); Package::new("a", "0.1.0").publish(); p.cargo("test --workspace") .with_stdout_data(str![[r#" ... test a ... ok ... "#]]) .run(); } #[cargo_test] fn doctest_only_with_dev_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" [dev-dependencies] b = { path = "b" } "#, ) .file( "src/lib.rs", r#" /// ``` /// extern crate b; /// /// b::b(); /// ``` pub fn a() {} "#, ) .file("b/Cargo.toml", &basic_manifest("b", "0.1.0")) .file("b/src/lib.rs", "pub fn b() {}") .build(); p.cargo("test --doc -v").run(); } #[cargo_test] fn test_many_targets() { let p = project() .file( "src/bin/a.rs", r#" fn main() {} #[test] fn bin_a() {} "#, ) .file( "src/bin/b.rs", r#" fn main() {} #[test] fn bin_b() {} "#, ) .file( "src/bin/c.rs", r#" fn main() {} #[test] fn bin_c() { panic!(); } "#, ) .file( "examples/a.rs", r#" fn main() {} #[test] fn example_a() {} "#, ) .file( "examples/b.rs", r#" fn main() {} #[test] fn example_b() {} "#, ) .file("examples/c.rs", "#[test] fn example_c() { panic!(); }") .file("tests/a.rs", "#[test] fn test_a() {}") .file("tests/b.rs", "#[test] fn test_b() {}") .file("tests/c.rs", "does not compile") .build(); p.cargo("test --verbose --bin a --bin b --example a --example b --test a --test b") .with_stdout_data( str![[r#" test bin_a ... ok test bin_b ... ok test test_a ... ok test test_b ... ok ... "#]] .unordered(), ) .with_stderr_data( str![[r#" [RUNNING] `rustc --crate-name a --edition=2015 examples/a.rs [..]` [RUNNING] `rustc --crate-name b --edition=2015 examples/b.rs [..]` ... "#]] .unordered(), ) .run(); } #[cargo_test] fn doctest_and_registry() { let p = project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.1.0" edition = "2015" [dependencies] b = { path = "b" } c = { path = "c" } [workspace] "#, ) .file("src/lib.rs", "") .file("b/Cargo.toml", &basic_manifest("b", "0.1.0")) .file( "b/src/lib.rs", " /// ``` /// b::foo(); /// ``` pub fn foo() {} ", ) .file( "c/Cargo.toml", r#" [package] name = "c" version = "0.1.0" edition = "2015" [dependencies] b = "0.1" "#, ) .file("c/src/lib.rs", "") .build(); Package::new("b", "0.1.0").publish(); p.cargo("test --workspace -v").run(); } #[cargo_test] fn cargo_test_env() { let rustc_host = rustc_host(); let src = format!( r#" #![crate_type = "rlib"] #[test] fn env_test() {{ use std::env; eprintln!("{{}}", env::var("{}").unwrap()); }} "#, cargo::CARGO_ENV ); let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", &src) .build(); let cargo = format!( "{}[EXE]", cargo_exe() .canonicalize() .unwrap() .with_extension("") .to_str() .unwrap() .replace(rustc_host, "[HOST_TARGET]") ); p.cargo("test --lib -- --nocapture") .with_stderr_contains(cargo) .with_stdout_data(str![[r#" ... test env_test ... ok ... "#]]) .run(); // Check that `cargo test` propagates the environment's $CARGO let rustc = cargo_util::paths::resolve_executable("rustc".as_ref()) .unwrap() .canonicalize() .unwrap(); let stderr_rustc = format!( "{}[EXE]", rustc .with_extension("") .to_str() .unwrap() .replace(rustc_host, "[HOST_TARGET]") ); p.cargo("test --lib -- --nocapture") // we use rustc since $CARGO is only used if it points to a path that exists .env(cargo::CARGO_ENV, rustc) .with_stderr_contains(stderr_rustc) .with_stdout_data(str![[r#" ... test env_test ... ok ... "#]]) .run(); } #[cargo_test] fn test_order() { let p = project() .file("src/lib.rs", "#[test] fn test_lib() {}") .file("tests/a.rs", "#[test] fn test_a() {}") .file("tests/z.rs", "#[test] fn test_z() {}") .build(); p.cargo("test --workspace") .with_stdout_data(str![[r#" running 1 test test test_lib ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test test_a ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test test_z ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s ... "#]]) .run(); } #[cargo_test] fn cyclic_dev() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dev-dependencies] foo = { path = "." } "#, ) .file("src/lib.rs", "#[test] fn test_lib() {}") .file("tests/foo.rs", "extern crate foo;") .build(); p.cargo("test --workspace").run(); } #[cargo_test] fn cyclical_dep_with_missing_feature() { // Checks for error handling when a cyclical dev-dependency specify a // feature that doesn't exist. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dev-dependencies] foo = { path = ".", features = ["missing"] } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to select a version for `foo`. ... required by package `foo v0.1.0 ([ROOT]/foo)` versions that meet the requirements `*` are: 0.1.0 the package `foo` depends on `foo`, with features: `missing` but `foo` does not have these features. failed to select a version for `foo` which could resolve this conflict "#]]) .run(); } #[cargo_test] fn publish_a_crate_without_tests() { Package::new("testless", "0.1.0") .file( "Cargo.toml", r#" [package] name = "testless" version = "0.1.0" edition = "2015" exclude = ["tests/*"] [[test]] name = "a_test" "#, ) .file("src/lib.rs", "") // In real life, the package will have a test, // which would be excluded from .crate file by the // `exclude` field. Our test harness does not honor // exclude though, so let's just not add the file! // .file("tests/a_test.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] testless = "0.1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("test").run(); p.cargo("test --package testless").run(); } #[cargo_test] fn find_dependency_of_proc_macro_dependency_with_target() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["root", "proc_macro_dep"] "#, ) .file( "root/Cargo.toml", r#" [package] name = "root" version = "0.1.0" edition = "2015" authors = [] [dependencies] proc_macro_dep = { path = "../proc_macro_dep" } "#, ) .file( "root/src/lib.rs", r#" #[macro_use] extern crate proc_macro_dep; #[derive(Noop)] pub struct X; "#, ) .file( "proc_macro_dep/Cargo.toml", r#" [package] name = "proc_macro_dep" version = "0.1.0" edition = "2015" authors = [] [lib] proc-macro = true [dependencies] baz = "^0.1" "#, ) .file( "proc_macro_dep/src/lib.rs", r#" extern crate baz; extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro_derive(Noop)] pub fn noop(_input: TokenStream) -> TokenStream { "".parse().unwrap() } "#, ) .build(); Package::new("bar", "0.1.0").publish(); Package::new("baz", "0.1.0") .dep("bar", "0.1") .file("src/lib.rs", "extern crate bar;") .publish(); p.cargo("test --workspace --target").arg(rustc_host()).run(); } #[cargo_test] fn test_hint_not_masked_by_doctest() { let p = project() .file( "src/lib.rs", r#" /// ``` /// assert_eq!(1, 1); /// ``` pub fn this_works() {} "#, ) .file( "tests/integ.rs", r#" #[test] fn this_fails() { panic!(); } "#, ) .build(); p.cargo("test --no-fail-fast") .with_status(101) .with_stdout_data( str![[r#" test this_fails ... FAILED test [..]this_works (line [..]) ... ok ... "#]] .unordered(), ) .with_stderr_data(str![[r#" ... [ERROR] test failed, to rerun pass `--test integ` ... "#]]) .run(); } #[cargo_test] fn test_hint_workspace_virtual() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b", "c"] "#, ) .file("a/Cargo.toml", &basic_manifest("a", "0.1.0")) .file("a/src/lib.rs", "#[test] fn t1() {}") .file("b/Cargo.toml", &basic_manifest("b", "0.1.0")) .file("b/src/lib.rs", "#[test] fn t1() {assert!(false)}") .file("c/Cargo.toml", &basic_manifest("c", "0.1.0")) .file( "c/src/lib.rs", r#" /// ```rust /// assert_eq!(1, 2); /// ``` pub fn foo() {} "#, ) .file( "c/src/main.rs", r#" fn main() {} #[test] fn from_main() { assert_eq!(1, 2); } "#, ) .file( "c/tests/t1.rs", r#" #[test] fn from_int_test() { assert_eq!(1, 2); } "#, ) .file( "c/examples/ex1.rs", r#" fn main() {} #[test] fn from_example() { assert_eq!(1, 2); } "#, ) // This does not use #[bench] since it is unstable. #[test] works just // the same for our purpose of checking the hint. .file( "c/benches/b1.rs", r#" #[test] fn from_bench() { assert_eq!(1, 2); } "#, ) .build(); // This depends on Units being sorted so that `b` fails first. p.cargo("test") .with_stderr_data( str![[r#" [COMPILING] c v0.1.0 ([ROOT]/foo/c) [COMPILING] a v0.1.0 ([ROOT]/foo/a) [COMPILING] b v0.1.0 ([ROOT]/foo/b) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/a-[HASH][EXE]) [RUNNING] unittests src/lib.rs (target/debug/deps/b-[HASH][EXE]) [ERROR] test failed, to rerun pass `-p b --lib` "#]] .unordered(), ) .with_status(101) .run(); p.cargo("test") .cwd("b") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs ([ROOT]/foo/target/debug/deps/b-[HASH][EXE]) [ERROR] test failed, to rerun pass `--lib` "#]]) .with_status(101) .run(); p.cargo("test --no-fail-fast") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/a-[HASH][EXE]) [RUNNING] unittests src/lib.rs (target/debug/deps/b-[HASH][EXE]) [ERROR] test failed, to rerun pass `-p b --lib` [RUNNING] unittests src/lib.rs (target/debug/deps/c-[HASH][EXE]) [RUNNING] unittests src/main.rs (target/debug/deps/c-[HASH][EXE]) [ERROR] test failed, to rerun pass `-p c --bin c` [RUNNING] tests/t1.rs (target/debug/deps/t1-[HASH][EXE]) [ERROR] test failed, to rerun pass `-p c --test t1` [DOCTEST] a [DOCTEST] b [DOCTEST] c [ERROR] doctest failed, to rerun pass `-p c --doc` [ERROR] 4 targets failed: `-p b --lib` `-p c --bin c` `-p c --test t1` `-p c --doc` "#]]) .with_status(101) .run(); // Check others that are not in the default set. p.cargo("test -p c --examples --benches --no-fail-fast") .with_stderr_data(str![[r#" [COMPILING] c v0.1.0 ([ROOT]/foo/c) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/c-[HASH][EXE]) [RUNNING] unittests src/main.rs (target/debug/deps/c-[HASH][EXE]) [ERROR] test failed, to rerun pass `-p c --bin c` [RUNNING] benches/b1.rs (target/debug/deps/b1-[HASH][EXE]) [ERROR] test failed, to rerun pass `-p c --bench b1` [RUNNING] unittests examples/ex1.rs (target/debug/examples/ex1-[HASH][EXE]) [ERROR] test failed, to rerun pass `-p c --example ex1` [ERROR] 3 targets failed: `-p c --bin c` `-p c --bench b1` `-p c --example ex1` "#]]) .with_status(101) .run(); } #[cargo_test] fn test_hint_workspace_nonvirtual() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["a"] "#, ) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("a", "0.1.0")) .file("a/src/lib.rs", "#[test] fn t1() {assert!(false)}") .build(); p.cargo("test --workspace") .with_stderr_data(str![[r#" ... [ERROR] test failed, to rerun pass `-p a --lib` ... "#]]) .with_status(101) .run(); p.cargo("test -p a") .with_stderr_data(str![[r#" ... [ERROR] test failed, to rerun pass `-p a --lib` ... "#]]) .with_status(101) .run(); } #[cargo_test] fn json_artifact_includes_test_flag() { // Verify that the JSON artifact output includes `test` flag. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [profile.test] opt-level = 1 "#, ) .file("src/lib.rs", "") .build(); p.cargo("test --lib -v --no-run --message-format=json") .with_stdout_data( str![[r#" [ { "executable": "[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]", "features": [], "filenames": "{...}", "fresh": false, "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.0.1", "profile": "{...}", "reason": "compiler-artifact", "target": { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } }, { "reason": "build-finished", "success": true } ] "#]] .is_json() .against_jsonlines(), ) .run(); } #[cargo_test] fn json_artifact_includes_executable_for_library_tests() { let p = project() .file("src/main.rs", "fn main() { }") .file("src/lib.rs", r#"#[test] fn lib_test() {}"#) .build(); p.cargo("test --lib -v --no-run --message-format=json") .with_stdout_data( str![[r#" [ { "executable": "[ROOT]/foo/target/debug/deps/foo-[HASH][EXE]", "features": [], "filenames": "{...}", "fresh": false, "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.0.1", "profile": "{...}", "reason": "compiler-artifact", "target": { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } }, { "reason": "build-finished", "success": true } ] "#]] .is_json() .against_jsonlines(), ) .run(); } #[cargo_test] fn json_artifact_includes_executable_for_integration_tests() { let p = project() .file( "tests/integration_test.rs", r#"#[test] fn integration_test() {}"#, ) .build(); p.cargo("test -v --no-run --message-format=json --test integration_test") .with_stdout_data( str![[r#" [ { "executable": "[ROOT]/foo/target/debug/deps/integration_test-[HASH][EXE]", "features": [], "filenames": "{...}", "fresh": false, "manifest_path": "[ROOT]/foo/Cargo.toml", "package_id": "path+[ROOTURL]/foo#0.0.1", "profile": "{...}", "reason": "compiler-artifact", "target": { "crate_types": [ "bin" ], "doc": false, "doctest": false, "edition": "2015", "kind": [ "test" ], "name": "integration_test", "src_path": "[ROOT]/foo/tests/integration_test.rs", "test": true } }, { "reason": "build-finished", "success": true } ] "#]] .is_json() .against_jsonlines(), ) .run(); } #[cargo_test] fn test_build_script_links() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" links = 'something' [lib] test = false "#, ) .file("build.rs", "fn main() {}") .file("src/lib.rs", "") .build(); p.cargo("test --no-run").run(); } #[cargo_test] fn doctest_skip_staticlib() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [lib] crate-type = ["staticlib"] "#, ) .file( "src/lib.rs", r#" //! ``` //! assert_eq!(1,2); //! ``` "#, ) .build(); p.cargo("test --doc") .with_status(101) .with_stderr_data(str![[r#" [WARNING] doc tests are not supported for crate type(s) `staticlib` in package `foo` [ERROR] no library targets found in package `foo` "#]]) .run(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .run(); } #[cargo_test] fn can_not_mix_doc_tests_and_regular_tests() { let p = project() .file( "src/lib.rs", "\ /// ``` /// assert_eq!(1, 1) /// ``` pub fn foo() -> u8 { 1 } #[cfg(test)] mod tests { #[test] fn it_works() { assert_eq!(2 + 2, 4); } } ", ) .build(); p.cargo("test") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) [DOCTEST] foo "#]]) .with_stdout_data(str![[r#" running 1 test test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s running 1 test test src/lib.rs - foo (line 1) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); p.cargo("test --lib") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .with_stdout_data(str![[r#" running 1 test test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .run(); // This has been modified to attempt to diagnose spurious errors on CI. // For some reason, this is recompiling the lib when it shouldn't. If the // root cause is ever found, the changes here should be reverted. // See https://github.com/rust-lang/cargo/issues/6887 p.cargo("test --doc -vv") .with_stderr_does_not_contain("[COMPILING] foo [..]") .with_stderr_data(str![[r#" ... [DOCTEST] foo ... "#]]) .with_stdout_data(str![[r#" running 1 test test src/lib.rs - foo (line 1) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s "#]]) .env("CARGO_LOG", "cargo=trace") .run(); p.cargo("test --lib --doc") .with_status(101) .with_stderr_data(str![[r#" [ERROR] Can't mix --doc with other target selecting options "#]]) .run(); } #[cargo_test] fn can_not_no_run_doc_tests() { let p = project() .file( "src/lib.rs", r#" /// ``` /// let _x = 1 + "foo"; /// ``` pub fn foo() -> u8 { 1 } "#, ) .build(); p.cargo("test --doc --no-run") .with_status(101) .with_stderr_data(str![[r#" [ERROR] Can't skip running doc tests with --no-run "#]]) .run(); } #[cargo_test] fn test_all_targets_lib() { let p = project().file("src/lib.rs", "").build(); p.cargo("test --all-targets") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] unittests src/lib.rs (target/debug/deps/foo-[HASH][EXE]) "#]]) .run(); } #[cargo_test] fn test_dep_with_dev() { Package::new("devdep", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" [dependencies] bar = { path = "bar" } "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" [dev-dependencies] devdep = "0.1" "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("test -p bar") .with_status(101) .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version [ERROR] package `bar` cannot be tested because it requires dev-dependencies and is not a member of the workspace "#]]) .run(); } #[cargo_test(nightly, reason = "-Zdoctest-xcompile is unstable")] fn cargo_test_doctest_xcompile_ignores() { // -Zdoctest-xcompile also enables --enable-per-target-ignores which // allows the ignore-TARGET syntax. let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file( "src/lib.rs", r#" ///```ignore-x86_64 ///assert!(cfg!(not(target_arch = "x86_64"))); ///``` pub fn foo() -> u8 { 4 } "#, ) .build(); p.cargo("build").run(); #[cfg(not(target_arch = "x86_64"))] p.cargo("test") .with_stdout_data(str![[r#" ... test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s ... "#]]) .run(); #[cfg(target_arch = "x86_64")] p.cargo("test") .with_status(101) .with_stdout_data(str![[r#" ... test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s ... "#]], ) .run(); #[cfg(not(target_arch = "x86_64"))] p.cargo("test -Zdoctest-xcompile") .masquerade_as_nightly_cargo(&["doctest-xcompile"]) .with_stdout_data(str![[r#" ... test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s ... "#]]) .run(); #[cfg(target_arch = "x86_64")] p.cargo("test -Zdoctest-xcompile") .masquerade_as_nightly_cargo(&["doctest-xcompile"]) .with_stdout_data(str![[r#" ... test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s ... "#]]) .run(); } #[cargo_test(nightly, reason = "-Zdoctest-xcompile is unstable")] fn cargo_test_doctest_xcompile() { if !cross_compile::can_run_on_host() { return; } let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file( "src/lib.rs", r#" ///``` ///assert!(1 == 1); ///``` pub fn foo() -> u8 { 4 } "#, ) .build(); p.cargo("build").run(); p.cargo(&format!("test --target {}", cross_compile::alternate())) .with_stdout_data(str![[r#" ... running 0 tests ... "#]]) .run(); p.cargo(&format!( "test --target {} -Zdoctest-xcompile", cross_compile::alternate() )) .masquerade_as_nightly_cargo(&["doctest-xcompile"]) .with_stdout_data(str![[r#" ... test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s ... "#]]) .run(); } #[cargo_test(nightly, reason = "-Zdoctest-xcompile is unstable")] fn cargo_test_doctest_xcompile_runner() { if !cross_compile::can_run_on_host() { return; } let runner = project() .file("Cargo.toml", &basic_bin_manifest("runner")) .file( "src/main.rs", r#" pub fn main() { eprintln!("this is a runner"); let args: Vec = std::env::args().collect(); std::process::Command::new(&args[1]).spawn(); } "#, ) .build(); runner.cargo("build").run(); assert!(runner.bin("runner").is_file()); let runner_path = paths::root().join("runner"); fs::copy(&runner.bin("runner"), &runner_path).unwrap(); let config = paths::root().join(".cargo/config.toml"); fs::create_dir_all(config.parent().unwrap()).unwrap(); // Escape Windows backslashes for TOML config. let runner_str = runner_path.to_str().unwrap().replace('\\', "\\\\"); fs::write( config, format!( r#" [target.'cfg(target_arch = "{}")'] runner = "{}" "#, cross_compile::alternate_arch(), runner_str ), ) .unwrap(); let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file( "src/lib.rs", &format!( r#" ///``` ///assert!(cfg!(target_arch = "{}")); ///``` pub fn foo() -> u8 {{ 4 }} "#, cross_compile::alternate_arch() ), ) .build(); p.cargo("build").run(); p.cargo(&format!("test --target {}", cross_compile::alternate())) .with_stdout_data(str![[r#" ... running 0 tests ... "#]]) .run(); p.cargo(&format!( "test --target {} -Zdoctest-xcompile", cross_compile::alternate() )) .masquerade_as_nightly_cargo(&["doctest-xcompile"]) .with_stdout_data(str![[r#" ... test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s ... "#]]) .with_stderr_data(str![[r#" ... this is a runner ... "#]]) .run(); } #[cargo_test(nightly, reason = "-Zdoctest-xcompile is unstable")] fn cargo_test_doctest_xcompile_no_runner() { if !cross_compile::can_run_on_host() { return; } let p = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file( "src/lib.rs", &format!( r#" ///``` ///assert!(cfg!(target_arch = "{}")); ///``` pub fn foo() -> u8 {{ 4 }} "#, cross_compile::alternate_arch() ), ) .build(); p.cargo("build").run(); p.cargo(&format!("test --target {}", cross_compile::alternate())) .with_stdout_data(str![[r#" ... running 0 tests ... "#]]) .run(); p.cargo(&format!( "test --target {} -Zdoctest-xcompile", cross_compile::alternate() )) .masquerade_as_nightly_cargo(&["doctest-xcompile"]) .with_stdout_data(str![[r#" ... test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in [ELAPSED]s ... "#]]) .run(); } #[cargo_test(nightly, reason = "-Zpanic-abort-tests in rustc is unstable")] fn panic_abort_tests() { let p = project() .file( "Cargo.toml", r#" [package] name = 'foo' version = '0.1.0' edition = "2015" [dependencies] a = { path = 'a' } [profile.dev] panic = 'abort' [profile.test] panic = 'abort' "#, ) .file( "src/lib.rs", r#" #[test] fn foo() { a::foo(); } "#, ) .file("a/Cargo.toml", &basic_lib_manifest("a")) .file("a/src/lib.rs", "pub fn foo() {}") .build(); p.cargo("test -Z panic-abort-tests -v") .with_stderr_data( str![[r#" [RUNNING] `[..]--crate-name a [..]-C panic=abort[..]` [RUNNING] `[..]--crate-name foo [..]-C panic=abort[..]` [RUNNING] `[..]--crate-name foo [..]-C panic=abort[..]--test[..]` ... "#]] .unordered(), ) .masquerade_as_nightly_cargo(&["panic-abort-tests"]) .run(); } #[cargo_test] // Unlike with rustc, `rustdoc --test -Cpanic=abort` already works on stable fn panic_abort_doc_tests() { let p = project() .file( "Cargo.toml", r#" [package] name = 'foo' version = '0.1.0' edition = "2015" [profile.dev] panic = 'abort' "#, ) .file( "src/lib.rs", r#" //! ```should_panic //! panic!(); //! ``` "#, ) .build(); p.cargo("test --doc -Z panic-abort-tests -v") .with_stderr_data( str![[r#" [RUNNING] `[..]rustc[..] --crate-name foo [..]-C panic=abort[..]` [RUNNING] `[..]rustdoc[..] --crate-name foo [..]--test[..]-C panic=abort[..]` ... "#]] .unordered(), ) .masquerade_as_nightly_cargo(&["panic-abort-tests"]) .run(); } #[cargo_test(nightly, reason = "-Zpanic-abort-tests in rustc is unstable")] fn panic_abort_only_test() { let p = project() .file( "Cargo.toml", r#" [package] name = 'foo' version = '0.1.0' edition = "2015" [dependencies] a = { path = 'a' } [profile.test] panic = 'abort' "#, ) .file( "src/lib.rs", r#" #[test] fn foo() { a::foo(); } "#, ) .file("a/Cargo.toml", &basic_lib_manifest("a")) .file("a/src/lib.rs", "pub fn foo() {}") .build(); p.cargo("test -Z panic-abort-tests -v") .with_stderr_data(str![[r#" [WARNING] `panic` setting is ignored for `test` profile ... "#]]) .masquerade_as_nightly_cargo(&["panic-abort-tests"]) .run(); } #[cargo_test(nightly, reason = "-Zpanic-abort-tests in rustc is unstable")] fn panic_abort_test_profile_inherits() { let p = project() .file( "Cargo.toml", r#" [package] name = 'foo' version = '0.1.0' edition = "2015" [dependencies] a = { path = 'a' } [profile.dev] panic = 'abort' "#, ) .file( "src/lib.rs", r#" #[test] fn foo() { a::foo(); } "#, ) .file("a/Cargo.toml", &basic_lib_manifest("a")) .file("a/src/lib.rs", "pub fn foo() {}") .build(); p.cargo("test -Z panic-abort-tests -v") .masquerade_as_nightly_cargo(&["panic-abort-tests"]) .with_status(0) .run(); } #[cargo_test] fn bin_env_for_test() { // Test for the `CARGO_BIN_EXE_` environment variables for tests. // // Note: The Unicode binary uses a `[[bin]]` definition because different // filesystems normalize utf-8 in different ways. For example, HFS uses // "gru\u{308}ßen" and APFS uses "gr\u{fc}ßen". Defining it in TOML forces // one form to be used. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2018" [[bin]] name = 'grüßen' path = 'src/bin/grussen.rs' "#, ) .file("src/bin/foo.rs", "fn main() {}") .file("src/bin/with-dash.rs", "fn main() {}") .file("src/bin/grussen.rs", "fn main() {}") .build(); let bin_path = |name| p.bin(name).to_string_lossy().replace("\\", "\\\\"); p.change_file( "tests/check_env.rs", &r#" #[test] fn run_bins() { assert_eq!(env!("CARGO_BIN_EXE_foo"), ""); assert_eq!(env!("CARGO_BIN_EXE_with-dash"), ""); assert_eq!(env!("CARGO_BIN_EXE_grüßen"), ""); } "# .replace("", &bin_path("foo")) .replace("", &bin_path("with-dash")) .replace("", &bin_path("grüßen")), ); p.cargo("test --test check_env").run(); p.cargo("check --test check_env").run(); } #[cargo_test] fn test_workspaces_cwd() { // This tests that all the different test types are executed from the // crate directory (manifest_dir), and not from the workspace root. let make_lib_file = |expected| { format!( r#" //! ``` //! assert_eq!("{expected}", std::fs::read_to_string("file.txt").unwrap()); //! assert_eq!("{expected}", include_str!("../file.txt")); //! assert_eq!( //! std::path::PathBuf::from(std::env!("CARGO_MANIFEST_DIR")), //! std::env::current_dir().unwrap(), //! ); //! ``` #[test] fn test_unit_{expected}_cwd() {{ assert_eq!("{expected}", std::fs::read_to_string("file.txt").unwrap()); assert_eq!("{expected}", include_str!("../file.txt")); assert_eq!( std::path::PathBuf::from(std::env!("CARGO_MANIFEST_DIR")), std::env::current_dir().unwrap(), ); }} "#, expected = expected ) }; let make_test_file = |expected| { format!( r#" #[test] fn test_integration_{expected}_cwd() {{ assert_eq!("{expected}", std::fs::read_to_string("file.txt").unwrap()); assert_eq!("{expected}", include_str!("../file.txt")); assert_eq!( std::path::PathBuf::from(std::env!("CARGO_MANIFEST_DIR")), std::env::current_dir().unwrap(), ); }} "#, expected = expected ) }; let p = project() .file( "Cargo.toml", r#" [package] name = "root-crate" version = "0.0.0" [workspace] members = [".", "nested-crate", "very/deeply/nested/deep-crate"] "#, ) .file("file.txt", "root") .file("src/lib.rs", &make_lib_file("root")) .file("tests/integration.rs", &make_test_file("root")) .file( "nested-crate/Cargo.toml", r#" [package] name = "nested-crate" version = "0.0.0" "#, ) .file("nested-crate/file.txt", "nested") .file("nested-crate/src/lib.rs", &make_lib_file("nested")) .file( "nested-crate/tests/integration.rs", &make_test_file("nested"), ) .file( "very/deeply/nested/deep-crate/Cargo.toml", r#" [package] name = "deep-crate" version = "0.0.0" "#, ) .file("very/deeply/nested/deep-crate/file.txt", "deep") .file( "very/deeply/nested/deep-crate/src/lib.rs", &make_lib_file("deep"), ) .file( "very/deeply/nested/deep-crate/tests/integration.rs", &make_test_file("deep"), ) .build(); p.cargo("test --workspace --all") .with_stderr_data( str![[r#" [DOCTEST] root_crate [DOCTEST] nested_crate [DOCTEST] deep_crate ... "#]] .unordered(), ) .with_stdout_data( str![[r#" test test_unit_root_cwd ... ok test test_unit_nested_cwd ... ok test test_unit_deep_cwd ... ok test test_integration_root_cwd ... ok test test_integration_nested_cwd ... ok test test_integration_deep_cwd ... ok ... "#]] .unordered(), ) .run(); p.cargo("test -p root-crate --all") .with_stderr_data(str![[r#" ... [DOCTEST] root_crate ... "#]]) .with_stdout_data( str![[r#" test test_unit_root_cwd ... ok test test_integration_root_cwd ... ok ... "#]] .unordered(), ) .run(); p.cargo("test -p nested-crate --all") .with_stderr_data(str![[r#" ... [DOCTEST] nested_crate ... "#]]) .with_stdout_data( str![[r#" test test_unit_nested_cwd ... ok test test_integration_nested_cwd ... ok ... "#]] .unordered(), ) .run(); p.cargo("test -p deep-crate --all") .with_stderr_data(str![[r#" ... [DOCTEST] deep_crate ... "#]]) .with_stdout_data( str![[r#" test test_unit_deep_cwd ... ok test test_integration_deep_cwd ... ok ... "#]] .unordered(), ) .run(); p.cargo("test --all") .cwd("nested-crate") .with_stderr_data(str![[r#" ... [DOCTEST] nested_crate ... "#]]) .with_stdout_data( str![[r#" test test_unit_nested_cwd ... ok test test_integration_nested_cwd ... ok ... "#]] .unordered(), ) .run(); p.cargo("test --all") .cwd("very/deeply/nested/deep-crate") .with_stderr_data(str![[r#" ... [DOCTEST] deep_crate ... "#]]) .with_stdout_data( str![[r#" test test_unit_deep_cwd ... ok test test_integration_deep_cwd ... ok ... "#]] .unordered(), ) .run(); } #[cargo_test] fn execution_error() { // Checks the behavior when a test fails to launch. let p = project() .file( "tests/t1.rs", r#" #[test] fn foo() {} "#, ) .build(); let key = format!("CARGO_TARGET_{}_RUNNER", rustc_host_env()); p.cargo("test") .env(&key, "does_not_exist") // The actual error is usually "no such file", but on Windows it has a // custom message. Since matching against the error string produced by // Rust is not very reliable, this just uses `[..]`. .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] tests/t1.rs (target/debug/deps/t1-[HASH][EXE]) [ERROR] test failed, to rerun pass `--test t1` Caused by: could not execute process `does_not_exist [ROOT]/foo/target/debug/deps/t1-[HASH][EXE]` (never executed) Caused by: [NOT_FOUND] "#]]) .with_status(101) .run(); } #[cargo_test] fn nonzero_exit_status() { // Tests for nonzero exit codes from tests. let p = project() .file( "tests/t1.rs", r#" #[test] fn t() { panic!("this is a normal error") } "#, ) .file( "tests/t2.rs", r#" #[test] fn t() { std::process::exit(4) } "#, ) .build(); p.cargo("test --test t1") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] tests/t1.rs (target/debug/deps/t1-[HASH][EXE]) [ERROR] test failed, to rerun pass `--test t1` "#]]) .with_stdout_data(str![[r#" ... this is a normal error ... "#]]) .with_status(101) .run(); p.cargo("test --test t2") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] tests/t2.rs (target/debug/deps/t2-[HASH][EXE]) [ERROR] test failed, to rerun pass `--test t2` Caused by: process didn't exit successfully: `[ROOT]/foo/target/debug/deps/t2-[HASH][EXE]` ([EXIT_STATUS]: 4) [NOTE] test exited abnormally; to see the full output pass --nocapture to the harness. "#]]) .with_status(4) .run(); p.cargo("test --test t2 -- --nocapture") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] tests/t2.rs (target/debug/deps/t2-[HASH][EXE]) [ERROR] test failed, to rerun pass `--test t2` Caused by: process didn't exit successfully: `[ROOT]/foo/target/debug/deps/t2-[HASH][EXE] --nocapture` ([EXIT_STATUS]: 4) "#]]) .with_status(4) .run(); // no-fail-fast always uses 101 p.cargo("test --no-fail-fast") .with_stderr_data(str![[r#" [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] tests/t1.rs (target/debug/deps/t1-[HASH][EXE]) [ERROR] test failed, to rerun pass `--test t1` [RUNNING] tests/t2.rs (target/debug/deps/t2-[HASH][EXE]) [ERROR] test failed, to rerun pass `--test t2` Caused by: process didn't exit successfully: `[ROOT]/foo/target/debug/deps/t2-[HASH][EXE]` ([EXIT_STATUS]: 4) [NOTE] test exited abnormally; to see the full output pass --nocapture to the harness. [ERROR] 2 targets failed: `--test t1` `--test t2` "#]]) .with_status(101) .run(); p.cargo("test --no-fail-fast -- --nocapture") .with_stderr_does_not_contain( "test exited abnormally; to see the full output pass --nocapture to the harness.", ) .with_stderr_data(str![[r#" [..]thread [..]panicked [..] tests/t1.rs[..] [NOTE] run with `RUST_BACKTRACE=1` environment variable to display a backtrace Caused by: process didn't exit successfully: `[ROOT]/foo/target/debug/deps/t2-[HASH][EXE] --nocapture` ([EXIT_STATUS]: 4) ... "#]].unordered()) .with_status(101) .run(); } #[cargo_test] fn cargo_test_print_env_verbose() { let p = project() .file("Cargo.toml", &basic_manifest("foo", "0.0.1")) .file("src/lib.rs", "") .build(); p.cargo("test -vv").with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `[..]CARGO_MANIFEST_DIR=[ROOT]/foo[..] rustc --crate-name foo[..]` [RUNNING] `[..]CARGO_MANIFEST_DIR=[ROOT]/foo[..] rustc --crate-name foo[..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `[..]CARGO_MANIFEST_DIR=[ROOT]/foo[..] [ROOT]/foo/target/debug/deps/foo-[HASH][EXE]` [DOCTEST] foo [RUNNING] `[..]CARGO_MANIFEST_DIR=[ROOT]/foo[..] rustdoc --edition=2015 --crate-type lib --color auto --crate-name foo[..]` "#]]).run(); } #[cargo_test] fn cargo_test_set_out_dir_env_var() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2021" "#, ) .file( "src/lib.rs", r#" pub fn add(left: u64, right: u64) -> u64 { left + right } "#, ) .file( "build.rs", r#" fn main() {} "#, ) .file( "tests/case.rs", r#" #[cfg(test)] pub mod tests { #[test] fn test_add() { assert!(std::env::var("OUT_DIR").is_ok()); assert_eq!(foo::add(2, 5), 7); } } "#, ) .build(); p.cargo("test").run(); p.cargo("test --package foo --test case -- tests::test_add --exact --nocapture") .run(); } cargo-0.86.0/tests/testsuite/timings.rs000064400000000000000000000025361046102023000162330ustar 00000000000000//! Tests for --timings. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry::Package; use cargo_test_support::str; #[cargo_test] fn timings_works() { Package::new("dep", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] dep = "0.1" "#, ) .file("src/lib.rs", "") .file("src/main.rs", "fn main() {}") .file("tests/t1.rs", "") .file("examples/ex1.rs", "fn main() {}") .build(); p.cargo("build --all-targets --timings") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] dep v0.1.0 (registry `dummy-registry`) [COMPILING] dep v0.1.0 [COMPILING] foo v0.1.0 ([ROOT]/foo) Timing report saved to [ROOT]/foo/target/cargo-timings/cargo-timing-[..].html [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("clean").run(); p.cargo("test --timings").run(); p.cargo("clean").run(); p.cargo("check --timings").run(); p.cargo("clean").run(); p.cargo("doc --timings").run(); } cargo-0.86.0/tests/testsuite/tool_paths.rs000064400000000000000000000330701046102023000167320ustar 00000000000000//! Tests for configuration values that point to programs. use cargo_test_support::prelude::*; use cargo_test_support::{basic_lib_manifest, project, rustc_host, rustc_host_env, str}; #[cargo_test] fn pathless_tools() { let target = rustc_host(); let foo = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .file( ".cargo/config.toml", &format!( r#" [target.{}] linker = "nonexistent-linker" "#, target ), ) .build(); foo.cargo("build --verbose") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc [..]-C linker=nonexistent-linker [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } // can set a custom linker via `target.'cfg(..)'.linker` #[cargo_test] fn custom_linker_cfg() { let foo = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [target.'cfg(not(target_os = "none"))'] linker = "nonexistent-linker" "#, ) .build(); foo.cargo("build --verbose") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc [..]-C linker=nonexistent-linker [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } // custom linker set via `target.$triple.linker` have precede over `target.'cfg(..)'.linker` #[cargo_test] fn custom_linker_cfg_precedence() { let target = rustc_host(); let foo = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .file( ".cargo/config.toml", &format!( r#" [target.'cfg(not(target_os = "none"))'] linker = "ignored-linker" [target.{}] linker = "nonexistent-linker" "#, target ), ) .build(); foo.cargo("build --verbose") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc [..]-C linker=nonexistent-linker [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn custom_linker_cfg_collision() { let foo = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .file( ".cargo/config.toml", r#" [target.'cfg(not(target_arch = "avr"))'] linker = "nonexistent-linker1" [target.'cfg(not(target_os = "none"))'] linker = "nonexistent-linker2" "#, ) .build(); foo.cargo("build --verbose") .with_status(101) .with_stderr_data(str![[r#" [ERROR] several matching instances of `target.'cfg(..)'.linker` in configurations first match `cfg(not(target_arch = "avr"))` located in [ROOT]/foo/.cargo/config.toml second match `cfg(not(target_os = "none"))` located in [ROOT]/foo/.cargo/config.toml "#]]) .run(); } #[cargo_test] fn absolute_tools() { let target = rustc_host(); // Escaped as they appear within a TOML config file let linker = if cfg!(windows) { r#"C:\\bogus\\nonexistent-linker"# } else { r#"/bogus/nonexistent-linker"# }; let foo = project() .file("Cargo.toml", &basic_lib_manifest("foo")) .file("src/lib.rs", "") .file( ".cargo/config.toml", &format!( r#" [target.{target}] linker = "{linker}" "#, target = target, linker = linker ), ) .build(); foo.cargo("build --verbose") .with_stderr_data(str![[r#" [COMPILING] foo v0.5.0 ([ROOT]/foo) [RUNNING] `rustc [..]-C linker=[..]/bogus/nonexistent-linker [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn relative_tools() { let target = rustc_host(); // Escaped as they appear within a TOML config file let linker = if cfg!(windows) { r#".\\tools\\nonexistent-linker"# } else { r#"./tools/nonexistent-linker"# }; // Funky directory structure to test that relative tool paths are made absolute // by reference to the `.cargo/..` directory and not to (for example) the CWD. let p = project() .no_manifest() .file("bar/Cargo.toml", &basic_lib_manifest("bar")) .file("bar/src/lib.rs", "") .file( ".cargo/config.toml", &format!( r#" [target.{target}] linker = "{linker}" "#, target = target, linker = linker ), ) .build(); p.cargo("build --verbose") .cwd("bar") .with_stderr_data(str![[r#" [COMPILING] bar v0.5.0 ([ROOT]/foo/bar) [RUNNING] `rustc [..]-C linker=[ROOT]/foo/./tools/nonexistent-linker [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn custom_runner() { let target = rustc_host(); let p = project() .file("src/main.rs", "fn main() {}") .file("tests/test.rs", "") .file("benches/bench.rs", "") .file( ".cargo/config.toml", &format!( r#" [target.{}] runner = "nonexistent-runner -r" "#, target ), ) .build(); p.cargo("run -- --param") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `nonexistent-runner -r target/debug/foo[EXE] --param` ... "#]]) .run(); p.cargo("test --test test --verbose -- --param") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]` [FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `nonexistent-runner -r [ROOT]/foo/target/debug/deps/test-[HASH][EXE] --param` ... "#]]) .run(); p.cargo("bench --bench bench --verbose -- --param") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]` [RUNNING] `rustc [..]` [FINISHED] `bench` profile [optimized] target(s) in [ELAPSED]s [RUNNING] `nonexistent-runner -r [ROOT]/foo/target/release/deps/bench-[HASH][EXE] --param --bench` ... "#]]) .run(); } // can set a custom runner via `target.'cfg(..)'.runner` #[cargo_test] fn custom_runner_cfg() { let p = project() .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [target.'cfg(not(target_os = "none"))'] runner = "nonexistent-runner -r" "#, ) .build(); p.cargo("run -- --param") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `nonexistent-runner -r target/debug/foo[EXE] --param` ... "#]]) .run(); } // custom runner set via `target.$triple.runner` have precedence over `target.'cfg(..)'.runner` #[cargo_test] fn custom_runner_cfg_precedence() { let target = rustc_host(); let p = project() .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", &format!( r#" [target.'cfg(not(target_os = "none"))'] runner = "ignored-runner" [target.{}] runner = "nonexistent-runner -r" "#, target ), ) .build(); p.cargo("run -- --param") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `nonexistent-runner -r target/debug/foo[EXE] --param` ... "#]]) .run(); } #[cargo_test] fn custom_runner_cfg_collision() { let p = project() .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", r#" [target.'cfg(not(target_arch = "avr"))'] runner = "true" [target.'cfg(not(target_os = "none"))'] runner = "false" "#, ) .build(); p.cargo("run -- --param") .with_status(101) .with_stderr_data(str![[r#" [ERROR] several matching instances of `target.'cfg(..)'.runner` in configurations first match `cfg(not(target_arch = "avr"))` located in [ROOT]/foo/.cargo/config.toml second match `cfg(not(target_os = "none"))` located in [ROOT]/foo/.cargo/config.toml "#]]) .run(); } #[cargo_test] fn custom_runner_env() { let p = project().file("src/main.rs", "fn main() {}").build(); let key = format!("CARGO_TARGET_{}_RUNNER", rustc_host_env()); p.cargo("run") .env(&key, "nonexistent-runner --foo") .with_status(101) // FIXME: Update "Caused by" error message once rust/pull/87704 is merged. // On Windows, changing to a custom executable resolver has changed the // error messages. .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `nonexistent-runner --foo target/debug/foo[EXE]` [ERROR] could not execute process `nonexistent-runner --foo target/debug/foo[EXE]` (never executed) Caused by: [NOT_FOUND] "#]]) .run(); } #[cargo_test] fn custom_runner_env_overrides_config() { let target = rustc_host(); let p = project() .file("src/main.rs", "fn main() {}") .file( ".cargo/config.toml", &format!( r#" [target.{}] runner = "should-not-run -r" "#, target ), ) .build(); let key = format!("CARGO_TARGET_{}_RUNNER", rustc_host_env()); p.cargo("run") .env(&key, "should-run --foo") .with_status(101) .with_stderr_data(str![[r#" ... [RUNNING] `should-run --foo target/debug/foo[EXE]` ... "#]]) .run(); } #[cargo_test] #[cfg(unix)] // Assumes `true` is in PATH. fn custom_runner_env_true() { // Check for a bug where "true" was interpreted as a boolean instead of // the executable. let p = project().file("src/main.rs", "fn main() {}").build(); let key = format!("CARGO_TARGET_{}_RUNNER", rustc_host_env()); p.cargo("run") .env(&key, "true") .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `true target/debug/foo[EXE]` "#]]) .run(); } #[cargo_test] fn custom_linker_env() { let p = project().file("src/main.rs", "fn main() {}").build(); let key = format!("CARGO_TARGET_{}_LINKER", rustc_host_env()); p.cargo("build -v") .env(&key, "nonexistent-linker") .with_status(101) .with_stderr_data(str![[r#" [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc [..]-C linker=nonexistent-linker [..]` ... "#]]) .run(); } #[cargo_test] fn target_in_environment_contains_lower_case() { let p = project().file("src/main.rs", "fn main() {}").build(); let target = rustc_host(); let env_key = format!( "CARGO_TARGET_{}_LINKER", target.to_lowercase().replace('-', "_") ); p.cargo("build -v --target") .arg(target) .env(&env_key, "nonexistent-linker") .with_stderr_data(format!("\ [WARNING] environment variables are expected to use uppercase letters and underscores, the variable `{env_key}` will be ignored and have no effect [WARNING] environment variables are expected to use uppercase letters and underscores, the variable `{env_key}` will be ignored and have no effect [COMPILING] foo v0.0.1 ([ROOT]/foo) [RUNNING] `rustc --crate-name foo --edition=2015 src/main.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s " )) .run(); } #[cargo_test] fn cfg_ignored_fields() { // Test for some ignored fields in [target.'cfg()'] tables. let p = project() .file( ".cargo/config.toml", r#" # Try some empty tables. [target.'cfg(not(foo))'] [target.'cfg(not(bar))'.somelib] # A bunch of unused fields. [target.'cfg(not(target_os = "none"))'] linker = 'false' ar = 'false' foo = {rustc-flags = "-l foo"} invalid = 1 runner = 'false' rustflags = '' "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [WARNING] unused key `somelib` in [target] config table `cfg(not(bar))` [WARNING] unused key `ar` in [target] config table `cfg(not(target_os = "none"))` [WARNING] unused key `foo` in [target] config table `cfg(not(target_os = "none"))` [WARNING] unused key `invalid` in [target] config table `cfg(not(target_os = "none"))` [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/tree.rs000064400000000000000000001367421046102023000155270ustar 00000000000000//! Tests for the `cargo tree` command. use cargo_test_support::cross_compile::{self, alternate}; use cargo_test_support::prelude::*; use cargo_test_support::registry::{Dependency, Package}; use cargo_test_support::str; use cargo_test_support::{basic_manifest, git, project, rustc_host, Project}; use super::features2::switch_to_resolver_2; fn make_simple_proj() -> Project { Package::new("c", "1.0.0").publish(); Package::new("b", "1.0.0").dep("c", "1.0").publish(); Package::new("a", "1.0.0").dep("b", "1.0").publish(); Package::new("bdep", "1.0.0").dep("b", "1.0").publish(); Package::new("devdep", "1.0.0").dep("b", "1.0.0").publish(); project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] a = "1.0" c = "1.0" [build-dependencies] bdep = "1.0" [dev-dependencies] devdep = "1.0" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build() } #[cargo_test] fn simple() { // A simple test with a few different dependencies. let p = make_simple_proj(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ a v1.0.0 β”‚ └── b v1.0.0 β”‚ └── c v1.0.0 └── c v1.0.0 [build-dependencies] └── bdep v1.0.0 └── b v1.0.0 (*) [dev-dependencies] └── devdep v1.0.0 └── b v1.0.0 (*) "#]]) .run(); p.cargo("tree -p bdep") .with_stdout_data(str![[r#" bdep v1.0.0 └── b v1.0.0 └── c v1.0.0 "#]]) .run(); } #[cargo_test] fn virtual_workspace() { // Multiple packages in a virtual workspace. Package::new("somedep", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "baz", "c"] "#, ) .file("a/Cargo.toml", &basic_manifest("a", "1.0.0")) .file("a/src/lib.rs", "") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.0" [dependencies] c = { path = "../c" } somedep = "1.0" "#, ) .file("baz/src/lib.rs", "") .file("c/Cargo.toml", &basic_manifest("c", "1.0.0")) .file("c/src/lib.rs", "") .build(); p.cargo("tree") .with_stdout_data(str![[r#" a v1.0.0 ([ROOT]/foo/a) baz v0.1.0 ([ROOT]/foo/baz) β”œβ”€β”€ c v1.0.0 ([ROOT]/foo/c) └── somedep v1.0.0 c v1.0.0 ([ROOT]/foo/c) "#]]) .run(); p.cargo("tree -p a") .with_stdout_data(str![[r#" a v1.0.0 ([ROOT]/foo/a) "#]]) .run(); p.cargo("tree") .cwd("baz") .with_stdout_data(str![[r#" baz v0.1.0 ([ROOT]/foo/baz) β”œβ”€β”€ c v1.0.0 ([ROOT]/foo/c) └── somedep v1.0.0 "#]]) .run(); // exclude baz p.cargo("tree --workspace --exclude baz") .with_stdout_data(str![[r#" a v1.0.0 ([ROOT]/foo/a) c v1.0.0 ([ROOT]/foo/c) "#]]) .run(); // exclude glob '*z' p.cargo("tree --workspace --exclude '*z'") .with_stdout_data(str![[r#" a v1.0.0 ([ROOT]/foo/a) c v1.0.0 ([ROOT]/foo/c) "#]]) .run(); // include glob '*z' p.cargo("tree -p '*z'") .with_stdout_data(str![[r#" baz v0.1.0 ([ROOT]/foo/baz) β”œβ”€β”€ c v1.0.0 ([ROOT]/foo/c) └── somedep v1.0.0 "#]]) .run(); } #[cargo_test] fn dedupe_edges() { // Works around https://github.com/rust-lang/cargo/issues/7985 Package::new("bitflags", "1.0.0").publish(); Package::new("manyfeat", "1.0.0") .feature("f1", &[]) .feature("f2", &[]) .feature("f3", &[]) .dep("bitflags", "1.0") .publish(); Package::new("a", "1.0.0") .feature_dep("manyfeat", "1.0", &["f1"]) .publish(); Package::new("b", "1.0.0") .feature_dep("manyfeat", "1.0", &["f2"]) .publish(); Package::new("c", "1.0.0") .feature_dep("manyfeat", "1.0", &["f3"]) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] a = "1.0" b = "1.0" c = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ a v1.0.0 β”‚ └── manyfeat v1.0.0 β”‚ └── bitflags v1.0.0 β”œβ”€β”€ b v1.0.0 β”‚ └── manyfeat v1.0.0 (*) └── c v1.0.0 └── manyfeat v1.0.0 (*) "#]]) .run(); } #[cargo_test] fn renamed_deps() { // Handles renamed dependencies. Package::new("one", "1.0.0").publish(); Package::new("two", "1.0.0").publish(); Package::new("bar", "1.0.0").dep("one", "1.0").publish(); Package::new("bar", "2.0.0").dep("two", "1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" [dependencies] bar1 = {version = "1.0", package="bar"} bar2 = {version = "2.0", package="bar"} "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree") .with_stdout_data(str![[r#" foo v1.0.0 ([ROOT]/foo) β”œβ”€β”€ bar v1.0.0 β”‚ └── one v1.0.0 └── bar v2.0.0 └── two v1.0.0 "#]]) .run(); } #[cargo_test] fn source_kinds() { // Handles git and path sources. Package::new("regdep", "1.0.0").publish(); let git_project = git::new("gitdep", |p| { p.file("Cargo.toml", &basic_manifest("gitdep", "1.0.0")) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] regdep = "1.0" pathdep = {{ path = "pathdep" }} gitdep = {{ git = "{}" }} "#, git_project.url() ), ) .file("src/lib.rs", "") .file("pathdep/Cargo.toml", &basic_manifest("pathdep", "1.0.0")) .file("pathdep/src/lib.rs", "") .build(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ gitdep v1.0.0 ([ROOTURL]/gitdep#[..]) β”œβ”€β”€ pathdep v1.0.0 ([ROOT]/foo/pathdep) └── regdep v1.0.0 "#]]) .run(); } #[cargo_test] fn features() { // Exercises a variety of feature behaviors. Package::new("optdep_default", "1.0.0").publish(); Package::new("optdep", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "a" version = "0.1.0" [dependencies] optdep_default = { version = "1.0", optional = true } optdep = { version = "1.0", optional = true } [features] default = ["optdep_default"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree") .with_stdout_data(str![[r#" a v0.1.0 ([ROOT]/foo) └── optdep_default v1.0.0 "#]]) .run(); p.cargo("tree --no-default-features") .with_stdout_data(str![[r#" a v0.1.0 ([ROOT]/foo) "#]]) .run(); p.cargo("tree --all-features") .with_stdout_data(str![[r#" a v0.1.0 ([ROOT]/foo) β”œβ”€β”€ optdep v1.0.0 └── optdep_default v1.0.0 "#]]) .run(); p.cargo("tree --features optdep") .with_stdout_data(str![[r#" a v0.1.0 ([ROOT]/foo) β”œβ”€β”€ optdep v1.0.0 └── optdep_default v1.0.0 "#]]) .run(); } #[cargo_test] fn filters_target() { // --target flag if cross_compile::disabled() { return; } Package::new("targetdep", "1.0.0").publish(); Package::new("hostdep", "1.0.0").publish(); Package::new("devdep", "1.0.0").publish(); Package::new("build_target_dep", "1.0.0").publish(); Package::new("build_host_dep", "1.0.0") .target_dep("targetdep", "1.0", alternate()) .target_dep("hostdep", "1.0", rustc_host()) .publish(); Package::new("pm_target", "1.0.0") .proc_macro(true) .publish(); Package::new("pm_host", "1.0.0").proc_macro(true).publish(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [target.'{alt}'.dependencies] targetdep = "1.0" pm_target = "1.0" [target.'{host}'.dependencies] hostdep = "1.0" pm_host = "1.0" [target.'{alt}'.dev-dependencies] devdep = "1.0" [target.'{alt}'.build-dependencies] build_target_dep = "1.0" [target.'{host}'.build-dependencies] build_host_dep = "1.0" "#, alt = alternate(), host = rustc_host() ), ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ hostdep v1.0.0 └── pm_host v1.0.0 (proc-macro) [build-dependencies] └── build_host_dep v1.0.0 └── hostdep v1.0.0 "#]]) .run(); p.cargo("tree --target") .arg(alternate()) .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ pm_target v1.0.0 (proc-macro) └── targetdep v1.0.0 [build-dependencies] └── build_host_dep v1.0.0 └── hostdep v1.0.0 [dev-dependencies] └── devdep v1.0.0 "#]]) .run(); p.cargo("tree --target") .arg(rustc_host()) .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ hostdep v1.0.0 └── pm_host v1.0.0 (proc-macro) [build-dependencies] └── build_host_dep v1.0.0 └── hostdep v1.0.0 "#]]) .run(); p.cargo("tree --target=all") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ hostdep v1.0.0 β”œβ”€β”€ pm_host v1.0.0 (proc-macro) β”œβ”€β”€ pm_target v1.0.0 (proc-macro) └── targetdep v1.0.0 [build-dependencies] β”œβ”€β”€ build_host_dep v1.0.0 β”‚ β”œβ”€β”€ hostdep v1.0.0 β”‚ └── targetdep v1.0.0 └── build_target_dep v1.0.0 [dev-dependencies] └── devdep v1.0.0 "#]]) .run(); // no-proc-macro p.cargo("tree --target=all -e no-proc-macro") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ hostdep v1.0.0 └── targetdep v1.0.0 [build-dependencies] β”œβ”€β”€ build_host_dep v1.0.0 β”‚ β”œβ”€β”€ hostdep v1.0.0 β”‚ └── targetdep v1.0.0 └── build_target_dep v1.0.0 [dev-dependencies] └── devdep v1.0.0 "#]]) .run(); } #[cargo_test] fn no_selected_target_dependency() { // --target flag if cross_compile::disabled() { return; } Package::new("targetdep", "1.0.0").publish(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [target.'{alt}'.dependencies] targetdep = "1.0" "#, alt = alternate(), ), ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) "#]]) .run(); p.cargo("tree -i targetdep") .with_stderr_data(str![[r#" [WARNING] nothing to print. To find dependencies that require specific target platforms, try to use option `--target all` first, and then narrow your search scope accordingly. "#]]) .run(); p.cargo("tree -i targetdep --target all") .with_stdout_data(str![[r#" targetdep v1.0.0 └── foo v0.1.0 ([ROOT]/foo) "#]]) .run(); } #[cargo_test] fn dep_kinds() { Package::new("inner-devdep", "1.0.0").publish(); Package::new("inner-builddep", "1.0.0").publish(); Package::new("inner-normal", "1.0.0").publish(); Package::new("inner-pm", "1.0.0").proc_macro(true).publish(); Package::new("inner-buildpm", "1.0.0") .proc_macro(true) .publish(); Package::new("normaldep", "1.0.0") .dep("inner-normal", "1.0") .dev_dep("inner-devdep", "1.0") .build_dep("inner-builddep", "1.0") .publish(); Package::new("devdep", "1.0.0") .dep("inner-normal", "1.0") .dep("inner-pm", "1.0") .dev_dep("inner-devdep", "1.0") .build_dep("inner-builddep", "1.0") .build_dep("inner-buildpm", "1.0") .publish(); Package::new("builddep", "1.0.0") .dep("inner-normal", "1.0") .dev_dep("inner-devdep", "1.0") .build_dep("inner-builddep", "1.0") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] normaldep = "1.0" [dev-dependencies] devdep = "1.0" [build-dependencies] builddep = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── normaldep v1.0.0 └── inner-normal v1.0.0 [build-dependencies] └── inner-builddep v1.0.0 [build-dependencies] └── builddep v1.0.0 └── inner-normal v1.0.0 [build-dependencies] └── inner-builddep v1.0.0 [dev-dependencies] └── devdep v1.0.0 β”œβ”€β”€ inner-normal v1.0.0 └── inner-pm v1.0.0 (proc-macro) [build-dependencies] β”œβ”€β”€ inner-builddep v1.0.0 └── inner-buildpm v1.0.0 (proc-macro) "#]]) .run(); p.cargo("tree -e no-dev") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── normaldep v1.0.0 └── inner-normal v1.0.0 [build-dependencies] └── inner-builddep v1.0.0 [build-dependencies] └── builddep v1.0.0 └── inner-normal v1.0.0 [build-dependencies] └── inner-builddep v1.0.0 "#]]) .run(); p.cargo("tree -e normal") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── normaldep v1.0.0 └── inner-normal v1.0.0 "#]]) .run(); p.cargo("tree -e dev,build") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) [build-dependencies] └── builddep v1.0.0 [build-dependencies] └── inner-builddep v1.0.0 [dev-dependencies] └── devdep v1.0.0 [build-dependencies] β”œβ”€β”€ inner-builddep v1.0.0 └── inner-buildpm v1.0.0 (proc-macro) "#]]) .run(); p.cargo("tree -e dev,build,no-proc-macro") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) [build-dependencies] └── builddep v1.0.0 [build-dependencies] └── inner-builddep v1.0.0 [dev-dependencies] └── devdep v1.0.0 [build-dependencies] └── inner-builddep v1.0.0 "#]]) .run(); } #[cargo_test] fn cyclic_dev_dep() { // Cyclical dev-dependency and inverse flag. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dev-dependencies] dev-dep = { path = "dev-dep" } "#, ) .file("src/lib.rs", "") .file( "dev-dep/Cargo.toml", r#" [package] name = "dev-dep" version = "0.1.0" [dependencies] foo = { path=".." } "#, ) .file("dev-dep/src/lib.rs", "") .build(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) [dev-dependencies] └── dev-dep v0.1.0 ([ROOT]/foo/dev-dep) └── foo v0.1.0 ([ROOT]/foo) (*) "#]]) .run(); p.cargo("tree --invert foo") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── dev-dep v0.1.0 ([ROOT]/foo/dev-dep) [dev-dependencies] └── foo v0.1.0 ([ROOT]/foo) (*) "#]]) .run(); } #[cargo_test] fn invert() { Package::new("b1", "1.0.0").dep("c", "1.0").publish(); Package::new("b2", "1.0.0").dep("d", "1.0").publish(); Package::new("c", "1.0.0").publish(); Package::new("d", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] b1 = "1.0" b2 = "1.0" c = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ b1 v1.0.0 β”‚ └── c v1.0.0 β”œβ”€β”€ b2 v1.0.0 β”‚ └── d v1.0.0 └── c v1.0.0 "#]]) .run(); p.cargo("tree --invert c") .with_stdout_data(str![[r#" c v1.0.0 β”œβ”€β”€ b1 v1.0.0 β”‚ └── foo v0.1.0 ([ROOT]/foo) └── foo v0.1.0 ([ROOT]/foo) "#]]) .run(); } #[cargo_test] fn invert_with_build_dep() { // -i for a common dependency between normal and build deps. Package::new("common", "1.0.0").publish(); Package::new("bdep", "1.0.0").dep("common", "1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] common = "1.0" [build-dependencies] bdep = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── common v1.0.0 [build-dependencies] └── bdep v1.0.0 └── common v1.0.0 "#]]) .run(); p.cargo("tree -i common") .with_stdout_data(str![[r#" common v1.0.0 β”œβ”€β”€ bdep v1.0.0 β”‚ [build-dependencies] β”‚ └── foo v0.1.0 ([ROOT]/foo) └── foo v0.1.0 ([ROOT]/foo) "#]]) .run(); } #[cargo_test] fn no_indent() { let p = make_simple_proj(); p.cargo("tree --prefix=none") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) a v1.0.0 b v1.0.0 c v1.0.0 c v1.0.0 bdep v1.0.0 b v1.0.0 (*) devdep v1.0.0 b v1.0.0 (*) "#]]) .run(); } #[cargo_test] fn prefix_depth() { let p = make_simple_proj(); p.cargo("tree --prefix=depth") .with_stdout_data(str![[r#" 0foo v0.1.0 ([ROOT]/foo) 1a v1.0.0 2b v1.0.0 3c v1.0.0 1c v1.0.0 1bdep v1.0.0 2b v1.0.0 (*) 1devdep v1.0.0 2b v1.0.0 (*) "#]]) .run(); } #[cargo_test] fn no_dedupe() { let p = make_simple_proj(); p.cargo("tree --no-dedupe") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ a v1.0.0 β”‚ └── b v1.0.0 β”‚ └── c v1.0.0 └── c v1.0.0 [build-dependencies] └── bdep v1.0.0 └── b v1.0.0 └── c v1.0.0 [dev-dependencies] └── devdep v1.0.0 └── b v1.0.0 └── c v1.0.0 "#]]) .run(); } #[cargo_test] fn no_dedupe_cycle() { // --no-dedupe with a dependency cycle let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dev-dependencies] bar = {path = "bar"} "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" [dependencies] foo = {path=".."} "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) [dev-dependencies] └── bar v0.1.0 ([ROOT]/foo/bar) └── foo v0.1.0 ([ROOT]/foo) (*) "#]]) .run(); p.cargo("tree --no-dedupe") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) [dev-dependencies] └── bar v0.1.0 ([ROOT]/foo/bar) └── foo v0.1.0 ([ROOT]/foo) (*) "#]]) .run(); } #[cargo_test] fn duplicates() { Package::new("dog", "1.0.0").publish(); Package::new("dog", "2.0.0").publish(); Package::new("cat", "1.0.0").publish(); Package::new("cat", "2.0.0").publish(); Package::new("dep", "1.0.0") .dep("dog", "1.0") .dep("cat", "1.0") .publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" [dependencies] dog1 = { version = "1.0", package = "dog" } dog2 = { version = "2.0", package = "dog" } "#, ) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" [dependencies] dep = "1.0" cat = "2.0" "#, ) .file("b/src/lib.rs", "") .build(); p.cargo("tree -p a") .with_stdout_data(str![[r#" a v0.1.0 ([ROOT]/foo/a) β”œβ”€β”€ dog v1.0.0 └── dog v2.0.0 "#]]) .run(); p.cargo("tree -p b") .with_stdout_data(str![[r#" b v0.1.0 ([ROOT]/foo/b) β”œβ”€β”€ cat v2.0.0 └── dep v1.0.0 β”œβ”€β”€ cat v1.0.0 └── dog v1.0.0 "#]]) .run(); p.cargo("tree -p a -d") .with_stdout_data(str![[r#" dog v1.0.0 └── a v0.1.0 ([ROOT]/foo/a) dog v2.0.0 └── a v0.1.0 ([ROOT]/foo/a) "#]]) .run(); p.cargo("tree -p b -d") .with_stdout_data(str![[r#" cat v1.0.0 └── dep v1.0.0 └── b v0.1.0 ([ROOT]/foo/b) cat v2.0.0 └── b v0.1.0 ([ROOT]/foo/b) "#]]) .run(); } #[cargo_test] fn duplicates_with_target() { // --target flag if cross_compile::disabled() { return; } Package::new("a", "1.0.0").publish(); Package::new("dog", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] a = "1.0" dog = "1.0" [build-dependencies] a = "1.0" dog = "1.0" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); p.cargo("tree -d").with_stdout_data(str![""]).run(); p.cargo("tree -d --target") .arg(alternate()) .with_stdout_data(str![""]) .run(); p.cargo("tree -d --target") .arg(rustc_host()) .with_stdout_data(str![""]) .run(); p.cargo("tree -d --target=all") .with_stdout_data(str![""]) .run(); } #[cargo_test] fn duplicates_with_proc_macro() { Package::new("dupe-dep", "1.0.0").publish(); Package::new("dupe-dep", "2.0.0").publish(); Package::new("proc", "1.0.0") .proc_macro(true) .dep("dupe-dep", "1.0") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] proc = "1.0" dupe-dep = "2.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ dupe-dep v2.0.0 └── proc v1.0.0 (proc-macro) └── dupe-dep v1.0.0 "#]]) .run(); p.cargo("tree --duplicates") .with_stdout_data(str![[r#" dupe-dep v1.0.0 └── proc v1.0.0 (proc-macro) └── foo v0.1.0 ([ROOT]/foo) dupe-dep v2.0.0 └── foo v0.1.0 ([ROOT]/foo) "#]]) .run(); p.cargo("tree --duplicates --edges no-proc-macro") .with_stdout_data(str![""]) .run(); } #[cargo_test] fn charset() { let p = make_simple_proj(); p.cargo("tree --charset ascii") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) |-- a v1.0.0 | `-- b v1.0.0 | `-- c v1.0.0 `-- c v1.0.0 [build-dependencies] `-- bdep v1.0.0 `-- b v1.0.0 (*) [dev-dependencies] `-- devdep v1.0.0 `-- b v1.0.0 (*) "#]]) .run(); } #[cargo_test] fn format() { Package::new("dep", "1.0.0").publish(); Package::new("other-dep", "1.0.0").publish(); Package::new("dep_that_is_awesome", "1.0.0") .file( "Cargo.toml", r#" [package] name = "dep_that_is_awesome" version = "1.0.0" [lib] name = "awesome_dep" "#, ) .file("src/lib.rs", "pub struct Straw;") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" license = "MIT" repository = "https://github.com/rust-lang/cargo" [dependencies] dep = {version="1.0", optional=true} other-dep = {version="1.0", optional=true} dep_that_is_awesome = {version="1.0", optional=true} [features] default = ["foo"] foo = ["bar"] bar = [] "#, ) .file("src/main.rs", "") .build(); p.cargo("tree --format <<<{p}>>>") .with_stdout_data(str![[r#" <<>> "#]]) .run(); p.cargo("tree --format {}") .with_stderr_data(str![[r#" [ERROR] tree format `{}` not valid Caused by: unsupported pattern `` "#]]) .with_status(101) .run(); p.cargo("tree --format {p}-{{hello}}") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo)-{hello} "#]]) .run(); p.cargo("tree --format") .arg("{p} {l} {r}") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) MIT https://github.com/rust-lang/cargo "#]]) .run(); p.cargo("tree --format") .arg("{p} {f}") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) bar,default,foo "#]]) .run(); p.cargo("tree --all-features --format") .arg("{p} [{f}]") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) [bar,default,dep,dep_that_is_awesome,foo,other-dep] β”œβ”€β”€ dep v1.0.0 [] β”œβ”€β”€ dep_that_is_awesome v1.0.0 [] └── other-dep v1.0.0 [] "#]]) .run(); p.cargo("tree") .arg("--features=other-dep,dep_that_is_awesome") .arg("--format={lib}") .with_stdout_data(str![[r#" β”œβ”€β”€ awesome_dep └── other_dep "#]]) .run(); } #[cargo_test] fn dev_dep_feature() { // New feature resolver with optional dep Package::new("optdep", "1.0.0").publish(); Package::new("bar", "1.0.0") .add_dep(Dependency::new("optdep", "1.0").optional(true)) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dev-dependencies] bar = { version = "1.0", features = ["optdep"] } [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); // Old behavior. p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar v1.0.0 └── optdep v1.0.0 [dev-dependencies] └── bar v1.0.0 (*) "#]]) .run(); p.cargo("tree -e normal") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar v1.0.0 └── optdep v1.0.0 "#]]) .run(); // New behavior. switch_to_resolver_2(&p); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar v1.0.0 └── optdep v1.0.0 [dev-dependencies] └── bar v1.0.0 (*) "#]]) .run(); p.cargo("tree -e normal") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar v1.0.0 "#]]) .run(); } #[cargo_test] fn host_dep_feature() { // New feature resolver with optional build dep Package::new("optdep", "1.0.0").publish(); Package::new("bar", "1.0.0") .add_dep(Dependency::new("optdep", "1.0").optional(true)) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [build-dependencies] bar = { version = "1.0", features = ["optdep"] } [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") .build(); // Old behavior p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar v1.0.0 └── optdep v1.0.0 [build-dependencies] └── bar v1.0.0 (*) "#]]) .run(); // -p p.cargo("tree -p bar") .with_stdout_data(str![[r#" bar v1.0.0 └── optdep v1.0.0 "#]]) .run(); // invert p.cargo("tree -i optdep") .with_stdout_data(str![[r#" optdep v1.0.0 └── bar v1.0.0 └── foo v0.1.0 ([ROOT]/foo) [build-dependencies] └── foo v0.1.0 ([ROOT]/foo) "#]]) .run(); // New behavior. switch_to_resolver_2(&p); p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar v1.0.0 [build-dependencies] └── bar v1.0.0 └── optdep v1.0.0 "#]]) .run(); p.cargo("tree -p bar") .with_stdout_data(str![[r#" bar v1.0.0 bar v1.0.0 └── optdep v1.0.0 "#]]) .run(); p.cargo("tree -i optdep") .with_stdout_data(str![[r#" optdep v1.0.0 └── bar v1.0.0 [build-dependencies] └── foo v0.1.0 ([ROOT]/foo) "#]]) .run(); // Check that -d handles duplicates with features. p.cargo("tree -d") .with_stdout_data(str![[r#" bar v1.0.0 └── foo v0.1.0 ([ROOT]/foo) bar v1.0.0 [build-dependencies] └── foo v0.1.0 ([ROOT]/foo) "#]]) .run(); } #[cargo_test] fn proc_macro_features() { // New feature resolver with a proc-macro Package::new("optdep", "1.0.0").publish(); Package::new("somedep", "1.0.0") .add_dep(Dependency::new("optdep", "1.0").optional(true)) .publish(); Package::new("pm", "1.0.0") .proc_macro(true) .feature_dep("somedep", "1.0", &["optdep"]) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] pm = "1.0" somedep = "1.0" "#, ) .file("src/lib.rs", "") .build(); // Old behavior p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ pm v1.0.0 (proc-macro) β”‚ └── somedep v1.0.0 β”‚ └── optdep v1.0.0 └── somedep v1.0.0 (*) "#]]) .run(); // Old behavior + no-proc-macro p.cargo("tree -e no-proc-macro") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── somedep v1.0.0 └── optdep v1.0.0 "#]]) .run(); // -p p.cargo("tree -p somedep") .with_stdout_data(str![[r#" somedep v1.0.0 └── optdep v1.0.0 "#]]) .run(); // -p -e no-proc-macro p.cargo("tree -p somedep -e no-proc-macro") .with_stdout_data(str![[r#" somedep v1.0.0 └── optdep v1.0.0 "#]]) .run(); // invert p.cargo("tree -i somedep") .with_stdout_data(str![[r#" somedep v1.0.0 β”œβ”€β”€ foo v0.1.0 ([ROOT]/foo) └── pm v1.0.0 (proc-macro) └── foo v0.1.0 ([ROOT]/foo) "#]]) .run(); // invert + no-proc-macro p.cargo("tree -i somedep -e no-proc-macro") .with_stdout_data(str![[r#" somedep v1.0.0 └── foo v0.1.0 ([ROOT]/foo) "#]]) .run(); // New behavior. switch_to_resolver_2(&p); // Note the missing (*) p.cargo("tree") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ pm v1.0.0 (proc-macro) β”‚ └── somedep v1.0.0 β”‚ └── optdep v1.0.0 └── somedep v1.0.0 "#]]) .run(); p.cargo("tree -e no-proc-macro") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── somedep v1.0.0 "#]]) .run(); p.cargo("tree -p somedep") .with_stdout_data(str![[r#" somedep v1.0.0 somedep v1.0.0 └── optdep v1.0.0 "#]]) .run(); p.cargo("tree -i somedep") .with_stdout_data(str![[r#" somedep v1.0.0 └── foo v0.1.0 ([ROOT]/foo) somedep v1.0.0 └── pm v1.0.0 (proc-macro) └── foo v0.1.0 ([ROOT]/foo) "#]]) .run(); p.cargo("tree -i somedep -e no-proc-macro") .with_stdout_data(str![[r#" somedep v1.0.0 └── foo v0.1.0 ([ROOT]/foo) "#]]) .run(); } #[cargo_test] fn itarget_opt_dep() { // New feature resolver with optional target dep Package::new("optdep", "1.0.0").publish(); Package::new("common", "1.0.0") .add_dep(Dependency::new("optdep", "1.0").optional(true)) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" [dependencies] common = "1.0" [target.'cfg(whatever)'.dependencies] common = { version = "1.0", features = ["optdep"] } "#, ) .file("src/lib.rs", "") .build(); // Old behavior p.cargo("tree") .with_stdout_data(str![[r#" foo v1.0.0 ([ROOT]/foo) └── common v1.0.0 └── optdep v1.0.0 "#]]) .run(); // New behavior. switch_to_resolver_2(&p); p.cargo("tree") .with_stdout_data(str![[r#" foo v1.0.0 ([ROOT]/foo) └── common v1.0.0 "#]]) .run(); } #[cargo_test] fn ambiguous_name() { // -p that is ambiguous. Package::new("dep", "1.0.0").publish(); Package::new("dep", "2.0.0").publish(); Package::new("bar", "1.0.0").dep("dep", "2.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] dep = "1.0" bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree -p dep") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 3 packages to latest compatible versions [ADDING] dep v1.0.0 (available: v2.0.0) [DOWNLOADING] crates ... [DOWNLOADED] dep v2.0.0 (registry `dummy-registry`) [DOWNLOADED] dep v1.0.0 (registry `dummy-registry`) [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [ERROR] There are multiple `dep` packages in your project, and the specification `dep` is ambiguous. Please re-run this command with one of the following specifications: dep@1.0.0 dep@2.0.0 "#]]) .with_status(101) .run(); } #[cargo_test] fn workspace_features_are_local() { // The features for workspace packages should be the same as `cargo build` // (i.e., the features selected depend on the "current" package). Package::new("optdep", "1.0.0").publish(); Package::new("somedep", "1.0.0") .add_dep(Dependency::new("optdep", "1.0").optional(true)) .publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" [dependencies] somedep = {version="1.0", features=["optdep"]} "#, ) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" [dependencies] somedep = "1.0" "#, ) .file("b/src/lib.rs", "") .build(); p.cargo("tree") .with_stdout_data(str![[r#" a v0.1.0 ([ROOT]/foo/a) └── somedep v1.0.0 └── optdep v1.0.0 b v0.1.0 ([ROOT]/foo/b) └── somedep v1.0.0 (*) "#]]) .run(); p.cargo("tree -p a") .with_stdout_data(str![[r#" a v0.1.0 ([ROOT]/foo/a) └── somedep v1.0.0 └── optdep v1.0.0 "#]]) .run(); p.cargo("tree -p b") .with_stdout_data(str![[r#" b v0.1.0 ([ROOT]/foo/b) └── somedep v1.0.0 "#]]) .run(); } #[cargo_test] fn unknown_edge_kind() { let p = project() .file("Cargo.toml", "") .file("src/lib.rs", "") .build(); p.cargo("tree -e unknown") .with_stderr_data(str![[r#" [ERROR] unknown edge kind `unknown`, valid values are "normal", "build", "dev", "no-normal", "no-build", "no-dev", "no-proc-macro", "features", or "all" "#]]) .with_status(101) .run(); } #[cargo_test] fn mixed_no_edge_kinds() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree -e no-build,normal") .with_stderr_data(str![[r#" [ERROR] `normal` dependency kind cannot be mixed with "no-normal", "no-build", or "no-dev" dependency kinds "#]]) .with_status(101) .run(); // `no-proc-macro` can be mixed with others p.cargo("tree -e no-proc-macro,normal") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) "#]]) .run(); } #[cargo_test] fn depth_limit() { let p = make_simple_proj(); p.cargo("tree --depth 0") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) [build-dependencies] [dev-dependencies] "#]]) .run(); p.cargo("tree --depth 1") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ a v1.0.0 └── c v1.0.0 [build-dependencies] └── bdep v1.0.0 [dev-dependencies] └── devdep v1.0.0 "#]]) .run(); p.cargo("tree --depth 2") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ a v1.0.0 β”‚ └── b v1.0.0 └── c v1.0.0 [build-dependencies] └── bdep v1.0.0 └── b v1.0.0 (*) [dev-dependencies] └── devdep v1.0.0 └── b v1.0.0 (*) "#]]) .run(); // specify a package p.cargo("tree -p bdep --depth 1") .with_stdout_data(str![[r#" bdep v1.0.0 └── b v1.0.0 "#]]) .run(); // different prefix p.cargo("tree --depth 1 --prefix depth") .with_stdout_data(str![[r#" 0foo v0.1.0 ([ROOT]/foo) 1a v1.0.0 1c v1.0.0 1bdep v1.0.0 1devdep v1.0.0 "#]]) .run(); // with edge-kinds p.cargo("tree --depth 1 -e no-dev") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ a v1.0.0 └── c v1.0.0 [build-dependencies] └── bdep v1.0.0 "#]]) .run(); // invert p.cargo("tree --depth 1 --invert c") .with_stdout_data(str![[r#" c v1.0.0 β”œβ”€β”€ b v1.0.0 └── foo v0.1.0 ([ROOT]/foo) "#]]) .run(); } #[cargo_test] fn depth_workspace() { Package::new("somedep", "1.0.0").publish(); Package::new("otherdep", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b", "c"] "#, ) .file("a/Cargo.toml", &basic_manifest("a", "1.0.0")) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" [dependencies] c = { path = "../c" } somedep = "1" "#, ) .file("b/src/lib.rs", "") .file( "c/Cargo.toml", r#" [package] name = "c" version = "0.1.0" [dependencies] somedep = "1" otherdep = "1" "#, ) .file("c/src/lib.rs", "") .build(); p.cargo("tree --depth workspace") .with_stdout_data(str![[r#" a v1.0.0 ([ROOT]/foo/a) b v0.1.0 ([ROOT]/foo/b) └── c v0.1.0 ([ROOT]/foo/c) c v0.1.0 ([ROOT]/foo/c) (*) "#]]) .run(); } #[cargo_test] fn prune() { let p = make_simple_proj(); p.cargo("tree --prune c") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── a v1.0.0 └── b v1.0.0 [build-dependencies] └── bdep v1.0.0 └── b v1.0.0 (*) [dev-dependencies] └── devdep v1.0.0 └── b v1.0.0 (*) "#]]) .run(); // multiple prune p.cargo("tree --prune c --prune bdep") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── a v1.0.0 └── b v1.0.0 [build-dependencies] [dev-dependencies] └── devdep v1.0.0 └── b v1.0.0 (*) "#]]) .run(); // with edge-kinds p.cargo("tree --prune c -e normal") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── a v1.0.0 └── b v1.0.0 "#]]) .run(); // pruning self does not works p.cargo("tree --prune foo") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ a v1.0.0 β”‚ └── b v1.0.0 β”‚ └── c v1.0.0 └── c v1.0.0 [build-dependencies] └── bdep v1.0.0 └── b v1.0.0 (*) [dev-dependencies] └── devdep v1.0.0 └── b v1.0.0 (*) "#]]) .run(); // dep not exist p.cargo("tree --prune no-dep") .with_stderr_data(str![[r#" [ERROR] package ID specification `no-dep` did not match any packages Did you mean `bdep`? "#]]) .with_status(101) .run(); } #[cargo_test] fn cyclic_features() { // Check for stack overflow with cyclic features (oops!). let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" [features] a = ["b"] b = ["a"] default = ["a"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree -e features") .with_stdout_data(str![[r#" foo v1.0.0 ([ROOT]/foo) "#]]) .run(); p.cargo("tree -e features -i foo") .with_stdout_data(str![[r#" foo v1.0.0 ([ROOT]/foo) β”œβ”€β”€ foo feature "a" β”‚ β”œβ”€β”€ foo feature "b" β”‚ β”‚ └── foo feature "a" (*) β”‚ └── foo feature "default" (command-line) β”œβ”€β”€ foo feature "b" (*) └── foo feature "default" (command-line) "#]]) .run(); } #[cargo_test] fn dev_dep_cycle_with_feature() { // Cycle with features and a dev-dependency. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" [dev-dependencies] bar = { path = "bar" } [features] a = ["bar/feat1"] "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "1.0.0" [dependencies] foo = { path = ".." } [features] feat1 = ["foo/a"] "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("tree -e features --features a") .with_stdout_data(str![[r#" foo v1.0.0 ([ROOT]/foo) [dev-dependencies] └── bar feature "default" └── bar v1.0.0 ([ROOT]/foo/bar) └── foo feature "default" (command-line) └── foo v1.0.0 ([ROOT]/foo) (*) "#]]) .run(); p.cargo("tree -e features --features a -i foo") .with_stdout_data(str![[r#" foo v1.0.0 ([ROOT]/foo) β”œβ”€β”€ foo feature "a" (command-line) β”‚ └── bar feature "feat1" β”‚ └── foo feature "a" (command-line) (*) └── foo feature "default" (command-line) └── bar v1.0.0 ([ROOT]/foo/bar) β”œβ”€β”€ bar feature "default" β”‚ [dev-dependencies] β”‚ └── foo v1.0.0 ([ROOT]/foo) (*) └── bar feature "feat1" (*) "#]]) .run(); } #[cargo_test] fn dev_dep_cycle_with_feature_nested() { // Checks for an issue where a cyclic dev dependency tries to activate a // feature on its parent that tries to activate the feature back on the // dev-dependency. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" [dev-dependencies] bar = { path = "bar" } [features] a = ["bar/feat1"] b = ["a"] "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "1.0.0" [dependencies] foo = { path = ".." } [features] feat1 = ["foo/b"] "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("tree -e features") .with_stdout_data(str![[r#" foo v1.0.0 ([ROOT]/foo) [dev-dependencies] └── bar feature "default" └── bar v1.0.0 ([ROOT]/foo/bar) └── foo feature "default" (command-line) └── foo v1.0.0 ([ROOT]/foo) (*) "#]]) .run(); p.cargo("tree -e features --features a -i foo") .with_stdout_data(str![[r#" foo v1.0.0 ([ROOT]/foo) β”œβ”€β”€ foo feature "a" (command-line) β”‚ └── foo feature "b" β”‚ └── bar feature "feat1" β”‚ └── foo feature "a" (command-line) (*) β”œβ”€β”€ foo feature "b" (*) └── foo feature "default" (command-line) └── bar v1.0.0 ([ROOT]/foo/bar) β”œβ”€β”€ bar feature "default" β”‚ [dev-dependencies] β”‚ └── foo v1.0.0 ([ROOT]/foo) (*) └── bar feature "feat1" (*) "#]]) .run(); p.cargo("tree -e features --features b -i foo") .with_stdout_data(str![[r#" foo v1.0.0 ([ROOT]/foo) β”œβ”€β”€ foo feature "a" β”‚ └── foo feature "b" (command-line) β”‚ └── bar feature "feat1" β”‚ └── foo feature "a" (*) β”œβ”€β”€ foo feature "b" (command-line) (*) └── foo feature "default" (command-line) └── bar v1.0.0 ([ROOT]/foo/bar) β”œβ”€β”€ bar feature "default" β”‚ [dev-dependencies] β”‚ └── foo v1.0.0 ([ROOT]/foo) (*) └── bar feature "feat1" (*) "#]]) .run(); p.cargo("tree -e features --features bar/feat1 -i foo") .with_stdout_data(str![[r#" foo v1.0.0 ([ROOT]/foo) β”œβ”€β”€ foo feature "a" β”‚ └── foo feature "b" β”‚ └── bar feature "feat1" (command-line) β”‚ └── foo feature "a" (*) β”œβ”€β”€ foo feature "b" (*) └── foo feature "default" (command-line) └── bar v1.0.0 ([ROOT]/foo/bar) β”œβ”€β”€ bar feature "default" β”‚ [dev-dependencies] β”‚ └── foo v1.0.0 ([ROOT]/foo) (*) └── bar feature "feat1" (command-line) (*) "#]]) .run(); } cargo-0.86.0/tests/testsuite/tree_graph_features.rs000064400000000000000000000233431046102023000205760ustar 00000000000000//! Tests for the `cargo tree` command with -e features option. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry::{Dependency, Package}; use cargo_test_support::str; #[cargo_test] fn dep_feature_various() { // Checks different ways of setting features via dependencies. Package::new("optdep", "1.0.0") .feature("default", &["cat"]) .feature("cat", &[]) .publish(); Package::new("defaultdep", "1.0.0") .feature("default", &["f1"]) .feature("f1", &["optdep"]) .add_dep(Dependency::new("optdep", "1.0").optional(true)) .publish(); Package::new("nodefaultdep", "1.0.0") .feature("default", &["f1"]) .feature("f1", &[]) .publish(); Package::new("nameddep", "1.0.0") .add_dep(Dependency::new("serde", "1.0").optional(true)) .feature("default", &["serde-stuff"]) .feature("serde-stuff", &["serde/derive"]) .feature("vehicle", &["car"]) .feature("car", &[]) .publish(); Package::new("serde_derive", "1.0.0").publish(); Package::new("serde", "1.0.0") .feature("derive", &["serde_derive"]) .add_dep(Dependency::new("serde_derive", "1.0").optional(true)) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] defaultdep = "1.0" nodefaultdep = {version="1.0", default-features = false} nameddep = {version="1.0", features = ["vehicle", "serde"]} "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree -e features") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ nodefaultdep v1.0.0 β”œβ”€β”€ defaultdep feature "default" β”‚ β”œβ”€β”€ defaultdep v1.0.0 β”‚ β”‚ └── optdep feature "default" β”‚ β”‚ β”œβ”€β”€ optdep v1.0.0 β”‚ β”‚ └── optdep feature "cat" β”‚ β”‚ └── optdep v1.0.0 β”‚ └── defaultdep feature "f1" β”‚ β”œβ”€β”€ defaultdep v1.0.0 (*) β”‚ └── defaultdep feature "optdep" β”‚ └── defaultdep v1.0.0 (*) β”œβ”€β”€ nameddep feature "default" β”‚ β”œβ”€β”€ nameddep v1.0.0 β”‚ β”‚ └── serde feature "default" β”‚ β”‚ └── serde v1.0.0 β”‚ β”‚ └── serde_derive feature "default" β”‚ β”‚ └── serde_derive v1.0.0 β”‚ └── nameddep feature "serde-stuff" β”‚ β”œβ”€β”€ nameddep v1.0.0 (*) β”‚ β”œβ”€β”€ nameddep feature "serde" β”‚ β”‚ └── nameddep v1.0.0 (*) β”‚ └── serde feature "derive" β”‚ β”œβ”€β”€ serde v1.0.0 (*) β”‚ └── serde feature "serde_derive" β”‚ └── serde v1.0.0 (*) β”œβ”€β”€ nameddep feature "serde" (*) └── nameddep feature "vehicle" β”œβ”€β”€ nameddep v1.0.0 (*) └── nameddep feature "car" └── nameddep v1.0.0 (*) "#]]) .run(); } #[cargo_test] fn graph_features_ws_interdependent() { // A workspace with interdependent crates. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a", "b"] "#, ) .file( "a/Cargo.toml", r#" [package] name = "a" version = "0.1.0" [dependencies] b = {path="../b", features=["feat2"]} [features] default = ["a1"] a1 = [] a2 = [] "#, ) .file("a/src/lib.rs", "") .file( "b/Cargo.toml", r#" [package] name = "b" version = "0.1.0" [features] default = ["feat1"] feat1 = [] feat2 = [] "#, ) .file("b/src/lib.rs", "") .build(); p.cargo("tree -e features") .with_stdout_data(str![[r#" a v0.1.0 ([ROOT]/foo/a) β”œβ”€β”€ b feature "default" (command-line) β”‚ β”œβ”€β”€ b v0.1.0 ([ROOT]/foo/b) β”‚ └── b feature "feat1" β”‚ └── b v0.1.0 ([ROOT]/foo/b) └── b feature "feat2" └── b v0.1.0 ([ROOT]/foo/b) b v0.1.0 ([ROOT]/foo/b) "#]]) .run(); p.cargo("tree -e features -i a -i b") .with_stdout_data(str![[r#" a v0.1.0 ([ROOT]/foo/a) β”œβ”€β”€ a feature "a1" β”‚ └── a feature "default" (command-line) └── a feature "default" (command-line) b v0.1.0 ([ROOT]/foo/b) β”œβ”€β”€ b feature "default" (command-line) β”‚ └── a v0.1.0 ([ROOT]/foo/a) (*) β”œβ”€β”€ b feature "feat1" β”‚ └── b feature "default" (command-line) (*) └── b feature "feat2" └── a v0.1.0 ([ROOT]/foo/a) (*) "#]]) .run(); } #[cargo_test] fn slash_feature_name() { // dep_name/feat_name syntax Package::new("opt", "1.0.0").feature("feat1", &[]).publish(); Package::new("notopt", "1.0.0") .feature("cat", &[]) .feature("animal", &["cat"]) .publish(); Package::new("opt2", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] opt = {version = "1.0", optional=true} opt2 = {version = "1.0", optional=true} notopt = "1.0" [features] f1 = ["opt/feat1", "notopt/animal"] f2 = ["f1"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree -e features --features f1") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ notopt feature "default" β”‚ └── notopt v1.0.0 └── opt feature "default" └── opt v1.0.0 "#]]) .run(); p.cargo("tree -e features --features f1 -i foo") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ foo feature "default" (command-line) β”œβ”€β”€ foo feature "f1" (command-line) └── foo feature "opt" └── foo feature "f1" (command-line) "#]]) .run(); p.cargo("tree -e features --features f1 -i notopt") .with_stdout_data(str![[r#" notopt v1.0.0 β”œβ”€β”€ notopt feature "animal" β”‚ └── foo feature "f1" (command-line) β”œβ”€β”€ notopt feature "cat" β”‚ └── notopt feature "animal" (*) └── notopt feature "default" └── foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ foo feature "default" (command-line) β”œβ”€β”€ foo feature "f1" (command-line) └── foo feature "opt" └── foo feature "f1" (command-line) "#]]) .run(); p.cargo("tree -e features --features notopt/animal -i notopt") .with_stdout_data(str![[r#" notopt v1.0.0 β”œβ”€β”€ notopt feature "animal" (command-line) β”œβ”€β”€ notopt feature "cat" β”‚ └── notopt feature "animal" (command-line) └── notopt feature "default" └── foo v0.1.0 ([ROOT]/foo) └── foo feature "default" (command-line) "#]]) .run(); p.cargo("tree -e features --all-features") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ notopt feature "default" β”‚ └── notopt v1.0.0 β”œβ”€β”€ opt feature "default" β”‚ └── opt v1.0.0 └── opt2 feature "default" └── opt2 v1.0.0 "#]]) .run(); p.cargo("tree -e features --all-features -i opt2") .with_stdout_data(str![[r#" opt2 v1.0.0 └── opt2 feature "default" └── foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ foo feature "default" (command-line) β”œβ”€β”€ foo feature "f1" (command-line) β”‚ └── foo feature "f2" (command-line) β”œβ”€β”€ foo feature "f2" (command-line) β”œβ”€β”€ foo feature "opt" (command-line) β”‚ └── foo feature "f1" (command-line) (*) └── foo feature "opt2" (command-line) "#]]) .run(); } #[cargo_test] fn features_enables_inactive_target() { // Features that enable things on targets that are not enabled. Package::new("optdep", "1.0.0") .feature("feat1", &[]) .publish(); Package::new("dep1", "1.0.0") .feature("somefeat", &[]) .publish(); Package::new("dep2", "1.0.0") .add_dep( Dependency::new("optdep", "1.0.0") .optional(true) .target("cfg(whatever)"), ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [target.'cfg(whatever)'.dependencies] optdep = {version="1.0", optional=true} dep1 = "1.0" [dependencies] dep2 = "1.0" [features] f1 = ["optdep"] f2 = ["optdep/feat1"] f3 = ["dep1/somefeat"] f4 = ["dep2/optdep"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("tree -e features") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── dep2 feature "default" └── dep2 v1.0.0 "#]]) .run(); p.cargo("tree -e features --all-features") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── dep2 feature "default" └── dep2 v1.0.0 "#]]) .run(); p.cargo("tree -e features --all-features --target=all") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) β”œβ”€β”€ dep1 feature "default" β”‚ └── dep1 v1.0.0 β”œβ”€β”€ dep2 feature "default" β”‚ └── dep2 v1.0.0 β”‚ └── optdep feature "default" β”‚ └── optdep v1.0.0 └── optdep feature "default" (*) "#]]) .run(); } cargo-0.86.0/tests/testsuite/unit_graph.rs000064400000000000000000000130451046102023000167160ustar 00000000000000//! Tests for --unit-graph option. use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry::Package; use cargo_test_support::str; #[cargo_test] fn gated() { let p = project().file("src/lib.rs", "").build(); p.cargo("build --unit-graph") .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `--unit-graph` flag is unstable, and only available on the nightly channel of Cargo, but this is the `stable` channel See https://doc.rust-lang.org/book/[..].html for more information about Rust release channels. See https://github.com/rust-lang/cargo/issues/8002 for more information about the `--unit-graph` flag. "#]]) .run(); } #[cargo_test] fn simple() { Package::new("a", "1.0.0") .dep("b", "1.0") .feature("feata", &["b/featb"]) .publish(); Package::new("b", "1.0.0") .dep("c", "1.0") .feature("featb", &["c/featc"]) .publish(); Package::new("c", "1.0.0").feature("featc", &[]).publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] a = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("build --features a/feata --unit-graph -Zunstable-options") .masquerade_as_nightly_cargo(&["unit-graph"]) .with_stdout_data( str![[r#" { "roots": [ 3 ], "units": [ { "dependencies": [ { "extern_crate_name": "b", "index": 1, "noprelude": false, "public": false } ], "features": [ "feata" ], "mode": "build", "pkg_id": "a 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "platform": null, "profile": { "codegen_backend": null, "codegen_units": null, "debug_assertions": true, "debuginfo": 2, "incremental": false, "lto": "false", "name": "dev", "opt_level": "0", "overflow_checks": true, "panic": "unwind", "rpath": false, "split_debuginfo": "{...}", "strip": "{...}" }, "target": { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "a", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/a-1.0.0/src/lib.rs", "test": true } }, { "dependencies": [ { "extern_crate_name": "c", "index": 2, "noprelude": false, "public": false } ], "features": [ "featb" ], "mode": "build", "pkg_id": "b 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "platform": null, "profile": { "codegen_backend": null, "codegen_units": null, "debug_assertions": true, "debuginfo": 2, "incremental": false, "lto": "false", "name": "dev", "opt_level": "0", "overflow_checks": true, "panic": "unwind", "rpath": false, "split_debuginfo": "{...}", "strip": "{...}" }, "target": { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "b", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/b-1.0.0/src/lib.rs", "test": true } }, { "dependencies": [], "features": [ "featc" ], "mode": "build", "pkg_id": "c 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "platform": null, "profile": { "codegen_backend": null, "codegen_units": null, "debug_assertions": true, "debuginfo": 2, "incremental": false, "lto": "false", "name": "dev", "opt_level": "0", "overflow_checks": true, "panic": "unwind", "rpath": false, "split_debuginfo": "{...}", "strip": "{...}" }, "target": { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "c", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/c-1.0.0/src/lib.rs", "test": true } }, { "dependencies": [ { "extern_crate_name": "a", "index": 0, "noprelude": false, "public": false } ], "features": [], "mode": "build", "pkg_id": "foo 0.1.0 (path+[ROOTURL]/foo)", "platform": null, "profile": { "codegen_backend": null, "codegen_units": null, "debug_assertions": true, "debuginfo": 2, "incremental": false, "lto": "false", "name": "dev", "opt_level": "0", "overflow_checks": true, "panic": "unwind", "rpath": false, "split_debuginfo": "{...}", "strip": "{...}" }, "target": { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "foo", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } } ], "version": 1 } "#]] .is_json(), ) .run(); } cargo-0.86.0/tests/testsuite/update.rs000064400000000000000000002246311046102023000160450ustar 00000000000000//! Tests for the `cargo update` command. use cargo_test_support::compare::assert_e2e; use cargo_test_support::prelude::*; use cargo_test_support::registry::{self}; use cargo_test_support::registry::{Dependency, Package}; use cargo_test_support::{basic_lib_manifest, basic_manifest, git, project, str}; #[cargo_test] fn minor_update_two_places() { Package::new("log", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] log = "0.1" foo = { path = "foo" } "#, ) .file("src/lib.rs", "") .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] log = "0.1" "#, ) .file("foo/src/lib.rs", "") .build(); p.cargo("check").run(); Package::new("log", "0.1.1").publish(); p.change_file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] log = "0.1.1" "#, ); p.cargo("check").run(); } #[cargo_test] fn transitive_minor_update() { Package::new("log", "0.1.0").publish(); Package::new("serde", "0.1.0").dep("log", "0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] serde = "0.1" log = "0.1" foo = { path = "foo" } "#, ) .file("src/lib.rs", "") .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] serde = "0.1" "#, ) .file("foo/src/lib.rs", "") .build(); p.cargo("check").run(); Package::new("log", "0.1.1").publish(); Package::new("serde", "0.1.1").dep("log", "0.1.1").publish(); // Note that `serde` isn't actually updated here! The default behavior for // `update` right now is to as conservatively as possible attempt to satisfy // an update. In this case we previously locked the dependency graph to `log // 0.1.0`, but nothing on the command line says we're allowed to update // that. As a result the update of `serde` here shouldn't update to `serde // 0.1.1` as that would also force an update to `log 0.1.1`. // // Also note that this is probably counterintuitive and weird. We may wish // to change this one day. p.cargo("update serde") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 0 packages to latest compatible versions [NOTE] pass `--verbose` to see 2 unchanged dependencies behind latest "#]]) .run(); } #[cargo_test] fn conservative() { Package::new("log", "0.1.0").publish(); Package::new("serde", "0.1.0").dep("log", "0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] serde = "0.1" log = "0.1" foo = { path = "foo" } "#, ) .file("src/lib.rs", "") .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] serde = "0.1" "#, ) .file("foo/src/lib.rs", "") .build(); p.cargo("check").run(); Package::new("log", "0.1.1").publish(); Package::new("serde", "0.1.1").dep("log", "0.1").publish(); p.cargo("update serde") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] serde v0.1.0 -> v0.1.1 [NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest "#]]) .run(); } #[cargo_test] fn update_via_new_dep() { Package::new("log", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] log = "0.1" # foo = { path = "foo" } "#, ) .file("src/lib.rs", "") .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] log = "0.1.1" "#, ) .file("foo/src/lib.rs", "") .build(); p.cargo("check").run(); Package::new("log", "0.1.1").publish(); p.uncomment_root_manifest(); p.cargo("check").env("CARGO_LOG", "cargo=trace").run(); } #[cargo_test] fn update_via_new_member() { Package::new("log", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [workspace] # members = [ "foo" ] [dependencies] log = "0.1" "#, ) .file("src/lib.rs", "") .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] log = "0.1.1" "#, ) .file("foo/src/lib.rs", "") .build(); p.cargo("check").run(); Package::new("log", "0.1.1").publish(); p.uncomment_root_manifest(); p.cargo("check").run(); } #[cargo_test] fn add_dep_deep_new_requirement() { Package::new("log", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] log = "0.1" # bar = "0.1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); Package::new("log", "0.1.1").publish(); Package::new("bar", "0.1.0").dep("log", "0.1.1").publish(); p.uncomment_root_manifest(); p.cargo("check").run(); } #[cargo_test] fn everything_real_deep() { Package::new("log", "0.1.0").publish(); Package::new("foo", "0.1.0").dep("log", "0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] foo = "0.1" # bar = "0.1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); Package::new("log", "0.1.1").publish(); Package::new("bar", "0.1.0").dep("log", "0.1.1").publish(); p.uncomment_root_manifest(); p.cargo("check").run(); } #[cargo_test] fn change_package_version() { let p = project() .file( "Cargo.toml", r#" [package] name = "a-foo" version = "0.2.0-alpha" edition = "2015" authors = [] [dependencies] bar = { path = "bar", version = "0.2.0-alpha" } "#, ) .file("src/lib.rs", "") .file("bar/Cargo.toml", &basic_manifest("bar", "0.2.0-alpha")) .file("bar/src/lib.rs", "") .file( "Cargo.lock", r#" [[package]] name = "foo" version = "0.2.0" dependencies = ["bar 0.2.0"] [[package]] name = "bar" version = "0.2.0" "#, ) .build(); p.cargo("check").run(); } #[cargo_test] fn update_precise() { Package::new("serde", "0.1.0").publish(); Package::new("serde", "0.2.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] serde = "0.2" foo = { path = "foo" } "#, ) .file("src/lib.rs", "") .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] serde = "0.1" "#, ) .file("foo/src/lib.rs", "") .build(); p.cargo("check").run(); Package::new("serde", "0.2.0").publish(); p.cargo("update serde:0.2.1 --precise 0.2.0") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNGRADING] serde v0.2.1 -> v0.2.0 "#]]) .run(); } #[cargo_test] fn update_precise_mismatched() { Package::new("serde", "1.2.0").publish(); Package::new("serde", "1.2.1").publish(); Package::new("serde", "1.6.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] serde = "~1.2" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); // `1.6.0` does not match `"~1.2"` p.cargo("update serde:1.2 --precise 1.6.0") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] failed to select a version for the requirement `serde = "~1.2"` candidate versions found which didn't match: 1.6.0 location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `bar v0.0.1 ([ROOT]/foo)` perhaps a crate was updated and forgotten to be re-vendored? "#]]) .with_status(101) .run(); // `1.9.0` does not exist p.cargo("update serde:1.2 --precise 1.9.0") // This terrible error message has been the same for a long time. A fix is more than welcome! .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] no matching package named `serde` found location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `bar v0.0.1 ([ROOT]/foo)` "#]]) .with_status(101) .run(); } #[cargo_test] fn update_precise_build_metadata() { Package::new("serde", "0.0.1+first").publish(); Package::new("serde", "0.0.1+second").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.0" edition = "2015" [dependencies] serde = "0.0.1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); p.cargo("update serde --precise 0.0.1+first").run(); p.cargo("update serde --precise 0.0.1+second") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] serde v0.0.1+first -> v0.0.1+second "#]]) .run(); // This is not considered "Downgrading". Build metadata are not assumed to // be ordered. p.cargo("update serde --precise 0.0.1+first") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] serde v0.0.1+second -> v0.0.1+first "#]]) .run(); } #[cargo_test] fn update_precise_do_not_force_update_deps() { Package::new("log", "0.1.0").publish(); Package::new("serde", "0.2.1").dep("log", "0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] serde = "0.2" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); Package::new("log", "0.1.1").publish(); Package::new("serde", "0.2.2").dep("log", "0.1").publish(); p.cargo("update serde:0.2.1 --precise 0.2.2") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] serde v0.2.1 -> v0.2.2 [NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest "#]]) .run(); } #[cargo_test] fn update_recursive() { Package::new("log", "0.1.0").publish(); Package::new("serde", "0.2.1").dep("log", "0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] serde = "0.2" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); Package::new("log", "0.1.1").publish(); Package::new("serde", "0.2.2").dep("log", "0.1").publish(); p.cargo("update serde:0.2.1 --recursive") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [UPDATING] log v0.1.0 -> v0.1.1 [UPDATING] serde v0.2.1 -> v0.2.2 "#]]) .run(); } #[cargo_test] fn update_aggressive_alias_for_recursive() { Package::new("log", "0.1.0").publish(); Package::new("serde", "0.2.1").dep("log", "0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] serde = "0.2" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); Package::new("log", "0.1.1").publish(); Package::new("serde", "0.2.2").dep("log", "0.1").publish(); p.cargo("update serde:0.2.1 --aggressive") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions [UPDATING] log v0.1.0 -> v0.1.1 [UPDATING] serde v0.2.1 -> v0.2.2 "#]]) .run(); } #[cargo_test] fn update_recursive_conflicts_with_precise() { Package::new("log", "0.1.0").publish(); Package::new("serde", "0.2.1").dep("log", "0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] serde = "0.2" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check").run(); Package::new("log", "0.1.1").publish(); Package::new("serde", "0.2.2").dep("log", "0.1").publish(); p.cargo("update serde:0.2.1 --precise 0.2.2 --recursive") .with_status(1) .with_stderr_data(str![[r#" [ERROR] the argument '--precise ' cannot be used with '--recursive' Usage: cargo[EXE] update --precise ]> For more information, try '--help'. "#]]) .run(); } // cargo update should respect its arguments even without a lockfile. // See issue "Running cargo update without a Cargo.lock ignores arguments" // at . #[cargo_test] fn update_precise_first_run() { Package::new("serde", "0.1.0").publish(); Package::new("serde", "0.2.0").publish(); Package::new("serde", "0.2.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" [dependencies] serde = "0.2" "#, ) .file("src/lib.rs", "") .build(); p.cargo("update serde --precise 0.2.0") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [DOWNGRADING] serde v0.2.1 -> v0.2.0 "#]]) .run(); // Assert `cargo metadata` shows serde 0.2.0 p.cargo("metadata") .with_stdout_data( str![[r#" { "metadata": null, "packages": [ { "authors": [], "categories": [], "default_run": null, "dependencies": [ { "features": [], "kind": null, "name": "serde", "optional": false, "registry": null, "rename": null, "req": "^0.2", "source": "registry+https://github.com/rust-lang/crates.io-index", "target": null, "uses_default_features": true } ], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "path+[ROOTURL]/foo#bar@0.0.1", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/foo/Cargo.toml", "metadata": null, "name": "bar", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": null, "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "bar", "src_path": "[ROOT]/foo/src/lib.rs", "test": true } ], "version": "0.0.1" }, { "authors": [], "categories": [], "default_run": null, "dependencies": [], "description": null, "documentation": null, "edition": "2015", "features": {}, "homepage": null, "id": "registry+https://github.com/rust-lang/crates.io-index#serde@0.2.0", "keywords": [], "license": null, "license_file": null, "links": null, "manifest_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/serde-0.2.0/Cargo.toml", "metadata": null, "name": "serde", "publish": null, "readme": null, "repository": null, "rust_version": null, "source": "registry+https://github.com/rust-lang/crates.io-index", "targets": [ { "crate_types": [ "lib" ], "doc": true, "doctest": true, "edition": "2015", "kind": [ "lib" ], "name": "serde", "src_path": "[ROOT]/home/.cargo/registry/src/-[HASH]/serde-0.2.0/src/lib.rs", "test": true } ], "version": "0.2.0" } ], "resolve": { "nodes": [ { "dependencies": [ "registry+https://github.com/rust-lang/crates.io-index#serde@0.2.0" ], "deps": [ { "dep_kinds": [ { "kind": null, "target": null } ], "name": "serde", "pkg": "registry+https://github.com/rust-lang/crates.io-index#serde@0.2.0" } ], "features": [], "id": "path+[ROOTURL]/foo#bar@0.0.1" }, { "dependencies": [], "deps": [], "features": [], "id": "registry+https://github.com/rust-lang/crates.io-index#serde@0.2.0" } ], "root": "path+[ROOTURL]/foo#bar@0.0.1" }, "target_directory": "[ROOT]/foo/target", "version": 1, "workspace_default_members": [ "path+[ROOTURL]/foo#bar@0.0.1" ], "workspace_members": [ "path+[ROOTURL]/foo#bar@0.0.1" ], "workspace_root": "[ROOT]/foo" } "#]] .is_json(), ) .run(); p.cargo("update serde --precise 0.2.0") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index "#]]) .run(); } #[cargo_test] fn preserve_top_comment() { let p = project().file("src/lib.rs", "").build(); p.cargo("update").run(); let lockfile = p.read_lockfile(); assert!(lockfile.starts_with("# This file is automatically @generated by Cargo.\n# It is not intended for manual editing.\n")); let mut lines = lockfile.lines().collect::>(); lines.insert(2, "# some other comment"); let mut lockfile = lines.join("\n"); lockfile.push('\n'); // .lines/.join loses the last newline println!("saving Cargo.lock contents:\n{}", lockfile); p.change_file("Cargo.lock", &lockfile); p.cargo("update").run(); let lockfile2 = p.read_lockfile(); println!("loaded Cargo.lock contents:\n{}", lockfile2); assert_eq!(lockfile, lockfile2); } #[cargo_test] fn dry_run_update() { Package::new("log", "0.1.0").publish(); Package::new("serde", "0.1.0").dep("log", "0.1").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] serde = "0.1" log = "0.1" foo = { path = "foo" } "#, ) .file("src/lib.rs", "") .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] serde = "0.1" "#, ) .file("foo/src/lib.rs", "") .build(); p.cargo("check").run(); let old_lockfile = p.read_lockfile(); Package::new("log", "0.1.1").publish(); Package::new("serde", "0.1.1").dep("log", "0.1").publish(); p.cargo("update serde --dry-run") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] serde v0.1.0 -> v0.1.1 [NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest [WARNING] not updating lockfile due to dry run "#]]) .run(); let new_lockfile = p.read_lockfile(); assert_eq!(old_lockfile, new_lockfile) } #[cargo_test] fn workspace_only() { let p = project().file("src/main.rs", "fn main() {}").build(); p.cargo("generate-lockfile").run(); let lock1 = p.read_lockfile(); p.change_file( "Cargo.toml", r#" [package] name = "foo" authors = [] version = "0.0.2" edition = "2015" "#, ); p.cargo("update --workspace").run(); let lock2 = p.read_lockfile(); assert_ne!(lock1, lock2); assert!(lock1.contains("0.0.1")); assert!(lock2.contains("0.0.2")); assert!(!lock1.contains("0.0.2")); assert!(!lock2.contains("0.0.1")); } #[cargo_test] fn precise_with_build_metadata() { // +foo syntax shouldn't be necessary with --precise Package::new("bar", "0.1.0+extra-stuff.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = "0.1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); Package::new("bar", "0.1.1+extra-stuff.1").publish(); Package::new("bar", "0.1.2+extra-stuff.2").publish(); p.cargo("update bar --precise 0.1") .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid version format for precise version `0.1` Caused by: unexpected end of input while parsing minor version number "#]]) .run(); p.cargo("update bar --precise 0.1.1+does-not-match") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] no matching package named `bar` found location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.1.0 ([ROOT]/foo)` "#]]) .run(); p.cargo("update bar --precise 0.1.1") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] bar v0.1.0+extra-stuff.0 -> v0.1.1+extra-stuff.1 "#]]) .run(); Package::new("bar", "0.1.3").publish(); p.cargo("update bar --precise 0.1.3+foo") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [ERROR] no matching package named `bar` found location searched: `dummy-registry` index (which is replacing registry `crates-io`) required by package `foo v0.1.0 ([ROOT]/foo)` "#]]) .run(); p.cargo("update bar --precise 0.1.3") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPDATING] bar v0.1.1+extra-stuff.1 -> v0.1.3 "#]]) .run(); } #[cargo_test] fn update_only_members_order_one() { let git_project = git::new("rustdns", |project| { project .file("Cargo.toml", &basic_lib_manifest("rustdns")) .file("src/lib.rs", "pub fn bar() {}") }); let workspace_toml = format!( r#" [workspace.package] version = "2.29.8" edition = "2021" publish = false [workspace] members = [ "rootcrate", "subcrate", ] resolver = "2" [workspace.dependencies] # Internal crates subcrate = {{ version = "*", path = "./subcrate" }} # External dependencies rustdns = {{ version = "0.5.0", default-features = false, git = "{}" }} "#, git_project.url() ); let p = project() .file("Cargo.toml", &workspace_toml) .file( "rootcrate/Cargo.toml", r#" [package] name = "rootcrate" version.workspace = true edition.workspace = true publish.workspace = true [dependencies] subcrate.workspace = true "#, ) .file("rootcrate/src/main.rs", "fn main() {}") .file( "subcrate/Cargo.toml", r#" [package] name = "subcrate" version.workspace = true edition.workspace = true publish.workspace = true [dependencies] rustdns.workspace = true "#, ) .file("subcrate/src/lib.rs", "pub foo() {}") .build(); // First time around we should compile both foo and bar p.cargo("generate-lockfile") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/rustdns` [LOCKING] 1 package to latest compatible version "#]]) .run(); // Modify a file manually, shouldn't trigger a recompile git_project.change_file("src/lib.rs", r#"pub fn bar() { println!("hello!"); }"#); // Commit the changes and make sure we don't trigger a recompile because the // lock file says not to change let repo = git2::Repository::open(&git_project.root()).unwrap(); git::add(&repo); git::commit(&repo); p.change_file("Cargo.toml", &workspace_toml.replace("2.29.8", "2.29.81")); p.cargo("update -p rootcrate") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [UPDATING] rootcrate v2.29.8 ([ROOT]/foo/rootcrate) -> v2.29.81 [UPDATING] subcrate v2.29.8 ([ROOT]/foo/subcrate) -> v2.29.81 "#]]) .run(); } #[cargo_test] fn update_only_members_order_two() { let git_project = git::new("rustdns", |project| { project .file("Cargo.toml", &basic_lib_manifest("rustdns")) .file("src/lib.rs", "pub fn bar() {}") }); let workspace_toml = format!( r#" [workspace.package] version = "2.29.8" edition = "2021" publish = false [workspace] members = [ "crate2", "crate1", ] resolver = "2" [workspace.dependencies] # Internal crates crate1 = {{ version = "*", path = "./crate1" }} # External dependencies rustdns = {{ version = "0.5.0", default-features = false, git = "{}" }} "#, git_project.url() ); let p = project() .file("Cargo.toml", &workspace_toml) .file( "crate2/Cargo.toml", r#" [package] name = "crate2" version.workspace = true edition.workspace = true publish.workspace = true [dependencies] crate1.workspace = true "#, ) .file("crate2/src/main.rs", "fn main() {}") .file( "crate1/Cargo.toml", r#" [package] name = "crate1" version.workspace = true edition.workspace = true publish.workspace = true [dependencies] rustdns.workspace = true "#, ) .file("crate1/src/lib.rs", "pub foo() {}") .build(); // First time around we should compile both foo and bar p.cargo("generate-lockfile") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/rustdns` [LOCKING] 1 package to latest compatible version "#]]) .run(); // Modify a file manually, shouldn't trigger a recompile git_project.change_file("src/lib.rs", r#"pub fn bar() { println!("hello!"); }"#); // Commit the changes and make sure we don't trigger a recompile because the // lock file says not to change let repo = git2::Repository::open(&git_project.root()).unwrap(); git::add(&repo); git::commit(&repo); p.change_file("Cargo.toml", &workspace_toml.replace("2.29.8", "2.29.81")); p.cargo("update -p crate2") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [UPDATING] crate1 v2.29.8 ([ROOT]/foo/crate1) -> v2.29.81 [UPDATING] crate2 v2.29.8 ([ROOT]/foo/crate2) -> v2.29.81 "#]]) .run(); } #[cargo_test] fn update_only_members_with_workspace() { let git_project = git::new("rustdns", |project| { project .file("Cargo.toml", &basic_lib_manifest("rustdns")) .file("src/lib.rs", "pub fn bar() {}") }); let workspace_toml = format!( r#" [workspace.package] version = "2.29.8" edition = "2021" publish = false [workspace] members = [ "crate2", "crate1", ] resolver = "2" [workspace.dependencies] # Internal crates crate1 = {{ version = "*", path = "./crate1" }} # External dependencies rustdns = {{ version = "0.5.0", default-features = false, git = "{}" }} "#, git_project.url() ); let p = project() .file("Cargo.toml", &workspace_toml) .file( "crate2/Cargo.toml", r#" [package] name = "crate2" version.workspace = true edition.workspace = true publish.workspace = true [dependencies] crate1.workspace = true "#, ) .file("crate2/src/main.rs", "fn main() {}") .file( "crate1/Cargo.toml", r#" [package] name = "crate1" version.workspace = true edition.workspace = true publish.workspace = true [dependencies] rustdns.workspace = true "#, ) .file("crate1/src/lib.rs", "pub foo() {}") .build(); // First time around we should compile both foo and bar p.cargo("generate-lockfile") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/rustdns` [LOCKING] 1 package to latest compatible version "#]]) .run(); // Modify a file manually, shouldn't trigger a recompile git_project.change_file("src/lib.rs", r#"pub fn bar() { println!("hello!"); }"#); // Commit the changes and make sure we don't trigger a recompile because the // lock file says not to change let repo = git2::Repository::open(&git_project.root()).unwrap(); git::add(&repo); git::commit(&repo); p.change_file("Cargo.toml", &workspace_toml.replace("2.29.8", "2.29.81")); p.cargo("update --workspace") .with_stderr_data(str![[r#" [LOCKING] 2 packages to latest compatible versions [UPDATING] crate1 v2.29.8 ([ROOT]/foo/crate1) -> v2.29.81 [UPDATING] crate2 v2.29.8 ([ROOT]/foo/crate2) -> v2.29.81 "#]]) .run(); } #[cargo_test] fn update_precise_git_revisions() { let (git_project, git_repo) = git::new_repo("git", |p| { p.file("Cargo.toml", &basic_lib_manifest("git")) .file("src/lib.rs", "") }); let tag_name = "NazgΓ»l"; git::tag(&git_repo, tag_name); let tag_commit_id = git_repo.head().unwrap().target().unwrap().to_string(); git_project.change_file("src/lib.rs", "fn f() {}"); git::add(&git_repo); let head_id = git::commit(&git_repo).to_string(); let short_id = &head_id[..8]; let url = git_project.url(); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] git = {{ git = '{url}' }} "# ), ) .file("src/lib.rs", "") .build(); p.cargo("fetch") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/git` [LOCKING] 1 package to latest compatible version "#]]) .run(); assert!(p.read_lockfile().contains(&head_id)); p.cargo("update git --precise") .arg(tag_name) .with_stderr_data(format!( "\ [UPDATING] git repository `[ROOTURL]/git` [UPDATING] git v0.5.0 ([ROOTURL]/git#[..]) -> #{} ", &tag_commit_id[..8], )) .run(); assert!(p.read_lockfile().contains(&tag_commit_id)); assert!(!p.read_lockfile().contains(&head_id)); p.cargo("update git --precise") .arg(short_id) .with_stderr_data(format!( "\ [UPDATING] git repository `[ROOTURL]/git` [UPDATING] git v0.5.0 ([ROOTURL]/git[..]) -> #{short_id} ", )) .run(); assert!(p.read_lockfile().contains(&head_id)); assert!(!p.read_lockfile().contains(&tag_commit_id)); // updating back to tag still requires a git fetch, // as the ref may change over time. p.cargo("update git --precise") .arg(tag_name) .with_stderr_data(format!( "\ [UPDATING] git repository `[ROOTURL]/git` [UPDATING] git v0.5.0 ([ROOTURL]/git#[..]) -> #{} ", &tag_commit_id[..8], )) .run(); assert!(p.read_lockfile().contains(&tag_commit_id)); assert!(!p.read_lockfile().contains(&head_id)); // Now make a tag looks like an oid. // It requires a git fetch, as the oid cannot be found in preexisting git db. let arbitrary_tag: String = std::iter::repeat('a').take(head_id.len()).collect(); git::tag(&git_repo, &arbitrary_tag); p.cargo("update git --precise") .arg(&arbitrary_tag) .with_stderr_data(format!( "\ [UPDATING] git repository `[ROOTURL]/git` [UPDATING] git v0.5.0 ([ROOTURL]/git#[..]) -> #{} ", &head_id[..8], )) .run(); assert!(p.read_lockfile().contains(&head_id)); assert!(!p.read_lockfile().contains(&tag_commit_id)); } #[cargo_test] fn precise_yanked() { Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.1.1").yanked(true).publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" [dependencies] bar = "0.1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); // Use non-yanked version. let lockfile = p.read_lockfile(); assert!(lockfile.contains("\nname = \"bar\"\nversion = \"0.1.0\"")); p.cargo("update --precise 0.1.1 bar") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [WARNING] selected package `bar@0.1.1` was yanked by the author [NOTE] if possible, try a compatible non-yanked version [UPDATING] bar v0.1.0 -> v0.1.1 "#]]) .run(); // Use yanked version. let lockfile = p.read_lockfile(); assert!(lockfile.contains("\nname = \"bar\"\nversion = \"0.1.1\"")); } #[cargo_test] fn precise_yanked_multiple_presence() { Package::new("bar", "0.1.0").publish(); Package::new("bar", "0.1.1").yanked(true).publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" [dependencies] bar = "0.1" baz = { package = "bar", version = "0.1" } "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); // Use non-yanked version. let lockfile = p.read_lockfile(); assert!(lockfile.contains("\nname = \"bar\"\nversion = \"0.1.0\"")); p.cargo("update --precise 0.1.1 bar") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [WARNING] selected package `bar@0.1.1` was yanked by the author [NOTE] if possible, try a compatible non-yanked version [UPDATING] bar v0.1.0 -> v0.1.1 "#]]) .run(); // Use yanked version. let lockfile = p.read_lockfile(); assert!(lockfile.contains("\nname = \"bar\"\nversion = \"0.1.1\"")); } #[cargo_test] fn report_behind() { Package::new("two-ver", "0.1.0").publish(); Package::new("two-ver", "0.2.0").publish(); Package::new("pre", "1.0.0-alpha.0").publish(); Package::new("pre", "1.0.0-alpha.1").publish(); Package::new("breaking", "0.1.0").publish(); Package::new("breaking", "0.2.0").publish(); Package::new("breaking", "0.2.1-alpha.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" [dependencies] breaking = "0.1" pre = "=1.0.0-alpha.0" two-ver = "0.2.0" two-ver-one = { version = "0.1.0", package = "two-ver" } "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); Package::new("breaking", "0.1.1").publish(); p.cargo("update --dry-run") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] breaking v0.1.0 -> v0.1.1 (available: v0.2.0) [NOTE] pass `--verbose` to see 2 unchanged dependencies behind latest [WARNING] not updating lockfile due to dry run "#]]) .run(); p.cargo("update --dry-run --verbose") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] breaking v0.1.0 -> v0.1.1 (available: v0.2.0) [UNCHANGED] pre v1.0.0-alpha.0 (available: v1.0.0-alpha.1) [UNCHANGED] two-ver v0.1.0 (available: v0.2.0) [NOTE] to see how you depend on a package, run `cargo tree --invert --package @` [WARNING] not updating lockfile due to dry run "#]]) .run(); p.cargo("update").run(); p.cargo("update --dry-run") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 0 packages to latest compatible versions [NOTE] pass `--verbose` to see 3 unchanged dependencies behind latest [WARNING] not updating lockfile due to dry run "#]]) .run(); p.cargo("update --dry-run --verbose") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 0 packages to latest compatible versions [UNCHANGED] breaking v0.1.1 (available: v0.2.0) [UNCHANGED] pre v1.0.0-alpha.0 (available: v1.0.0-alpha.1) [UNCHANGED] two-ver v0.1.0 (available: v0.2.0) [NOTE] to see how you depend on a package, run `cargo tree --invert --package @` [WARNING] not updating lockfile due to dry run "#]]) .run(); } #[cargo_test] fn update_with_missing_feature() { // Attempting to update a package to a version with a missing feature // should produce a warning. Package::new("bar", "0.1.0").feature("feat1", &[]).publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = {version="0.1", features=["feat1"]} "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); // Publish an update that is missing the feature. Package::new("bar", "0.1.1").publish(); p.cargo("update") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 0 packages to latest compatible versions [NOTE] pass `--verbose` to see 1 unchanged dependencies behind latest "#]]) .run(); // Publish a fixed version, should not warn. Package::new("bar", "0.1.2").feature("feat1", &[]).publish(); p.cargo("update") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [UPDATING] bar v0.1.0 -> v0.1.2 "#]]) .run(); } #[cargo_test] fn update_breaking_unstable() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] "#, ) .file("src/lib.rs", "") .build(); p.cargo("update --breaking") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] the `--breaking` flag is unstable, pass `-Z unstable-options` to enable it See https://github.com/rust-lang/cargo/issues/12425 for more information about the `--breaking` flag. "#]]) .run(); } #[cargo_test] fn update_breaking_dry_run() { Package::new("incompatible", "1.0.0").publish(); Package::new("ws", "1.0.0").publish(); let root_manifest = r#" # Check if formatting is preserved. Nothing here should change, due to dry-run. [workspace] members = ["foo"] [workspace.dependencies] ws = "1.0" # Preserve formatting "#; let crate_manifest = r#" # Check if formatting is preserved. Nothing here should change, due to dry-run. [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] incompatible = "1.0" # Preserve formatting ws.workspace = true # Preserve formatting "#; let p = project() .file("Cargo.toml", root_manifest) .file("foo/Cargo.toml", crate_manifest) .file("foo/src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); let lock_file = p.read_file("Cargo.lock"); Package::new("incompatible", "1.0.1").publish(); Package::new("ws", "1.0.1").publish(); Package::new("incompatible", "2.0.0").publish(); Package::new("ws", "2.0.0").publish(); p.cargo("update -Zunstable-options --dry-run --breaking") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPGRADING] incompatible ^1.0 -> ^2.0 [UPGRADING] ws ^1.0 -> ^2.0 [LOCKING] 2 packages to latest compatible versions [UPDATING] incompatible v1.0.0 -> v2.0.0 [UPDATING] ws v1.0.0 -> v2.0.0 [WARNING] aborting update due to dry run "#]]) .run(); let root_manifest_after = p.read_file("Cargo.toml"); assert_e2e().eq(&root_manifest_after, root_manifest); let crate_manifest_after = p.read_file("foo/Cargo.toml"); assert_e2e().eq(&crate_manifest_after, crate_manifest); let lock_file_after = p.read_file("Cargo.lock"); assert_e2e().eq(&lock_file_after, lock_file); } #[cargo_test] fn update_breaking() { registry::alt_init(); Package::new("compatible", "1.0.0").publish(); Package::new("incompatible", "1.0.0").publish(); Package::new("pinned", "1.0.0").publish(); Package::new("less-than", "1.0.0").publish(); Package::new("renamed-from", "1.0.0").publish(); Package::new("pre-release", "1.0.0").publish(); Package::new("yanked", "1.0.0").publish(); Package::new("ws", "1.0.0").publish(); Package::new("shared", "1.0.0").publish(); Package::new("multiple-locations", "1.0.0").publish(); Package::new("multiple-versions", "1.0.0").publish(); Package::new("multiple-versions", "2.0.0").publish(); Package::new("alternative-1", "1.0.0") .alternative(true) .publish(); Package::new("alternative-2", "1.0.0") .alternative(true) .publish(); Package::new("bar", "1.0.0").alternative(true).publish(); Package::new("multiple-registries", "1.0.0").publish(); Package::new("multiple-registries", "2.0.0") .alternative(true) .publish(); Package::new("multiple-source-types", "1.0.0").publish(); Package::new("platform-specific", "1.0.0").publish(); Package::new("dev", "1.0.0").publish(); Package::new("build", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" # Check if formatting is preserved [workspace] members = ["foo", "bar"] [workspace.dependencies] ws = "1.0" # This line gets partially rewritten "#, ) .file( "foo/Cargo.toml", r#" # Check if formatting is preserved [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] compatible = "1.0" # Comment incompatible = "1.0" # Comment pinned = "=1.0" # Comment less-than = "<99.0" # Comment renamed-to = { package = "renamed-from", version = "1.0" } # Comment pre-release = "1.0" # Comment yanked = "1.0" # Comment ws.workspace = true # Comment shared = "1.0" # Comment multiple-locations = { path = "../multiple-locations", version = "1.0" } # Comment multiple-versions = "1.0" # Comment alternative-1 = { registry = "alternative", version = "1.0" } # Comment multiple-registries = "1.0" # Comment bar = { path = "../bar", registry = "alternative", version = "1.0.0" } # Comment multiple-source-types = { path = "../multiple-source-types", version = "1.0.0" } # Comment [dependencies.alternative-2] # Comment version = "1.0" # Comment registry = "alternative" # Comment [target.'cfg(unix)'.dependencies] platform-specific = "1.0" # Comment [dev-dependencies] dev = "1.0" # Comment [build-dependencies] build = "1.0" # Comment "#, ) .file("foo/src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "1.0.0" edition = "2015" authors = [] [dependencies] shared = "1.0" multiple-versions = "2.0" multiple-registries = { registry = "alternative", version = "2.0" } # Comment multiple-source-types = "1.0" # Comment "#, ) .file("bar/src/lib.rs", "") .file( "multiple-locations/Cargo.toml", r#" [package] name = "multiple-locations" version = "1.0.0" edition = "2015" authors = [] "#, ) .file("multiple-locations/src/lib.rs", "") .file( "multiple-source-types/Cargo.toml", r#" [package] name = "multiple-source-types" version = "1.0.0" edition = "2015" authors = [] "#, ) .file("multiple-source-types/src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); Package::new("compatible", "1.0.1").publish(); Package::new("incompatible", "1.0.1").publish(); Package::new("pinned", "1.0.1").publish(); Package::new("less-than", "1.0.1").publish(); Package::new("renamed-from", "1.0.1").publish(); Package::new("ws", "1.0.1").publish(); Package::new("multiple-locations", "1.0.1").publish(); Package::new("multiple-versions", "1.0.1").publish(); Package::new("multiple-versions", "2.0.1").publish(); Package::new("alternative-1", "1.0.1") .alternative(true) .publish(); Package::new("alternative-2", "1.0.1") .alternative(true) .publish(); Package::new("platform-specific", "1.0.1").publish(); Package::new("dev", "1.0.1").publish(); Package::new("build", "1.0.1").publish(); Package::new("incompatible", "2.0.0").publish(); Package::new("pinned", "2.0.0").publish(); Package::new("less-than", "2.0.0").publish(); Package::new("renamed-from", "2.0.0").publish(); Package::new("pre-release", "2.0.0-alpha").publish(); Package::new("yanked", "2.0.0").yanked(true).publish(); Package::new("ws", "2.0.0").publish(); Package::new("shared", "2.0.0").publish(); Package::new("multiple-locations", "2.0.0").publish(); Package::new("multiple-versions", "3.0.0").publish(); Package::new("alternative-1", "2.0.0") .alternative(true) .publish(); Package::new("alternative-2", "2.0.0") .alternative(true) .publish(); Package::new("bar", "2.0.0").alternative(true).publish(); Package::new("multiple-registries", "2.0.0").publish(); Package::new("multiple-registries", "3.0.0") .alternative(true) .publish(); Package::new("multiple-source-types", "2.0.0").publish(); Package::new("platform-specific", "2.0.0").publish(); Package::new("dev", "2.0.0").publish(); Package::new("build", "2.0.0").publish(); p.cargo("update -Zunstable-options --breaking") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `alternative` index [UPGRADING] multiple-registries ^2.0 -> ^3.0 [UPDATING] `dummy-registry` index [UPGRADING] multiple-source-types ^1.0 -> ^2.0 [UPGRADING] multiple-versions ^2.0 -> ^3.0 [UPGRADING] shared ^1.0 -> ^2.0 [UPGRADING] alternative-1 ^1.0 -> ^2.0 [UPGRADING] alternative-2 ^1.0 -> ^2.0 [UPGRADING] incompatible ^1.0 -> ^2.0 [UPGRADING] multiple-registries ^1.0 -> ^2.0 [UPGRADING] multiple-versions ^1.0 -> ^3.0 [UPGRADING] ws ^1.0 -> ^2.0 [UPGRADING] dev ^1.0 -> ^2.0 [UPGRADING] build ^1.0 -> ^2.0 [UPGRADING] platform-specific ^1.0 -> ^2.0 [LOCKING] 12 packages to latest compatible versions [UPDATING] alternative-1 v1.0.0 (registry `alternative`) -> v2.0.0 [UPDATING] alternative-2 v1.0.0 (registry `alternative`) -> v2.0.0 [UPDATING] build v1.0.0 -> v2.0.0 [UPDATING] dev v1.0.0 -> v2.0.0 [UPDATING] incompatible v1.0.0 -> v2.0.0 [UPDATING] multiple-registries v2.0.0 (registry `alternative`) -> v3.0.0 [UPDATING] multiple-registries v1.0.0 -> v2.0.0 [UPDATING] multiple-source-types v1.0.0 -> v2.0.0 [ADDING] multiple-versions v3.0.0 [UPDATING] platform-specific v1.0.0 -> v2.0.0 [UPDATING] shared v1.0.0 -> v2.0.0 [UPDATING] ws v1.0.0 -> v2.0.0 "#]]) .run(); let root_manifest = p.read_file("Cargo.toml"); assert_e2e().eq( &root_manifest, str![[r#" # Check if formatting is preserved [workspace] members = ["foo", "bar"] [workspace.dependencies] ws = "2.0" # This line gets partially rewritten "#]], ); let foo_manifest = p.read_file("foo/Cargo.toml"); assert_e2e().eq( &foo_manifest, str![[r#" # Check if formatting is preserved [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] compatible = "1.0" # Comment incompatible = "2.0" # Comment pinned = "=1.0" # Comment less-than = "<99.0" # Comment renamed-to = { package = "renamed-from", version = "1.0" } # Comment pre-release = "1.0" # Comment yanked = "1.0" # Comment ws.workspace = true # Comment shared = "2.0" # Comment multiple-locations = { path = "../multiple-locations", version = "1.0" } # Comment multiple-versions = "3.0" # Comment alternative-1 = { registry = "alternative", version = "2.0" } # Comment multiple-registries = "2.0" # Comment bar = { path = "../bar", registry = "alternative", version = "1.0.0" } # Comment multiple-source-types = { path = "../multiple-source-types", version = "1.0.0" } # Comment [dependencies.alternative-2] # Comment version = "2.0" # Comment registry = "alternative" # Comment [target.'cfg(unix)'.dependencies] platform-specific = "2.0" # Comment [dev-dependencies] dev = "2.0" # Comment [build-dependencies] build = "2.0" # Comment "#]], ); let bar_manifest = p.read_file("bar/Cargo.toml"); assert_e2e().eq( &bar_manifest, str![[r#" [package] name = "bar" version = "1.0.0" edition = "2015" authors = [] [dependencies] shared = "2.0" multiple-versions = "3.0" multiple-registries = { registry = "alternative", version = "3.0" } # Comment multiple-source-types = "2.0" # Comment "#]], ); p.cargo("update") .with_stderr_data(str![[r#" [UPDATING] `alternative` index [UPDATING] `dummy-registry` index [LOCKING] 4 packages to latest compatible versions [UPDATING] compatible v1.0.0 -> v1.0.1 [UPDATING] less-than v1.0.0 -> v2.0.0 [UPDATING] pinned v1.0.0 -> v1.0.1 (available: v2.0.0) [UPDATING] renamed-from v1.0.0 -> v1.0.1 (available: v2.0.0) "#]]) .run(); } #[cargo_test] fn update_breaking_specific_packages() { Package::new("just-foo", "1.0.0") .add_dep(Dependency::new("transitive-compatible", "1.0.0").build()) .add_dep(Dependency::new("transitive-incompatible", "1.0.0").build()) .publish(); Package::new("just-bar", "1.0.0").publish(); Package::new("shared", "1.0.0").publish(); Package::new("ws", "1.0.0").publish(); Package::new("transitive-compatible", "1.0.0").publish(); Package::new("transitive-incompatible", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo", "bar"] [workspace.dependencies] ws = "1.0" "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] just-foo = "1.0" shared = "1.0" ws.workspace = true "#, ) .file("foo/src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] just-bar = "1.0" shared = "1.0" ws.workspace = true "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); Package::new("just-foo", "1.0.1") .add_dep(Dependency::new("transitive-compatible", "1.0.0").build()) .add_dep(Dependency::new("transitive-incompatible", "1.0.0").build()) .publish(); Package::new("just-bar", "1.0.1").publish(); Package::new("shared", "1.0.1").publish(); Package::new("ws", "1.0.1").publish(); Package::new("transitive-compatible", "1.0.1").publish(); Package::new("transitive-incompatible", "1.0.1").publish(); Package::new("just-foo", "2.0.0") // Upgrading just-foo implies accepting an update of transitive-compatible. .add_dep(Dependency::new("transitive-compatible", "1.0.1").build()) // Upgrading just-foo implies accepting a major update of transitive-incompatible. .add_dep(Dependency::new("transitive-incompatible", "2.0.0").build()) .publish(); Package::new("just-bar", "2.0.0").publish(); Package::new("shared", "2.0.0").publish(); Package::new("ws", "2.0.0").publish(); Package::new("transitive-incompatible", "2.0.0").publish(); p.cargo("update -Zunstable-options --breaking just-foo shared ws") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPGRADING] shared ^1.0 -> ^2.0 [UPGRADING] ws ^1.0 -> ^2.0 [UPGRADING] just-foo ^1.0 -> ^2.0 [LOCKING] 5 packages to latest compatible versions [UPDATING] just-foo v1.0.0 -> v2.0.0 [UPDATING] shared v1.0.0 -> v2.0.0 [UPDATING] transitive-compatible v1.0.0 -> v1.0.1 [UPDATING] transitive-incompatible v1.0.0 -> v2.0.0 [UPDATING] ws v1.0.0 -> v2.0.0 "#]]) .run(); } #[cargo_test] fn update_breaking_specific_packages_that_wont_update() { Package::new("compatible", "1.0.0").publish(); Package::new("renamed-from", "1.0.0").publish(); Package::new("non-semver", "1.0.0").publish(); Package::new("bar", "1.0.0") .add_dep(Dependency::new("transitive-compatible", "1.0.0").build()) .add_dep(Dependency::new("transitive-incompatible", "1.0.0").build()) .publish(); Package::new("transitive-compatible", "1.0.0").publish(); Package::new("transitive-incompatible", "1.0.0").publish(); let crate_manifest = r#" # Check if formatting is preserved [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] compatible = "1.0" # Comment renamed-to = { package = "renamed-from", version = "1.0" } # Comment non-semver = "~1.0" # Comment bar = "1.0" # Comment "#; let p = project() .file("Cargo.toml", crate_manifest) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); let lock_file = p.read_file("Cargo.lock"); Package::new("compatible", "1.0.1").publish(); Package::new("renamed-from", "1.0.1").publish(); Package::new("non-semver", "1.0.1").publish(); Package::new("transitive-compatible", "1.0.1").publish(); Package::new("transitive-incompatible", "1.0.1").publish(); Package::new("renamed-from", "2.0.0").publish(); Package::new("non-semver", "2.0.0").publish(); Package::new("transitive-incompatible", "2.0.0").publish(); p.cargo("update -Zunstable-options --breaking compatible renamed-from non-semver transitive-compatible transitive-incompatible") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `[..]` index "#]]) .run(); let crate_manifest_after = p.read_file("Cargo.toml"); assert_e2e().eq(&crate_manifest_after, crate_manifest); let lock_file_after = p.read_file("Cargo.lock"); assert_e2e().eq(&lock_file_after, lock_file); p.cargo( "update compatible renamed-from non-semver transitive-compatible transitive-incompatible", ) .with_stderr_data(str![[r#" [UPDATING] `[..]` index [LOCKING] 5 packages to latest compatible versions [UPDATING] compatible v1.0.0 -> v1.0.1 [UPDATING] non-semver v1.0.0 -> v1.0.1 (available: v2.0.0) [UPDATING] renamed-from v1.0.0 -> v1.0.1 (available: v2.0.0) [UPDATING] transitive-compatible v1.0.0 -> v1.0.1 [UPDATING] transitive-incompatible v1.0.0 -> v1.0.1 "#]]) .run(); } #[cargo_test] fn update_breaking_without_lock_file() { Package::new("compatible", "1.0.0").publish(); Package::new("incompatible", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] compatible = "1.0" # Comment incompatible = "1.0" # Comment "#, ) .file("src/lib.rs", "") .build(); Package::new("compatible", "1.0.1").publish(); Package::new("incompatible", "1.0.1").publish(); Package::new("incompatible", "2.0.0").publish(); p.cargo("update -Zunstable-options --breaking") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `[..]` index [UPGRADING] incompatible ^1.0 -> ^2.0 [LOCKING] 2 packages to latest compatible versions "#]]) .run(); } #[cargo_test] fn update_breaking_spec_version() { Package::new("compatible", "1.0.0").publish(); Package::new("incompatible", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] compatible = "1.0" # Comment incompatible = "1.0" # Comment "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); Package::new("compatible", "1.0.1").publish(); Package::new("incompatible", "1.0.1").publish(); Package::new("incompatible", "2.0.0").publish(); // Invalid spec p.cargo("update -Zunstable-options --breaking incompatible@foo") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid package ID specification: `incompatible@foo` Caused by: expected a version like "1.32" "#]]) .run(); // Spec version not matching our current dependencies p.cargo("update -Zunstable-options --breaking incompatible@2.0.0") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#""#]]) .run(); // Spec source not matching our current dependencies p.cargo("update -Zunstable-options --breaking https://alternative.com#incompatible@1.0.0") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#""#]]) .run(); // Accepted spec p.cargo("update -Zunstable-options --breaking incompatible@1.0.0") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `[..]` index [UPGRADING] incompatible ^1.0 -> ^2.0 [LOCKING] 1 package to latest compatible version [UPDATING] incompatible v1.0.0 -> v2.0.0 "#]]) .run(); // Accepted spec, full format Package::new("incompatible", "3.0.0").publish(); p.cargo("update -Zunstable-options --breaking https://github.com/rust-lang/crates.io-index#incompatible@2.0.0") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `[..]` index [UPGRADING] incompatible ^2.0 -> ^3.0 [LOCKING] 1 package to latest compatible version [UPDATING] incompatible v2.0.0 -> v3.0.0 "#]]) .run(); // Spec matches a dependency that will not be upgraded p.cargo("update -Zunstable-options --breaking compatible@1.0.0") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `[..]` index "#]]) .run(); // Non-existing versions p.cargo("update -Zunstable-options --breaking incompatible@9.0.0") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#""#]]) .run(); p.cargo("update -Zunstable-options --breaking compatible@9.0.0") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#""#]]) .run(); } #[cargo_test] fn update_breaking_spec_version_transitive() { Package::new("dep", "1.0.0").publish(); Package::new("dep", "1.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] dep = "1.0" bar = { path = "bar", version = "0.0.1" } "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] dep = "1.1" "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); Package::new("dep", "1.1.1").publish(); Package::new("dep", "2.0.0").publish(); // Will upgrade the direct dependency p.cargo("update -Zunstable-options --breaking dep@1.0") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `[..]` index [UPGRADING] dep ^1.0 -> ^2.0 [LOCKING] 1 package to latest compatible version [ADDING] dep v2.0.0 "#]]) .run(); // But not the transitive one, because bar is not a workspace member p.cargo("update -Zunstable-options --breaking dep@1.1") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `[..]` index "#]]) .run(); // A non-breaking update is different, as it will update transitive dependencies p.cargo("update dep@1.1") .with_stderr_data(str![[r#" [UPDATING] `[..]` index [LOCKING] 1 package to latest compatible version [UPDATING] dep v1.1.0 -> v1.1.1 "#]]) .run(); } #[cargo_test] fn update_breaking_mixed_compatibility() { Package::new("mixed-compatibility", "1.0.0").publish(); Package::new("mixed-compatibility", "2.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo", "bar"] "#, ) .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] mixed-compatibility = "1.0" "#, ) .file("foo/src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.0.1" edition = "2015" authors = [] [dependencies] mixed-compatibility = "2.0" "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); Package::new("mixed-compatibility", "2.0.1").publish(); p.cargo("update -Zunstable-options --breaking") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `[..]` index [UPGRADING] mixed-compatibility ^1.0 -> ^2.0 [LOCKING] 1 package to latest compatible version [ADDING] mixed-compatibility v2.0.1 "#]]) .run(); } #[cargo_test] fn update_breaking_mixed_pinning_renaming() { Package::new("mixed-pinned", "1.0.0").publish(); Package::new("mixed-ws-pinned", "1.0.0").publish(); Package::new("renamed-from", "1.0.0").publish(); let p = project() .file( "Cargo.toml", r#" [workspace] members = ["pinned", "unpinned", "mixed"] [workspace.dependencies] mixed-ws-pinned = "=1.0" "#, ) .file( "pinned/Cargo.toml", r#" [package] name = "pinned" version = "0.0.1" edition = "2015" authors = [] [dependencies] mixed-pinned = "=1.0" mixed-ws-pinned.workspace = true renamed-to = { package = "renamed-from", version = "1.0" } "#, ) .file("pinned/src/lib.rs", "") .file( "unpinned/Cargo.toml", r#" [package] name = "unpinned" version = "0.0.1" edition = "2015" authors = [] [dependencies] mixed-pinned = "1.0" mixed-ws-pinned = "1.0" renamed-from = "1.0" "#, ) .file("unpinned/src/lib.rs", "") .file( "mixed/Cargo.toml", r#" [package] name = "mixed" version = "0.0.1" edition = "2015" authors = [] [target.'cfg(windows)'.dependencies] mixed-pinned = "1.0" [target.'cfg(unix)'.dependencies] mixed-pinned = "=1.0" "#, ) .file("mixed/src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); Package::new("mixed-pinned", "2.0.0").publish(); Package::new("mixed-ws-pinned", "2.0.0").publish(); Package::new("renamed-from", "2.0.0").publish(); p.cargo("update -Zunstable-options --breaking") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `[..]` index [UPGRADING] mixed-pinned ^1.0 -> ^2.0 [UPGRADING] mixed-ws-pinned ^1.0 -> ^2.0 [UPGRADING] renamed-from ^1.0 -> ^2.0 [LOCKING] 3 packages to latest compatible versions [ADDING] mixed-pinned v2.0.0 [ADDING] mixed-ws-pinned v2.0.0 [ADDING] renamed-from v2.0.0 "#]]) .run(); let root_manifest = p.read_file("Cargo.toml"); assert_e2e().eq( &root_manifest, str![[r#" [workspace] members = ["pinned", "unpinned", "mixed"] [workspace.dependencies] mixed-ws-pinned = "=1.0" "#]], ); let pinned_manifest = p.read_file("pinned/Cargo.toml"); assert_e2e().eq( &pinned_manifest, str![[r#" [package] name = "pinned" version = "0.0.1" edition = "2015" authors = [] [dependencies] mixed-pinned = "=1.0" mixed-ws-pinned.workspace = true renamed-to = { package = "renamed-from", version = "1.0" } "#]], ); let unpinned_manifest = p.read_file("unpinned/Cargo.toml"); assert_e2e().eq( &unpinned_manifest, str![[r#" [package] name = "unpinned" version = "0.0.1" edition = "2015" authors = [] [dependencies] mixed-pinned = "2.0" mixed-ws-pinned = "2.0" renamed-from = "2.0" "#]], ); let mixed_manifest = p.read_file("mixed/Cargo.toml"); assert_e2e().eq( &mixed_manifest, str![[r#" [package] name = "mixed" version = "0.0.1" edition = "2015" authors = [] [target.'cfg(windows)'.dependencies] mixed-pinned = "2.0" [target.'cfg(unix)'.dependencies] mixed-pinned = "=1.0" "#]], ); } #[cargo_test] fn update_breaking_pre_release_downgrade() { Package::new("bar", "2.0.0-beta.21").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "2.0.0-beta.21" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); // The purpose of this test is // to demonstrate that `update --breaking` will not try to downgrade to the latest stable version (1.7.0), // but will rather keep the latest pre-release (2.0.0-beta.21). Package::new("bar", "1.7.0").publish(); p.cargo("update -Zunstable-options --breaking bar") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index "#]]) .run(); } #[cargo_test] fn update_breaking_pre_release_upgrade() { Package::new("bar", "2.0.0-beta.21").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "2.0.0-beta.21" "#, ) .file("src/lib.rs", "") .build(); p.cargo("generate-lockfile").run(); // TODO: `2.0.0-beta.21` can be upgraded to `2.0.0-beta.22` Package::new("bar", "2.0.0-beta.22").publish(); p.cargo("update -Zunstable-options --breaking bar") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index "#]]) .run(); // TODO: `2.0.0-beta.21` can be upgraded to `2.0.0` Package::new("bar", "2.0.0").publish(); p.cargo("update -Zunstable-options --breaking bar") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index "#]]) .run(); Package::new("bar", "3.0.0").publish(); p.cargo("update -Zunstable-options --breaking bar") .masquerade_as_nightly_cargo(&["update-breaking"]) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [UPGRADING] bar ^2.0.0-beta.21 -> ^3.0.0 [LOCKING] 1 package to latest compatible version [UPDATING] bar v2.0.0-beta.21 -> v3.0.0 "#]]) .run(); } cargo-0.86.0/tests/testsuite/vendor.rs000064400000000000000000001353761046102023000160670ustar 00000000000000//! Tests for the `cargo vendor` command. //! //! Note that every test here uses `--respect-source-config` so that the //! "fake" crates.io is used. Otherwise `vendor` would download the crates.io //! index from the network. use std::fs; use cargo_test_support::compare::assert_e2e; use cargo_test_support::git; use cargo_test_support::prelude::*; use cargo_test_support::registry::{self, Package, RegistryBuilder}; use cargo_test_support::str; use cargo_test_support::{basic_lib_manifest, basic_manifest, paths, project, Project}; #[cargo_test] fn vendor_simple() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] log = "0.3.5" "#, ) .file("src/lib.rs", "") .build(); Package::new("log", "0.3.5").publish(); p.cargo("vendor --respect-source-config").run(); let lock = p.read_file("vendor/log/Cargo.toml"); assert!(lock.contains("version = \"0.3.5\"")); add_crates_io_vendor_config(&p); p.cargo("check").run(); } #[cargo_test] fn vendor_sample_config() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] log = "0.3.5" "#, ) .file("src/lib.rs", "") .build(); Package::new("log", "0.3.5").publish(); p.cargo("vendor --respect-source-config") .with_stdout_data(str![[r#" [source.crates-io] replace-with = "vendored-sources" [source.vendored-sources] directory = "vendor" "#]]) .run(); } #[cargo_test] fn vendor_sample_config_alt_registry() { let registry = RegistryBuilder::new().alternative().http_index().build(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] log = { version = "0.3.5", registry = "alternative" } "#, ) .file("src/lib.rs", "") .build(); Package::new("log", "0.3.5").alternative(true).publish(); p.cargo("vendor --respect-source-config") .with_stdout_data(format!( r#"[source."{0}"] registry = "{0}" replace-with = "vendored-sources" [source.vendored-sources] directory = "vendor" "#, registry.index_url() )) .run(); } #[cargo_test] fn vendor_path_specified() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] log = "0.3.5" "#, ) .file("src/lib.rs", "") .build(); Package::new("log", "0.3.5").publish(); let path = if cfg!(windows) { r#"deps\.vendor"# } else { "deps/.vendor" }; let output = p.cargo("vendor --respect-source-config").arg(path).run(); // Assert against original output to ensure that // path is normalized by `ops::vendor` on Windows. assert_eq!( &String::from_utf8(output.stdout).unwrap(), r#"[source.crates-io] replace-with = "vendored-sources" [source.vendored-sources] directory = "deps/.vendor" "# ); let lock = p.read_file("deps/.vendor/log/Cargo.toml"); assert!(lock.contains("version = \"0.3.5\"")); } fn add_crates_io_vendor_config(p: &Project) { p.change_file( ".cargo/config.toml", r#" [source.crates-io] replace-with = 'vendor' [source.vendor] directory = 'vendor' "#, ); } fn add_git_vendor_config(p: &Project, git_project: &Project) { p.change_file( ".cargo/config.toml", &format!( r#" [source."git+{url}"] git = "{url}" replace-with = 'vendor' [source.vendor] directory = 'vendor' "#, url = git_project.url() ), ); } #[cargo_test] fn package_exclude() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .build(); Package::new("bar", "0.1.0") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" exclude = [".*", "!.include", "!.dotdir/include"] "#, ) .file("src/lib.rs", "") .file(".exclude", "") .file(".include", "") .file(".dotdir/exclude", "") .file(".dotdir/include", "") .publish(); p.cargo("vendor --respect-source-config").run(); let csum = p.read_file("vendor/bar/.cargo-checksum.json"); assert!(csum.contains(".include")); assert!(!csum.contains(".exclude")); assert!(!csum.contains(".dotdir/exclude")); // Gitignore doesn't re-include a file in an excluded parent directory, // even if negating it explicitly. assert!(!csum.contains(".dotdir/include")); } #[cargo_test] fn discovery_inferred_build_rs_included() { let git_project = git::new("dep", |project| { project .file( "Cargo.toml", r#" [package] name = "dep" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/lib.rs", "build.rs"] "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" [dependencies.dep] git = '{}' "#, git_project.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("vendor --respect-source-config").run(); add_git_vendor_config(&p, &git_project); let lock = p.read_file("vendor/dep/Cargo.toml"); assert_e2e().eq( lock, str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "dep" version = "0.0.1" authors = [] build = "build.rs" include = [ "src/lib.rs", "build.rs", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "dep" path = "src/lib.rs" "##]], ); p.cargo("check").run(); } #[cargo_test] fn discovery_inferred_build_rs_excluded() { let git_project = git::new("dep", |project| { project .file( "Cargo.toml", r#" [package] name = "dep" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/lib.rs"] "#, ) .file("src/lib.rs", "") .file("build.rs", "fn main() {}") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" [dependencies.dep] git = '{}' "#, git_project.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("vendor --respect-source-config").run(); add_git_vendor_config(&p, &git_project); let lock = p.read_file("vendor/dep/Cargo.toml"); assert_e2e().eq( lock, str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "dep" version = "0.0.1" authors = [] build = false include = ["src/lib.rs"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "dep" path = "src/lib.rs" "##]], ); p.cargo("check").run(); } #[cargo_test] fn discovery_inferred_lib_included() { let git_project = git::new("dep", |project| { project .file( "Cargo.toml", r#" [package] name = "dep" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/main.rs", "src/lib.rs"] "#, ) .file("src/main.rs", "fn main() {}") .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" [dependencies.dep] git = '{}' "#, git_project.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("vendor --respect-source-config").run(); add_git_vendor_config(&p, &git_project); let lock = p.read_file("vendor/dep/Cargo.toml"); assert_e2e().eq( lock, str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "dep" version = "0.0.1" authors = [] build = false include = [ "src/main.rs", "src/lib.rs", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "dep" path = "src/lib.rs" [[bin]] name = "dep" path = "src/main.rs" "##]], ); p.cargo("check").run(); } #[cargo_test] fn discovery_inferred_lib_excluded() { let git_project = git::new("dep", |project| { project .file( "Cargo.toml", r#" [package] name = "dep" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/main.rs"] "#, ) .file("src/main.rs", "fn main() {}") .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" [dependencies.dep] git = '{}' "#, git_project.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("vendor --respect-source-config").run(); add_git_vendor_config(&p, &git_project); let lock = p.read_file("vendor/dep/Cargo.toml"); assert_e2e().eq( lock, str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "dep" version = "0.0.1" authors = [] build = false include = ["src/main.rs"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [[bin]] name = "dep" path = "src/main.rs" "##]], ); p.cargo("check").run(); } #[cargo_test] fn discovery_inferred_other_included() { let git_project = git::new("dep", |project| { project .file( "Cargo.toml", r#" [package] name = "dep" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/lib.rs", "src/bin/foo/main.rs", "examples/example_foo.rs", "tests/test_foo.rs", "benches/bench_foo.rs"] "#, ) .file("src/lib.rs", "") .file("src/bin/foo/main.rs", "fn main() {}") .file("examples/example_foo.rs", "fn main() {}") .file("tests/test_foo.rs", "fn main() {}") .file("benches/bench_foo.rs", "fn main() {}") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" [dependencies.dep] git = '{}' "#, git_project.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("vendor --respect-source-config").run(); add_git_vendor_config(&p, &git_project); let lock = p.read_file("vendor/dep/Cargo.toml"); assert_e2e().eq( lock, str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "dep" version = "0.0.1" authors = [] build = false include = [ "src/lib.rs", "src/bin/foo/main.rs", "examples/example_foo.rs", "tests/test_foo.rs", "benches/bench_foo.rs", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "dep" path = "src/lib.rs" [[bin]] name = "foo" path = "src/bin/foo/main.rs" [[example]] name = "example_foo" path = "examples/example_foo.rs" [[test]] name = "test_foo" path = "tests/test_foo.rs" [[bench]] name = "bench_foo" path = "benches/bench_foo.rs" "##]], ); p.cargo("check").run(); } #[cargo_test] fn discovery_inferred_other_excluded() { let git_project = git::new("dep", |project| { project .file( "Cargo.toml", r#" [package] name = "dep" version = "0.0.1" edition = "2015" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] include = ["src/lib.rs"] "#, ) .file("src/lib.rs", "") .file("src/bin/foo/main.rs", "fn main() {}") .file("examples/example_foo.rs", "fn main() {}") .file("tests/test_foo.rs", "fn main() {}") .file("benches/bench_foo.rs", "fn main() {}") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.5.0" edition = "2015" [dependencies.dep] git = '{}' "#, git_project.url() ), ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("vendor --respect-source-config").run(); add_git_vendor_config(&p, &git_project); let lock = p.read_file("vendor/dep/Cargo.toml"); assert_e2e().eq( lock, str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "dep" version = "0.0.1" authors = [] build = false include = ["src/lib.rs"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "dep" path = "src/lib.rs" "##]], ); p.cargo("check").run(); } #[cargo_test] fn two_versions() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bitflags = "0.8.0" bar = { path = "bar" } "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" [dependencies] bitflags = "0.7.0" "#, ) .file("bar/src/lib.rs", "") .build(); Package::new("bitflags", "0.7.0").publish(); Package::new("bitflags", "0.8.0").publish(); p.cargo("vendor --respect-source-config").run(); let lock = p.read_file("vendor/bitflags/Cargo.toml"); assert!(lock.contains("version = \"0.8.0\"")); let lock = p.read_file("vendor/bitflags-0.7.0/Cargo.toml"); assert!(lock.contains("version = \"0.7.0\"")); add_crates_io_vendor_config(&p); p.cargo("check").run(); } #[cargo_test] fn two_explicit_versions() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bitflags = "0.8.0" bar = { path = "bar" } "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" [dependencies] bitflags = "0.7.0" "#, ) .file("bar/src/lib.rs", "") .build(); Package::new("bitflags", "0.7.0").publish(); Package::new("bitflags", "0.8.0").publish(); p.cargo("vendor --respect-source-config --versioned-dirs") .run(); let lock = p.read_file("vendor/bitflags-0.8.0/Cargo.toml"); assert!(lock.contains("version = \"0.8.0\"")); let lock = p.read_file("vendor/bitflags-0.7.0/Cargo.toml"); assert!(lock.contains("version = \"0.7.0\"")); add_crates_io_vendor_config(&p); p.cargo("check").run(); } #[cargo_test] fn help() { let p = project().build(); p.cargo("vendor -h").run(); } #[cargo_test] fn update_versions() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bitflags = "0.7.0" "#, ) .file("src/lib.rs", "") .build(); Package::new("bitflags", "0.7.0").publish(); Package::new("bitflags", "0.8.0").publish(); p.cargo("vendor --respect-source-config").run(); let lock = p.read_file("vendor/bitflags/Cargo.toml"); assert!(lock.contains("version = \"0.7.0\"")); p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bitflags = "0.8.0" "#, ); p.cargo("vendor --respect-source-config").run(); let lock = p.read_file("vendor/bitflags/Cargo.toml"); assert!(lock.contains("version = \"0.8.0\"")); } #[cargo_test] fn two_lockfiles() { let p = project() .no_manifest() .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bitflags = "=0.7.0" "#, ) .file("foo/src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" [dependencies] bitflags = "=0.8.0" "#, ) .file("bar/src/lib.rs", "") .build(); Package::new("bitflags", "0.7.0").publish(); Package::new("bitflags", "0.8.0").publish(); p.cargo("vendor --respect-source-config -s bar/Cargo.toml --manifest-path foo/Cargo.toml") .run(); let lock = p.read_file("vendor/bitflags/Cargo.toml"); assert!(lock.contains("version = \"0.8.0\"")); let lock = p.read_file("vendor/bitflags-0.7.0/Cargo.toml"); assert!(lock.contains("version = \"0.7.0\"")); add_crates_io_vendor_config(&p); p.cargo("check").cwd("foo").run(); p.cargo("check").cwd("bar").run(); } #[cargo_test] fn test_sync_argument() { let p = project() .no_manifest() .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bitflags = "=0.7.0" "#, ) .file("foo/src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" [dependencies] bitflags = "=0.8.0" "#, ) .file("bar/src/lib.rs", "") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.0" [dependencies] bitflags = "=0.8.0" "#, ) .file("baz/src/lib.rs", "") .build(); Package::new("bitflags", "0.7.0").publish(); Package::new("bitflags", "0.8.0").publish(); p.cargo("vendor --respect-source-config --manifest-path foo/Cargo.toml -s bar/Cargo.toml baz/Cargo.toml test_vendor") .with_stderr_data(str![[r#" [ERROR] unexpected argument 'test_vendor' found Usage: cargo[EXE] vendor [OPTIONS] [path] For more information, try '--help'. "#]] ) .with_status(1) .run(); p.cargo("vendor --respect-source-config --manifest-path foo/Cargo.toml -s bar/Cargo.toml -s baz/Cargo.toml test_vendor") .run(); let lock = p.read_file("test_vendor/bitflags/Cargo.toml"); assert!(lock.contains("version = \"0.8.0\"")); let lock = p.read_file("test_vendor/bitflags-0.7.0/Cargo.toml"); assert!(lock.contains("version = \"0.7.0\"")); } #[cargo_test] fn delete_old_crates() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bitflags = "=0.7.0" "#, ) .file("src/lib.rs", "") .build(); Package::new("bitflags", "0.7.0").publish(); Package::new("log", "0.3.5").publish(); p.cargo("vendor --respect-source-config").run(); p.read_file("vendor/bitflags/Cargo.toml"); p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] log = "=0.3.5" "#, ); p.cargo("vendor --respect-source-config").run(); let lock = p.read_file("vendor/log/Cargo.toml"); assert!(lock.contains("version = \"0.3.5\"")); assert!(!p.root().join("vendor/bitflags/Cargo.toml").exists()); } #[cargo_test] fn ignore_files() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] url = "1.4.1" "#, ) .file("src/lib.rs", "") .build(); Package::new("url", "1.4.1") .file("src/lib.rs", "") .file("foo.orig", "") .file(".gitignore", "") .file(".gitattributes", "") .file("foo.rej", "") .publish(); p.cargo("vendor --respect-source-config").run(); let csum = p.read_file("vendor/url/.cargo-checksum.json"); assert!(!csum.contains("foo.orig")); assert!(!csum.contains(".gitignore")); assert!(!csum.contains(".gitattributes")); assert!(!csum.contains(".cargo-ok")); assert!(!csum.contains("foo.rej")); } #[cargo_test] fn included_files_only() { let git = git::new("a", |p| { p.file("Cargo.toml", &basic_lib_manifest("a")) .file("src/lib.rs", "") .file(".gitignore", "a") .file("a/b.md", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] a = {{ git = '{}' }} "#, git.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("vendor --respect-source-config").run(); let csum = p.read_file("vendor/a/.cargo-checksum.json"); assert!(!csum.contains("a/b.md")); } #[cargo_test] fn dependent_crates_in_crates() { let git = git::new("a", |p| { p.file( "Cargo.toml", r#" [package] name = "a" version = "0.1.0" [dependencies] b = { path = 'b' } "#, ) .file("src/lib.rs", "") .file("b/Cargo.toml", &basic_lib_manifest("b")) .file("b/src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] a = {{ git = '{}' }} "#, git.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("vendor --respect-source-config").run(); p.read_file("vendor/a/.cargo-checksum.json"); p.read_file("vendor/b/.cargo-checksum.json"); } #[cargo_test] fn vendoring_git_crates() { let git = git::new("git", |p| { p.file("Cargo.toml", &basic_lib_manifest("serde_derive")) .file("src/lib.rs", "") .file("src/wut.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies.serde] version = "0.5.0" [dependencies.serde_derive] version = "0.5.0" [patch.crates-io] serde_derive = {{ git = '{}' }} "#, git.url() ), ) .file("src/lib.rs", "") .build(); Package::new("serde", "0.5.0") .dep("serde_derive", "0.5") .publish(); Package::new("serde_derive", "0.5.0").publish(); p.cargo("vendor --respect-source-config").run(); p.read_file("vendor/serde_derive/src/wut.rs"); add_crates_io_vendor_config(&p); p.cargo("check").run(); } #[cargo_test] fn git_simple() { let git = git::new("git", |p| { p.file("Cargo.toml", &basic_lib_manifest("a")) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] a = {{ git = '{}' }} "#, git.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("vendor --respect-source-config").run(); let csum = p.read_file("vendor/a/.cargo-checksum.json"); assert!(csum.contains("\"package\":null")); } #[cargo_test] fn git_diff_rev() { let (git_project, git_repo) = git::new_repo("git", |p| { p.file("Cargo.toml", &basic_manifest("a", "0.1.0")) .file("src/lib.rs", "") }); let url = git_project.url(); let ref_1 = "v0.1.0"; let ref_2 = "v0.2.0"; git::tag(&git_repo, ref_1); git_project.change_file("Cargo.toml", &basic_manifest("a", "0.2.0")); git::add(&git_repo); git::commit(&git_repo); git::tag(&git_repo, ref_2); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] a_1 = {{ package = "a", git = '{url}', rev = '{ref_1}' }} a_2 = {{ package = "a", git = '{url}', rev = '{ref_2}' }} "# ), ) .file("src/lib.rs", "") .build(); p.cargo("vendor --respect-source-config") .with_stdout_data(str![[r#" [source."git+[ROOTURL]/git?rev=v0.1.0"] git = "[ROOTURL]/git" rev = "v0.1.0" replace-with = "vendored-sources" [source."git+[ROOTURL]/git?rev=v0.2.0"] git = "[ROOTURL]/git" rev = "v0.2.0" replace-with = "vendored-sources" [source.vendored-sources] directory = "vendor" "#]]) .run(); } #[cargo_test] fn git_duplicate() { let git = git::new("a", |p| { p.file( "Cargo.toml", r#" [package] name = "a" version = "0.1.0" [dependencies] b = { path = 'b' } "#, ) .file("src/lib.rs", "") .file("b/Cargo.toml", &basic_lib_manifest("b")) .file("b/src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] a = {{ git = '{}' }} b = '0.5.0' "#, git.url() ), ) .file("src/lib.rs", "") .build(); Package::new("b", "0.5.0").publish(); p.cargo("vendor --respect-source-config") .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/a` [UPDATING] `dummy-registry` index [LOCKING] 3 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] b v0.5.0 (registry `dummy-registry`) [ERROR] failed to sync Caused by: found duplicate version of package `b v0.5.0` vendored from two sources: source 1: registry `crates-io` source 2: [ROOTURL]/a#[..] "#]]) .with_status(101) .run(); } #[cargo_test] fn git_complex() { let git_b = git::new("git_b", |p| { p.file( "Cargo.toml", r#" [package] name = "b" version = "0.1.0" edition = "2021" [dependencies] dep_b = { path = 'dep_b' } "#, ) .file("src/lib.rs", "") .file("dep_b/Cargo.toml", &basic_lib_manifest("dep_b")) .file("dep_b/src/lib.rs", "") }); let git_a = git::new("git_a", |p| { p.file( "Cargo.toml", &format!( r#" [package] name = "a" version = "0.1.0" edition = "2021" [dependencies] b = {{ git = '{}' }} dep_a = {{ path = 'dep_a' }} "#, git_b.url() ), ) .file("src/lib.rs", "") .file("dep_a/Cargo.toml", &basic_lib_manifest("dep_a")) .file("dep_a/src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2021" [dependencies] a = {{ git = '{}' }} "#, git_a.url() ), ) .file("src/lib.rs", "") .build(); let output = p.cargo("vendor --respect-source-config").run(); let output = String::from_utf8(output.stdout).unwrap(); p.change_file(".cargo/config.toml", &output); p.cargo("check -v") .with_stderr_data( str![[r#" [CHECKING] dep_b v0.5.0 ([ROOTURL]/git_b#[..]) [CHECKING] dep_a v0.5.0 ([ROOTURL]/git_a#[..]) [RUNNING] `rustc [..] [ROOT]/foo/vendor/dep_b/src/lib.rs [..]` [RUNNING] `rustc [..] [ROOT]/foo/vendor/dep_a/src/lib.rs [..]` [CHECKING] b v0.1.0 ([ROOTURL]/git_b#[..]) [RUNNING] `rustc [..] [ROOT]/foo/vendor/b/src/lib.rs [..]` [CHECKING] a v0.1.0 ([ROOTURL]/git_a#[..]) [RUNNING] `rustc [..] [ROOT]/foo/vendor/a/src/lib.rs [..]` [CHECKING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] src/lib.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]] .unordered(), ) .run(); } #[cargo_test] fn git_deterministic() { let git_dep = git::new("git_dep", |p| { p.file( "Cargo.toml", r#" [package] name = "git_dep" version = "0.0.1" edition = "2021" license = "MIT" description = "foo" documentation = "docs.rs/foo" authors = [] [[example]] name = "c" [[example]] name = "b" [[example]] name = "a" "#, ) .file("src/lib.rs", "") .file("examples/z.rs", "fn main() {}") .file("examples/y.rs", "fn main() {}") .file("examples/x.rs", "fn main() {}") .file("examples/c.rs", "fn main() {}") .file("examples/b.rs", "fn main() {}") .file("examples/a.rs", "fn main() {}") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] git_dep = {{ git = '{}' }} "#, git_dep.url() ), ) .file("src/lib.rs", "") .build(); let output = p.cargo("vendor --respect-source-config").run(); let output = String::from_utf8(output.stdout).unwrap(); p.change_file(".cargo/config.toml", &output); let git_dep_manifest = p.read_file("vendor/git_dep/Cargo.toml"); assert_e2e().eq( git_dep_manifest, str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "git_dep" version = "0.0.1" authors = [] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" documentation = "docs.rs/foo" readme = false license = "MIT" [lib] name = "git_dep" path = "src/lib.rs" [[example]] name = "a" path = "examples/a.rs" [[example]] name = "b" path = "examples/b.rs" [[example]] name = "c" path = "examples/c.rs" [[example]] name = "x" path = "examples/x.rs" [[example]] name = "y" path = "examples/y.rs" [[example]] name = "z" path = "examples/z.rs" "##]], ); } #[cargo_test] fn git_update_rev() { let (git_project, git_repo) = git::new_repo("git", |p| { p.file("Cargo.toml", &basic_manifest("a", "0.1.0")) .file("src/lib.rs", "") }); let url = git_project.url(); let ref_1 = "initial"; let ref_2 = "update"; git::tag(&git_repo, ref_1); git_project.change_file("src/lib.rs", "pub fn f() {}"); git::add(&git_repo); git::commit(&git_repo); git::tag(&git_repo, ref_2); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] a = {{ git = '{url}', rev = '{ref_1}' }} "# ), ) .file("src/lib.rs", "") .build(); p.cargo("vendor --respect-source-config --versioned-dirs") .run(); let lib = p.read_file("vendor/a-0.1.0/src/lib.rs"); assert_e2e().eq(lib, ""); p.change_file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] a = {{ git = '{url}', rev = '{ref_2}' }} "# ), ); p.cargo("vendor --respect-source-config --versioned-dirs") .run(); let lib = p.read_file("vendor/a-0.1.0/src/lib.rs"); assert_e2e().eq(lib, "pub fn f() {}"); } #[cargo_test] fn depend_on_vendor_dir_not_deleted() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] libc = "0.2.30" "#, ) .file("src/lib.rs", "") .build(); Package::new("libc", "0.2.30").publish(); p.cargo("vendor --respect-source-config").run(); assert!(p.root().join("vendor/libc").is_dir()); p.change_file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] libc = "0.2.30" [patch.crates-io] libc = { path = 'vendor/libc' } "#, ); p.cargo("vendor --respect-source-config").run(); assert!(p.root().join("vendor/libc").is_dir()); } #[cargo_test] fn ignore_hidden() { // Don't delete files starting with `.` Package::new("bar", "0.1.0").publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "1.0.0" [dependencies] bar = "0.1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("vendor --respect-source-config").run(); // Add a `.git` directory. let repo = git::init(&p.root().join("vendor")); git::add(&repo); git::commit(&repo); assert!(p.root().join("vendor/.git").exists()); // Vendor again, shouldn't change anything. p.cargo("vendor --respect-source-config").run(); // .git should not be removed. assert!(p.root().join("vendor/.git").exists()); // And just for good measure, make sure no files changed. let mut opts = git2::StatusOptions::new(); assert!(repo .statuses(Some(&mut opts)) .unwrap() .iter() .all(|status| status.status() == git2::Status::CURRENT)); } #[cargo_test] fn config_instructions_works() { // Check that the config instructions work for all dependency kinds. registry::alt_init(); Package::new("dep", "0.1.0").publish(); Package::new("altdep", "0.1.0").alternative(true).publish(); let git_project = git::new("gitdep", |project| { project .file("Cargo.toml", &basic_lib_manifest("gitdep")) .file("src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2021" [dependencies] dep = "0.1" altdep = {{version="0.1", registry="alternative"}} gitdep = {{git='{}'}} "#, git_project.url() ), ) .file("src/lib.rs", "") .build(); let output = p.cargo("vendor --respect-source-config").run(); let output = String::from_utf8(output.stdout).unwrap(); p.change_file(".cargo/config.toml", &output); p.cargo("check -v") .with_stderr_data( str![[r#" [CHECKING] altdep v0.1.0 (registry `alternative`) [CHECKING] dep v0.1.0 [RUNNING] `rustc [..] [ROOT]/foo/vendor/altdep/src/lib.rs [..]` [RUNNING] `rustc [..] [ROOT]/foo/vendor/gitdep/src/lib.rs [..]` [RUNNING] `rustc [..] [ROOT]/foo/vendor/dep/src/lib.rs [..]` [CHECKING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] src/lib.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [CHECKING] gitdep v0.5.0 ([ROOTURL]/gitdep#[..]) "#]] .unordered(), ) .run(); } #[cargo_test] fn git_crlf_preservation() { // Check that newlines don't get changed when you vendor // (will only fail if your system is setup with core.autocrlf=true on windows) let input = "hello \nthere\nmy newline\nfriends"; let git_project = git::new("git", |p| { p.file("Cargo.toml", &basic_lib_manifest("a")) .file("src/lib.rs", input) }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" [dependencies] a = {{ git = '{}' }} "#, git_project.url() ), ) .file("src/lib.rs", "") .build(); fs::write( paths::home().join(".gitconfig"), r#" [core] autocrlf = true "#, ) .unwrap(); p.cargo("vendor --respect-source-config").run(); let output = p.read_file("vendor/a/src/lib.rs"); assert_eq!(input, output); } #[cargo_test] #[cfg(unix)] fn vendor_preserves_permissions() { use std::os::unix::fs::MetadataExt; Package::new("bar", "1.0.0") .file_with_mode("example.sh", 0o755, "#!/bin/sh") .file("src/lib.rs", "") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("vendor --respect-source-config").run(); let umask = cargo::util::get_umask(); let metadata = fs::metadata(p.root().join("vendor/bar/src/lib.rs")).unwrap(); assert_eq!(metadata.mode() & 0o777, 0o644 & !umask); let metadata = fs::metadata(p.root().join("vendor/bar/example.sh")).unwrap(); assert_eq!(metadata.mode() & 0o777, 0o755 & !umask); } #[cargo_test] fn no_remote_dependency_no_vendor() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = { path = "bar" } "#, ) .file("src/lib.rs", "") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" "#, ) .file("bar/src/lib.rs", "") .build(); p.cargo("vendor") .with_stderr_data(str![[r#" [LOCKING] 1 package to latest compatible version There is no dependency to vendor in this project. "#]]) .run(); assert!(!p.root().join("vendor").exists()); } #[cargo_test] fn vendor_crate_with_ws_inherit() { let git = git::new("ws", |p| { p.file( "Cargo.toml", r#" [workspace] members = ["bar"] [workspace.package] version = "0.1.0" "#, ) .file( "bar/Cargo.toml", r#" [package] name = "bar" version.workspace = true edition = "2021" "#, ) .file("bar/src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2021" [dependencies] bar = {{ git = '{}' }} "#, git.url() ), ) .file("src/lib.rs", "") .build(); p.cargo("vendor --respect-source-config").run(); p.change_file( ".cargo/config.toml", &format!( r#" [source."{}"] git = "{}" replace-with = "vendor" [source.vendor] directory = "vendor" "#, git.url(), git.url() ), ); p.cargo("check -v") .with_stderr_data(str![[r#" [CHECKING] bar v0.1.0 ([ROOTURL]/ws#[..]) [RUNNING] `rustc [..] [ROOT]/foo/vendor/bar/src/lib.rs [..]` [CHECKING] foo v0.1.0 ([ROOT]/foo) [RUNNING] `rustc [..] src/lib.rs [..]` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } cargo-0.86.0/tests/testsuite/verify_project.rs000064400000000000000000000037611046102023000176140ustar 00000000000000//! Tests for the `cargo verify-project` command. use cargo_test_support::prelude::*; use cargo_test_support::{basic_bin_manifest, main_file, project, str}; #[cargo_test] fn cargo_verify_project_path_to_cargo_toml_relative() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("verify-project --manifest-path foo/Cargo.toml") .cwd(p.root().parent().unwrap()) .with_stdout_data(str![[r#" {"success":"true"} "#]]) .run(); } #[cargo_test] fn cargo_verify_project_path_to_cargo_toml_absolute() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("verify-project --manifest-path") .arg(p.root().join("Cargo.toml")) .cwd(p.root().parent().unwrap()) .with_stdout_data(str![[r#" {"success":"true"} "#]]) .run(); } #[cargo_test] fn cargo_verify_project_cwd() { let p = project() .file("Cargo.toml", &basic_bin_manifest("foo")) .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) .build(); p.cargo("verify-project") .with_stdout_data(str![[r#" {"success":"true"} "#]]) .run(); } #[cargo_test] fn cargo_verify_project_honours_unstable_features() { let p = project() .file( "Cargo.toml", r#" cargo-features = ["test-dummy-unstable"] [package] name = "foo" version = "0.0.1" "#, ) .file("src/lib.rs", "") .build(); p.cargo("verify-project") .masquerade_as_nightly_cargo(&["test-dummy-unstable"]) .with_stdout_data(str![[r#" {"success":"true"} "#]]) .run(); p.cargo("verify-project") .with_status(1) .with_stdout_data(str![[r#" {"invalid":"failed to parse manifest at `[..]`"} "#]]) .run(); } cargo-0.86.0/tests/testsuite/version.rs000064400000000000000000000026771046102023000162540ustar 00000000000000//! Tests for displaying the cargo version. use cargo_test_support::prelude::*; use cargo_test_support::{cargo_process, project}; #[cargo_test] fn simple() { let p = project().build(); p.cargo("version") .with_stdout_data(&format!("cargo {}\n", cargo::version())) .run(); p.cargo("--version") .with_stdout_data(&format!("cargo {}\n", cargo::version())) .run(); p.cargo("-V") .with_stdout_data(&format!("cargo {}\n", cargo::version())) .run(); } #[cargo_test] fn version_works_without_rustc() { let p = project().build(); p.cargo("version").env("PATH", "").run(); } #[cargo_test] fn version_works_with_bad_config() { let p = project() .file(".cargo/config.toml", "this is not toml") .build(); p.cargo("version").run(); } #[cargo_test] fn version_works_with_bad_target_dir() { let p = project() .file( ".cargo/config.toml", r#" [build] target-dir = 4 "#, ) .build(); p.cargo("version").run(); } #[cargo_test] fn verbose() { // This is mainly to check that it doesn't explode. cargo_process("-vV") .with_stdout_data(format!( "\ cargo {} release: [..] commit-hash: [..] commit-date: [..] host: [HOST_TARGET] libgit2: [..] (sys:[..] [..]) libcurl: [..] (sys:[..] [..]) ... os: [..] ", cargo::version() )) .run(); } cargo-0.86.0/tests/testsuite/warn_on_failure.rs000064400000000000000000000066101046102023000177300ustar 00000000000000//! Tests for whether or not warnings are displayed for build scripts. use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{project, str, Project}; static WARNING1: &str = "Hello! I'm a warning. :)"; static WARNING2: &str = "And one more!"; fn make_lib(lib_src: &str) { Package::new("bar", "0.0.1") .file( "Cargo.toml", r#" [package] name = "bar" authors = [] version = "0.0.1" edition = "2015" build = "build.rs" "#, ) .file( "build.rs", &format!( r#" fn main() {{ use std::io::Write; println!("cargo::warning={{}}", "{}"); println!("hidden stdout"); write!(&mut ::std::io::stderr(), "hidden stderr"); println!("cargo::warning={{}}", "{}"); }} "#, WARNING1, WARNING2 ), ) .file("src/lib.rs", &format!("fn f() {{ {} }}", lib_src)) .publish(); } fn make_upstream(main_src: &str) -> Project { project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("src/main.rs", &format!("fn main() {{ {} }}", main_src)) .build() } #[cargo_test] fn no_warning_on_success() { make_lib(""); let upstream = make_upstream(""); upstream .cargo("build") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [COMPILING] bar v0.0.1 [COMPILING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn no_warning_on_bin_failure() { make_lib(""); let upstream = make_upstream("hi()"); upstream .cargo("build") .with_status(101) .with_stdout_does_not_contain("hidden stdout") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [COMPILING] bar v0.0.1 [COMPILING] foo v0.0.1 ([ROOT]/foo) error[E0425]: cannot find function `hi` in this scope ... [ERROR] could not compile `foo` (bin "foo") due to 1 previous error "#]]) .run(); } #[cargo_test] fn warning_on_lib_failure() { make_lib("err()"); let upstream = make_upstream(""); upstream .cargo("build") .with_status(101) .with_stdout_does_not_contain("hidden stdout") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) [COMPILING] bar v0.0.1 error[E0425]: cannot find function `err` in this scope ... [WARNING] bar@0.0.1: Hello! I'm a warning. :) [WARNING] bar@0.0.1: And one more! [ERROR] could not compile `bar` (lib) due to 1 previous error "#]]) .run(); } cargo-0.86.0/tests/testsuite/warning_override.rs000064400000000000000000000142261046102023000201240ustar 00000000000000//! Tests for overriding warning behavior using `build.warnings` config option. use cargo_test_support::{cargo_test, project, str, tools, Project}; fn make_project_with_rustc_warning() -> Project { project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.0.1" edition = "2021" "# ), ) .file("src/main.rs", "fn main() { let x = 3; }") .build() } #[cargo_test] fn rustc_caching_allow_first() { let p = make_project_with_rustc_warning(); p.cargo("check") .masquerade_as_nightly_cargo(&["warnings"]) .arg("-Zwarnings") .arg("--config") .arg("build.warnings='allow'") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .masquerade_as_nightly_cargo(&["warnings"]) .arg("-Zwarnings") .arg("--config") .arg("build.warnings='deny'") .with_stderr_data(str![[r#" [WARNING] unused variable: `x` --> src/main.rs:1:17 | 1 | fn main() { let x = 3; } | ^ [HELP] if this is intentional, prefix it with an underscore: `_x` | = [NOTE] `#[warn(unused_variables)]` on by default [WARNING] `foo` (bin "foo") generated 1 warning [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [ERROR] warnings are denied by `build.warnings` configuration "#]]) .with_status(101) .run(); } #[cargo_test] fn rustc_caching_deny_first() { let p = make_project_with_rustc_warning(); p.cargo("check") .masquerade_as_nightly_cargo(&["warnings"]) .arg("-Zwarnings") .arg("--config") .arg("build.warnings='deny'") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [WARNING] unused variable: `x` --> src/main.rs:1:17 | 1 | fn main() { let x = 3; } | ^ [HELP] if this is intentional, prefix it with an underscore: `_x` | = [NOTE] `#[warn(unused_variables)]` on by default [WARNING] `foo` (bin "foo") generated 1 warning [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [ERROR] warnings are denied by `build.warnings` configuration "#]]) .with_status(101) .run(); p.cargo("check") .masquerade_as_nightly_cargo(&["warnings"]) .arg("-Zwarnings") .arg("--config") .arg("build.warnings='allow'") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn config() { let p = make_project_with_rustc_warning(); p.cargo("check") .masquerade_as_nightly_cargo(&["warnings"]) .arg("-Zwarnings") .env("CARGO_BUILD_WARNINGS", "deny") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [WARNING] unused variable: `x` --> src/main.rs:1:17 | 1 | fn main() { let x = 3; } | ^ [HELP] if this is intentional, prefix it with an underscore: `_x` | = [NOTE] `#[warn(unused_variables)]` on by default [WARNING] `foo` (bin "foo") generated 1 warning [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [ERROR] warnings are denied by `build.warnings` configuration "#]]) .with_status(101) .run(); // CLI has precedence over env p.cargo("check") .masquerade_as_nightly_cargo(&["warnings"]) .arg("-Zwarnings") .arg("--config") .arg("build.warnings='warn'") .env("CARGO_BUILD_WARNINGS", "deny") .with_stderr_data(str![[r#" [WARNING] unused variable: `x` --> src/main.rs:1:17 | 1 | fn main() { let x = 3; } | ^ [HELP] if this is intentional, prefix it with an underscore: `_x` | = [NOTE] `#[warn(unused_variables)]` on by default [WARNING] `foo` (bin "foo") generated 1 warning [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn requires_nightly() { // build.warnings has no effect without -Zwarnings. let p = make_project_with_rustc_warning(); p.cargo("check") .arg("--config") .arg("build.warnings='deny'") .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [WARNING] unused variable: `x` --> src/main.rs:1:17 | 1 | fn main() { let x = 3; } | ^ [HELP] if this is intentional, prefix it with an underscore: `_x` | = [NOTE] `#[warn(unused_variables)]` on by default [WARNING] `foo` (bin "foo") generated 1 warning [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn clippy() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" edition = "2015" "#, ) .file("src/lib.rs", "use std::io;") // <-- unused import .build(); p.cargo("check") .masquerade_as_nightly_cargo(&["warnings"]) .arg("-Zwarnings") .arg("--config") .arg("build.warnings='deny'") .env("RUSTC_WORKSPACE_WRAPPER", tools::wrapped_clippy_driver()) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) [WARNING] unused import: `std::io` ... [WARNING] `foo` (lib) generated 1 warning (run `cargo clippy --fix --lib -p foo` to apply 1 suggestion) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [ERROR] warnings are denied by `build.warnings` configuration "#]]) .with_status(101) .run(); } #[cargo_test] fn unknown_value() { let p = make_project_with_rustc_warning(); p.cargo("check") .masquerade_as_nightly_cargo(&["warnings"]) .arg("-Zwarnings") .arg("--config") .arg("build.warnings='forbid'") .with_stderr_data(str![[r#" [ERROR] error in --config cli option: could not load config key `build.warnings` Caused by: unknown variant `forbid`, expected one of `warn`, `allow`, `deny` "#]]) .with_status(101) .run(); } cargo-0.86.0/tests/testsuite/weak_dep_features.rs000064400000000000000000000430221046102023000202310ustar 00000000000000//! Tests for weak-dep-features. use std::fmt::Write; use cargo_test_support::prelude::*; use cargo_test_support::registry::{Dependency, Package, RegistryBuilder}; use cargo_test_support::str; use cargo_test_support::{project, publish}; use super::features2::switch_to_resolver_2; // Helper to create lib.rs files that check features. fn require(enabled_features: &[&str], disabled_features: &[&str]) -> String { let mut s = String::new(); writeln!(s, "#![allow(unexpected_cfgs)]").unwrap(); for feature in enabled_features { writeln!(s, "#[cfg(not(feature=\"{feature}\"))] compile_error!(\"expected feature {feature} to be enabled\");", feature=feature).unwrap(); } for feature in disabled_features { writeln!(s, "#[cfg(feature=\"{feature}\")] compile_error!(\"did not expect feature {feature} to be enabled\");", feature=feature).unwrap(); } s } #[cargo_test] fn simple() { Package::new("bar", "1.0.0") .feature("feat", &[]) .file("src/lib.rs", &require(&["feat"], &[])) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { version = "1.0", optional = true } [features] f1 = ["bar?/feat"] "#, ) .file("src/lib.rs", &require(&["f1"], &[])) .build(); // It's a bit unfortunate that this has to download `bar`, but avoiding // that is extremely difficult. p.cargo("check --features f1") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check --features f1,bar") .with_stderr_data(str![[r#" [CHECKING] bar v1.0.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn deferred() { // A complex chain that requires deferring enabling the feature due to // another dependency getting enabled. Package::new("bar", "1.0.0") .feature("feat", &[]) .file("src/lib.rs", &require(&["feat"], &[])) .publish(); Package::new("dep", "1.0.0") .add_dep(Dependency::new("bar", "1.0").optional(true)) .feature("feat", &["bar?/feat"]) .publish(); Package::new("bar_activator", "1.0.0") .feature_dep("dep", "1.0", &["bar"]) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] dep = { version = "1.0", features = ["feat"] } bar_activator = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 3 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] dep v1.0.0 (registry `dummy-registry`) [DOWNLOADED] bar_activator v1.0.0 (registry `dummy-registry`) [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [CHECKING] bar v1.0.0 [CHECKING] dep v1.0.0 [CHECKING] bar_activator v1.0.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn not_optional_dep() { // Attempt to use dep_name?/feat where dep_name is not optional. Package::new("dep", "1.0.0").feature("feat", &[]).publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] dep = "1.0" [features] feat = ["dep?/feat"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` Caused by: feature `feat` includes `dep?/feat` with a `?`, but `dep` is not an optional dependency A non-optional dependency of the same name is defined; consider removing the `?` or changing the dependency to be optional "#]]) .run(); } #[cargo_test] fn optional_cli_syntax() { // --features bar?/feat Package::new("bar", "1.0.0") .feature("feat", &[]) .file("src/lib.rs", &require(&["feat"], &[])) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { version = "1.0", optional = true } "#, ) .file("src/lib.rs", "") .build(); // Does not build bar. p.cargo("check --features bar?/feat") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Builds bar. p.cargo("check --features bar?/feat,bar") .with_stderr_data(str![[r#" [CHECKING] bar v1.0.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); eprintln!("check V2 resolver"); switch_to_resolver_2(&p); p.build_dir().rm_rf(); // Does not build bar. p.cargo("check --features bar?/feat") .with_stderr_data(str![[r#" [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Builds bar. p.cargo("check --features bar?/feat,bar") .with_stderr_data(str![[r#" [CHECKING] bar v1.0.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn required_features() { // required-features doesn't allow ? Package::new("bar", "1.0.0").feature("feat", &[]).publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { version = "1.0", optional = true } [[bin]] name = "foo" required-features = ["bar?/feat"] "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [ERROR] invalid feature `bar?/feat` in required-features of target `foo`: optional dependency with `?` is not allowed in required-features "#]]) .run(); } #[cargo_test] fn weak_with_host_decouple() { // weak-dep-features with new resolver // // foo v0.1.0 // └── common v1.0.0 // └── bar v1.0.0 <-- does not have `feat` enabled // [build-dependencies] // └── bar_activator v1.0.0 // └── common v1.0.0 // └── bar v1.0.0 <-- does have `feat` enabled Package::new("bar", "1.0.0") .feature("feat", &[]) .file( "src/lib.rs", r#" pub fn feat() -> bool { cfg!(feature = "feat") } "#, ) .publish(); Package::new("common", "1.0.0") .add_dep(Dependency::new("bar", "1.0").optional(true)) .feature("feat", &["bar?/feat"]) .file( "src/lib.rs", r#" #[cfg(feature = "bar")] pub fn feat() -> bool { bar::feat() } #[cfg(not(feature = "bar"))] pub fn feat() -> bool { false } "#, ) .publish(); Package::new("bar_activator", "1.0.0") .feature_dep("common", "1.0", &["bar", "feat"]) .file( "src/lib.rs", r#" pub fn feat() -> bool { common::feat() } "#, ) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" resolver = "2" [dependencies] common = { version = "1.0", features = ["feat"] } [build-dependencies] bar_activator = "1.0" "#, ) .file( "src/main.rs", r#" fn main() { assert!(!common::feat()); } "#, ) .file( "build.rs", r#" fn main() { assert!(bar_activator::feat()); } "#, ) .build(); p.cargo("run") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 3 packages to latest compatible versions [DOWNLOADING] crates ... [DOWNLOADED] common v1.0.0 (registry `dummy-registry`) [DOWNLOADED] bar_activator v1.0.0 (registry `dummy-registry`) [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [COMPILING] bar v1.0.0 [COMPILING] common v1.0.0 [COMPILING] bar_activator v1.0.0 [COMPILING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [RUNNING] `target/debug/foo[EXE]` "#]]) .run(); } #[cargo_test] fn weak_namespaced() { // Behavior with a dep: dependency. Package::new("bar", "1.0.0") .feature("feat", &[]) .file("src/lib.rs", &require(&["feat"], &[])) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { version = "1.0", optional = true } [features] f1 = ["bar?/feat"] f2 = ["dep:bar"] "#, ) .file("src/lib.rs", &require(&["f1"], &["f2", "bar"])) .build(); p.cargo("check --features f1") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("tree -f") .arg("{p} feats:{f}") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) feats: "#]]) .run(); p.cargo("tree --features f1 -f") .arg("{p} feats:{f}") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) feats:f1 "#]]) .run(); p.cargo("tree --features f1,f2 -f") .arg("{p} feats:{f}") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) feats:f1,f2 └── bar v1.0.0 feats:feat "#]]) .run(); // "bar" remains not-a-feature p.change_file("src/lib.rs", &require(&["f1", "f2"], &["bar"])); p.cargo("check --features f1,f2") .with_stderr_data(str![[r#" [CHECKING] bar v1.0.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn tree() { Package::new("bar", "1.0.0") .feature("feat", &[]) .file("src/lib.rs", &require(&["feat"], &[])) .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] bar = { version = "1.0", optional = true } [features] f1 = ["bar?/feat"] "#, ) .file("src/lib.rs", &require(&["f1"], &[])) .build(); p.cargo("tree --features f1") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) "#]]) .run(); p.cargo("tree --features f1,bar") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar v1.0.0 "#]]) .run(); p.cargo("tree --features f1,bar -e features") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) └── bar feature "default" └── bar v1.0.0 "#]]) .run(); p.cargo("tree --features f1,bar -e features -i bar") .with_stdout_data(str![[r#" bar v1.0.0 β”œβ”€β”€ bar feature "default" β”‚ └── foo v0.1.0 ([ROOT]/foo) β”‚ β”œβ”€β”€ foo feature "bar" (command-line) β”‚ β”œβ”€β”€ foo feature "default" (command-line) β”‚ └── foo feature "f1" (command-line) └── bar feature "feat" └── foo feature "f1" (command-line) "#]]) .run(); p.cargo("tree -e features --features bar?/feat") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo) "#]]) .run(); // This is a little strange in that it produces no output. // Maybe `cargo tree` should print a note about why? p.cargo("tree -e features -i bar --features bar?/feat") .with_stdout_data("") .run(); p.cargo("tree -e features -i bar --features bar?/feat,bar") .with_stdout_data(str![[r#" bar v1.0.0 β”œβ”€β”€ bar feature "default" β”‚ └── foo v0.1.0 ([ROOT]/foo) β”‚ β”œβ”€β”€ foo feature "bar" (command-line) β”‚ └── foo feature "default" (command-line) └── bar feature "feat" (command-line) "#]]) .run(); } #[cargo_test] fn publish() { let registry = RegistryBuilder::new().http_api().http_index().build(); // Publish behavior with /? syntax. Package::new("bar", "1.0.0").feature("feat", &[]).publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" description = "foo" license = "MIT" homepage = "https://example.com/" [dependencies] bar = { version = "1.0", optional = true } [features] feat1 = [] feat2 = ["bar?/feat"] "#, ) .file("src/lib.rs", "") .build(); p.cargo("publish") .replace_crates_io(registry.index_url()) .with_stderr_data(str![[r#" [UPDATING] crates.io index [PACKAGING] foo v0.1.0 ([ROOT]/foo) [UPDATING] crates.io index [PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed) [VERIFYING] foo v0.1.0 ([ROOT]/foo) [COMPILING] foo v0.1.0 ([ROOT]/foo/target/package/foo-0.1.0) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s [UPLOADING] foo v0.1.0 ([ROOT]/foo) [UPLOADED] foo v0.1.0 to registry `crates-io` [NOTE] waiting for `foo v0.1.0` to be available at registry `crates-io`. You may press ctrl-c to skip waiting; the crate should be available shortly. [PUBLISHED] foo v0.1.0 at registry `crates-io` "#]]) .run(); publish::validate_upload_with_contents( r#" { "authors": [], "badges": {}, "categories": [], "deps": [ { "default_features": true, "features": [], "kind": "normal", "name": "bar", "optional": true, "target": null, "version_req": "^1.0" } ], "description": "foo", "documentation": null, "features": { "feat1": [], "feat2": ["bar?/feat"] }, "homepage": "https://example.com/", "keywords": [], "license": "MIT", "license_file": null, "links": null, "name": "foo", "readme": null, "readme_file": null, "repository": null, "rust_version": null, "vers": "0.1.0" } "#, "foo-0.1.0.crate", &["Cargo.toml", "Cargo.toml.orig", "src/lib.rs", "Cargo.lock"], [( "Cargo.toml", str![[r##" # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2015" name = "foo" version = "0.1.0" build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "foo" homepage = "https://example.com/" readme = false license = "MIT" [features] feat1 = [] feat2 = ["bar?/feat"] [lib] name = "foo" path = "src/lib.rs" [dependencies.bar] version = "1.0" optional = true "##]], )], ); } cargo-0.86.0/tests/testsuite/workspaces.rs000064400000000000000000002046421046102023000167440ustar 00000000000000//! Tests for workspaces. use std::env; use std::fs; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::str; use cargo_test_support::{basic_lib_manifest, basic_manifest, git, project, sleep_ms}; #[cargo_test] fn simple_explicit() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = ".." "#, ) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); assert!(!p.bin("bar").is_file()); p.cargo("build").cwd("bar").run(); assert!(p.bin("foo").is_file()); assert!(p.bin("bar").is_file()); assert!(p.root().join("Cargo.lock").is_file()); assert!(!p.root().join("bar/Cargo.lock").is_file()); } #[cargo_test] fn simple_explicit_default_members() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["bar"] default-members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = ".." "#, ) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("build").run(); assert!(p.bin("bar").is_file()); assert!(!p.bin("foo").is_file()); } #[cargo_test] fn non_virtual_default_members_build_other_member() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = [".", "bar", "baz"] default-members = ["baz"] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] baz v0.1.0 ([ROOT]/foo/baz) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check --manifest-path bar/Cargo.toml") .with_stderr_data(str![[r#" [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn non_virtual_default_members_build_root_project() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["bar"] default-members = ["."] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .build(); p.cargo("check") .with_stderr_data(str![[r#" [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn inferred_root() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); assert!(!p.bin("bar").is_file()); p.cargo("build").cwd("bar").run(); assert!(p.bin("foo").is_file()); assert!(p.bin("bar").is_file()); assert!(p.root().join("Cargo.lock").is_file()); assert!(!p.root().join("bar/Cargo.lock").is_file()); } #[cargo_test] fn inferred_path_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = { path = "bar" } [workspace] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/main.rs", "fn main() {}") .file("bar/src/lib.rs", ""); let p = p.build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); assert!(!p.bin("bar").is_file()); p.cargo("build").cwd("bar").run(); assert!(p.bin("foo").is_file()); assert!(p.bin("bar").is_file()); assert!(p.root().join("Cargo.lock").is_file()); assert!(!p.root().join("bar/Cargo.lock").is_file()); } #[cargo_test] fn transitive_path_dep() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = { path = "bar" } [workspace] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] baz = { path = "../baz" } "#, ) .file("bar/src/main.rs", "fn main() {}") .file("bar/src/lib.rs", "") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/main.rs", "fn main() {}") .file("baz/src/lib.rs", ""); let p = p.build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); assert!(!p.bin("bar").is_file()); assert!(!p.bin("baz").is_file()); p.cargo("build").cwd("bar").run(); assert!(p.bin("foo").is_file()); assert!(p.bin("bar").is_file()); assert!(!p.bin("baz").is_file()); p.cargo("build").cwd("baz").run(); assert!(p.bin("foo").is_file()); assert!(p.bin("bar").is_file()); assert!(p.bin("baz").is_file()); assert!(p.root().join("Cargo.lock").is_file()); assert!(!p.root().join("bar/Cargo.lock").is_file()); assert!(!p.root().join("baz/Cargo.lock").is_file()); } #[cargo_test] fn parent_pointer_works() { let p = project() .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = { path = "../bar" } [workspace] "#, ) .file("foo/src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = "../foo" "#, ) .file("bar/src/main.rs", "fn main() {}") .file("bar/src/lib.rs", ""); let p = p.build(); p.cargo("build").cwd("foo").run(); p.cargo("build").cwd("bar").run(); assert!(p.root().join("foo/Cargo.lock").is_file()); assert!(!p.root().join("bar/Cargo.lock").is_file()); } #[cargo_test] fn same_names_in_workspace() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] workspace = ".." "#, ) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] two packages named `foo` in this workspace: - [ROOT]/foo/bar/Cargo.toml - [ROOT]/foo/Cargo.toml "#]]) .run(); } #[cargo_test] fn parent_doesnt_point_to_child() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check") .cwd("bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] current package believes it's in a workspace when it's not: current: [ROOT]/foo/bar/Cargo.toml workspace: [ROOT]/foo/Cargo.toml this may be fixable by ensuring that this crate is depended on by the workspace root: [ROOT]/foo/Cargo.toml Alternatively, to keep it out of the workspace, add the package to the `workspace.exclude` array, or add an empty `[workspace]` table to the package's manifest. "#]]) .run(); } #[cargo_test] fn invalid_parent_pointer() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] workspace = "foo" "#, ) .file("src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to read `[ROOT]/foo/foo/Cargo.toml` Caused by: [NOT_FOUND] "#]]) .run(); } #[cargo_test] fn invalid_members() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["foo"] "#, ) .file("src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to load manifest for workspace member `[ROOT]/foo/foo` referenced by workspace at `[ROOT]/foo/Cargo.toml` Caused by: failed to read `[ROOT]/foo/foo/Cargo.toml` Caused by: [NOT_FOUND] "#]]) .run(); } #[cargo_test] fn bare_workspace_ok() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] "#, ) .file("src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check").run(); } #[cargo_test] fn two_roots() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [workspace] members = [".."] "#, ) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] multiple workspace roots found in the same workspace: [ROOT]/foo/bar [ROOT]/foo "#]]) .run(); } #[cargo_test] fn workspace_isnt_root() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] workspace = "bar" "#, ) .file("src/main.rs", "fn main() {}") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] root of a workspace inferred but wasn't a root: [ROOT]/foo/bar/Cargo.toml "#]]) .run(); } #[cargo_test] fn dangling_member() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = "../baz" "#, ) .file("bar/src/main.rs", "fn main() {}") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.0" edition = "2015" authors = [] workspace = "../baz" "#, ) .file("baz/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package `[ROOT]/foo/bar/Cargo.toml` is a member of the wrong workspace expected: [ROOT]/foo/Cargo.toml actual: [ROOT]/foo/baz/Cargo.toml "#]]) .run(); } #[cargo_test] fn cycle() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] workspace = "bar" "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = ".." "#, ) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] root of a workspace inferred but wasn't a root: [ROOT]/foo/bar/Cargo.toml "#]]) .run(); } #[cargo_test] fn share_dependencies() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] dep1 = "0.1" [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] dep1 = "< 0.1.5" "#, ) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); Package::new("dep1", "0.1.3").publish(); Package::new("dep1", "0.1.8").publish(); p.cargo("check") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [ADDING] dep1 v0.1.3 (available: v0.1.8) [DOWNLOADING] crates ... [DOWNLOADED] dep1 v0.1.3 (registry `dummy-registry`) [CHECKING] dep1 v0.1.3 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn fetch_fetches_all() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] dep1 = "*" "#, ) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); Package::new("dep1", "0.1.3").publish(); p.cargo("fetch") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 1 package to latest compatible version [DOWNLOADING] crates ... [DOWNLOADED] dep1 v0.1.3 (registry `dummy-registry`) "#]]) .run(); } #[cargo_test] fn lock_works_for_everyone() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] dep2 = "0.1" [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [dependencies] dep1 = "0.1" "#, ) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); Package::new("dep1", "0.1.0").publish(); Package::new("dep2", "0.1.0").publish(); p.cargo("generate-lockfile") .with_stderr_data(str![[r#" [UPDATING] `dummy-registry` index [LOCKING] 2 packages to latest compatible versions "#]]) .run(); Package::new("dep1", "0.1.1").publish(); Package::new("dep2", "0.1.1").publish(); p.cargo("check") .with_stderr_data(str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] dep2 v0.1.0 (registry `dummy-registry`) [CHECKING] dep2 v0.1.0 [CHECKING] foo v0.1.0 ([ROOT]/foo) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("check") .cwd("bar") .with_stderr_data(str![[r#" [DOWNLOADING] crates ... [DOWNLOADED] dep1 v0.1.0 (registry `dummy-registry`) [CHECKING] dep1 v0.1.0 [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn virtual_works() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("build").cwd("bar").run(); assert!(p.root().join("Cargo.lock").is_file()); assert!(p.bin("bar").is_file()); assert!(!p.root().join("bar/Cargo.lock").is_file()); } #[cargo_test] fn explicit_package_argument_works_with_virtual_manifest() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("build --package bar").run(); assert!(p.root().join("Cargo.lock").is_file()); assert!(p.bin("bar").is_file()); assert!(!p.root().join("bar/Cargo.lock").is_file()); } #[cargo_test] fn virtual_misconfigure() { let p = project() .file( "Cargo.toml", r#" [workspace] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check") .cwd("bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] current package believes it's in a workspace when it's not: current: [ROOT]/foo/bar/Cargo.toml workspace: [ROOT]/foo/Cargo.toml this may be fixable by adding `bar` to the `workspace.members` array of the manifest located at: [ROOT]/foo/Cargo.toml Alternatively, to keep it out of the workspace, add the package to the `workspace.exclude` array, or add an empty `[workspace]` table to the package's manifest. "#]]) .run(); } #[cargo_test] fn virtual_build_all_implied() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check").run(); } #[cargo_test] fn virtual_default_members() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] default-members = ["bar"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("bar/src/main.rs", "fn main() {}") .file("baz/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("build").run(); assert!(p.bin("bar").is_file()); assert!(!p.bin("baz").is_file()); } #[cargo_test] fn virtual_default_member_is_not_a_member() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar"] default-members = ["something-else"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package `[ROOT]/foo/something-else` is listed in default-members but is not a member for workspace at [ROOT]/foo/Cargo.toml. "#]]) .run(); } #[cargo_test] fn virtual_default_members_build_other_member() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] default-members = ["baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("check --manifest-path bar/Cargo.toml") .with_stderr_data(str![[r#" [CHECKING] bar v0.1.0 ([ROOT]/foo/bar) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn virtual_build_no_members() { let p = project().file( "Cargo.toml", r#" [workspace] "#, ); let p = p.build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] manifest path `[ROOT]/foo` contains no package: The manifest is virtual, and the workspace has no members. "#]]) .run(); } #[cargo_test] fn include_virtual() { let p = project() .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["bar"] "#, ) .file("src/main.rs", "") .file( "bar/Cargo.toml", r#" [workspace] "#, ); let p = p.build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] multiple workspace roots found in the same workspace: [ROOT]/foo/bar [ROOT]/foo "#]]) .run(); } #[cargo_test] fn members_include_path_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["p1"] [dependencies] p3 = { path = "p3" } "#, ) .file("src/lib.rs", "") .file( "p1/Cargo.toml", r#" [package] name = "p1" version = "0.1.0" edition = "2015" authors = [] [dependencies] p2 = { path = "../p2" } "#, ) .file("p1/src/lib.rs", "") .file("p2/Cargo.toml", &basic_manifest("p2", "0.1.0")) .file("p2/src/lib.rs", "") .file("p3/Cargo.toml", &basic_manifest("p3", "0.1.0")) .file("p3/src/lib.rs", ""); let p = p.build(); p.cargo("check").cwd("p1").run(); p.cargo("check").cwd("p2").run(); p.cargo("check").cwd("p3").run(); p.cargo("check").run(); assert!(p.root().join("target").is_dir()); assert!(!p.root().join("p1/target").is_dir()); assert!(!p.root().join("p2/target").is_dir()); assert!(!p.root().join("p3/target").is_dir()); } #[cargo_test] fn new_creates_members_list() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] "#, ) .file("src/lib.rs", ""); let p = p.build(); p.cargo("new --lib bar").with_stderr_data(str![[r#" [CREATING] library `bar` package [ADDING] `bar` as member of workspace at `[ROOT]/foo` [NOTE] see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html "#]]).run(); } #[cargo_test] fn new_warning_with_corrupt_ws() { let p = project().file("Cargo.toml", "asdf").build(); p.cargo("new bar").with_stderr_data(str![[r#" [CREATING] binary (application) `bar` package [ERROR] expected `.`, `=` --> Cargo.toml:1:5 | 1 | asdf | ^ | [WARNING] compiling this new package may not work due to invalid workspace configuration [NOTE] see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html "#]]).run(); } #[cargo_test] fn lock_doesnt_change_depending_on_crate() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ['baz'] [dependencies] foo = "*" "#, ) .file("src/lib.rs", "") .file( "baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = "*" "#, ) .file("baz/src/lib.rs", ""); let p = p.build(); Package::new("foo", "1.0.0").publish(); Package::new("bar", "1.0.0").publish(); p.cargo("check").run(); let lockfile = p.read_lockfile(); p.cargo("check").cwd("baz").run(); let lockfile2 = p.read_lockfile(); assert_eq!(lockfile, lockfile2); } #[cargo_test] fn rebuild_please() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ['lib', 'bin'] "#, ) .file("lib/Cargo.toml", &basic_manifest("lib", "0.1.0")) .file( "lib/src/lib.rs", r#" pub fn foo() -> u32 { 0 } "#, ) .file( "bin/Cargo.toml", r#" [package] name = "bin" version = "0.1.0" edition = "2015" [dependencies] lib = { path = "../lib" } "#, ) .file( "bin/src/main.rs", r#" extern crate lib; fn main() { assert_eq!(lib::foo(), 0); } "#, ); let p = p.build(); p.cargo("run").cwd("bin").run(); sleep_ms(1000); p.change_file("lib/src/lib.rs", "pub fn foo() -> u32 { 1 }"); p.cargo("build").cwd("lib").run(); p.cargo("run") .cwd("bin") .with_status(101) .with_stderr_data(str![[r#" ... assertion[..] ... "#]]) .run(); } #[cargo_test] fn workspace_in_git() { let git_project = git::new("dep1", |project| { project .file( "Cargo.toml", r#" [workspace] members = ["foo"] "#, ) .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/lib.rs", "") }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "lib" version = "0.1.0" edition = "2015" [dependencies.foo] git = '{}' "#, git_project.url() ), ) .file( "src/lib.rs", r#" pub fn foo() -> u32 { 0 } "#, ); let p = p.build(); p.cargo("check").run(); } #[cargo_test] fn lockfile_can_specify_nonexistent_members() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a"] "#, ) .file("a/Cargo.toml", &basic_manifest("a", "0.1.0")) .file("a/src/main.rs", "fn main() {}") .file( "Cargo.lock", r#" [[package]] name = "a" version = "0.1.0" [[package]] name = "b" version = "0.1.0" "#, ); let p = p.build(); p.cargo("check").cwd("a").run(); } #[cargo_test] fn you_cannot_generate_lockfile_for_empty_workspaces() { let p = project() .file( "Cargo.toml", r#" [workspace] "#, ) .file("bar/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("update") .with_status(101) .with_stderr_data(str![[r#" [ERROR] you can't generate a lockfile for an empty workspace. "#]]) .run(); } #[cargo_test] fn workspace_with_transitive_dev_deps() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.5.0" edition = "2015" authors = ["mbrubeck@example.com"] [dependencies.bar] path = "bar" [workspace] "#, ) .file("src/main.rs", r#"fn main() {}"#) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.5.0" edition = "2015" authors = ["mbrubeck@example.com"] [dev-dependencies.baz] path = "../baz" "#, ) .file( "bar/src/lib.rs", r#" pub fn init() {} #[cfg(test)] #[test] fn test() { extern crate baz; baz::do_stuff(); } "#, ) .file("baz/Cargo.toml", &basic_manifest("baz", "0.5.0")) .file("baz/src/lib.rs", r#"pub fn do_stuff() {}"#); let p = p.build(); p.cargo("test -p bar").run(); } #[cargo_test] fn error_if_parent_cargo_toml_is_invalid() { let p = project() .file("Cargo.toml", "Totally not a TOML file") .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check") .cwd("bar") .with_status(101) .with_stderr_data(str![[r#" [ERROR] expected `.`, `=` --> ../Cargo.toml:1:9 | 1 | Totally not a TOML file | ^ | "#]]) .run(); } #[cargo_test] fn relative_path_for_member_works() { let p = project() .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["../bar"] "#, ) .file("foo/src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = "../foo" "#, ) .file("bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check").cwd("foo").run(); p.cargo("check").cwd("bar").run(); } #[cargo_test] fn relative_path_for_root_works() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] [dependencies] subproj = { path = "./subproj" } "#, ) .file("src/main.rs", "fn main() {}") .file("subproj/Cargo.toml", &basic_manifest("subproj", "0.1.0")) .file("subproj/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check --manifest-path ./Cargo.toml").run(); p.cargo("check --manifest-path ../Cargo.toml") .cwd("subproj") .run(); } #[cargo_test] fn path_dep_outside_workspace_is_not_member() { let p = project() .no_manifest() .file( "ws/Cargo.toml", r#" [package] name = "ws" version = "0.1.0" edition = "2015" authors = [] [dependencies] foo = { path = "../foo" } [workspace] "#, ) .file("ws/src/lib.rs", "extern crate foo;") .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/lib.rs", ""); let p = p.build(); p.cargo("check").cwd("ws").run(); } #[cargo_test] fn test_in_and_out_of_workspace() { let p = project() .no_manifest() .file( "ws/Cargo.toml", r#" [package] name = "ws" version = "0.1.0" edition = "2015" authors = [] [dependencies] foo = { path = "../foo" } [workspace] members = [ "../bar" ] "#, ) .file("ws/src/lib.rs", "extern crate foo; pub fn f() { foo::f() }") .file( "foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = { path = "../bar" } "#, ) .file( "foo/src/lib.rs", "extern crate bar; pub fn f() { bar::f() }", ) .file( "bar/Cargo.toml", r#" [package] workspace = "../ws" name = "bar" version = "0.1.0" edition = "2015" authors = [] "#, ) .file("bar/src/lib.rs", "pub fn f() { }"); let p = p.build(); p.cargo("check").cwd("ws").run(); assert!(p.root().join("ws/Cargo.lock").is_file()); assert!(p.root().join("ws/target").is_dir()); assert!(!p.root().join("foo/Cargo.lock").is_file()); assert!(!p.root().join("foo/target").is_dir()); assert!(!p.root().join("bar/Cargo.lock").is_file()); assert!(!p.root().join("bar/target").is_dir()); p.cargo("check").cwd("foo").run(); assert!(p.root().join("foo/Cargo.lock").is_file()); assert!(p.root().join("foo/target").is_dir()); assert!(!p.root().join("bar/Cargo.lock").is_file()); assert!(!p.root().join("bar/target").is_dir()); } #[cargo_test] fn test_path_dependency_under_member() { let p = project() .file( "ws/Cargo.toml", r#" [package] name = "ws" version = "0.1.0" edition = "2015" authors = [] [dependencies] foo = { path = "../foo" } [workspace] "#, ) .file("ws/src/lib.rs", "extern crate foo; pub fn f() { foo::f() }") .file( "foo/Cargo.toml", r#" [package] workspace = "../ws" name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = { path = "./bar" } "#, ) .file( "foo/src/lib.rs", "extern crate bar; pub fn f() { bar::f() }", ) .file("foo/bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("foo/bar/src/lib.rs", "pub fn f() { }"); let p = p.build(); p.cargo("check").cwd("ws").run(); assert!(!p.root().join("foo/bar/Cargo.lock").is_file()); assert!(!p.root().join("foo/bar/target").is_dir()); p.cargo("check").cwd("foo/bar").run(); assert!(!p.root().join("foo/bar/Cargo.lock").is_file()); assert!(!p.root().join("foo/bar/target").is_dir()); } #[cargo_test] fn excluded_simple() { let p = project() .file( "Cargo.toml", r#" [package] name = "ws" version = "0.1.0" edition = "2015" authors = [] [workspace] exclude = ["foo"] "#, ) .file("src/lib.rs", "") .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/lib.rs", ""); let p = p.build(); p.cargo("check").run(); assert!(p.root().join("target").is_dir()); p.cargo("check").cwd("foo").run(); assert!(p.root().join("foo/target").is_dir()); } #[cargo_test] fn exclude_members_preferred() { let p = project() .file( "Cargo.toml", r#" [package] name = "ws" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["foo/bar"] exclude = ["foo"] "#, ) .file("src/lib.rs", "") .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/lib.rs", "") .file("foo/bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("foo/bar/src/lib.rs", ""); let p = p.build(); p.cargo("check").run(); assert!(p.root().join("target").is_dir()); p.cargo("check").cwd("foo").run(); assert!(p.root().join("foo/target").is_dir()); p.cargo("check").cwd("foo/bar").run(); assert!(!p.root().join("foo/bar/target").is_dir()); } #[cargo_test] fn exclude_but_also_depend() { let p = project() .file( "Cargo.toml", r#" [package] name = "ws" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = { path = "foo/bar" } [workspace] exclude = ["foo"] "#, ) .file("src/lib.rs", "") .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/lib.rs", "") .file("foo/bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("foo/bar/src/lib.rs", ""); let p = p.build(); p.cargo("check").run(); assert!(p.root().join("target").is_dir()); p.cargo("check").cwd("foo").run(); assert!(p.root().join("foo/target").is_dir()); p.cargo("check").cwd("foo/bar").run(); assert!(p.root().join("foo/bar/target").is_dir()); } #[cargo_test] fn excluded_default_members_still_must_be_members() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo"] default-members = ["foo", "bar"] exclude = ["bar"] "#, ) .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/lib.rs", "") .file("bar/something.txt", ""); let p = p.build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] package `[ROOT]/foo/bar` is listed in default-members but is not a member for workspace at [ROOT]/foo/Cargo.toml. "#]]) .run(); } #[cargo_test] fn excluded_default_members_crate_glob() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo", "bar/*"] default-members = ["bar/*"] exclude = ["bar/quux"] "#, ) .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/main.rs", "fn main() {}") .file("bar/baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("bar/baz/src/main.rs", "fn main() {}") .file("bar/quux/Cargo.toml", &basic_manifest("quux", "0.1.0")) .file("bar/quux/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("build").run(); assert!(p.root().join("target").is_dir()); assert!(!p.bin("foo").is_file()); assert!(p.bin("baz").is_file()); assert!(!p.bin("quux").exists()); p.cargo("build --workspace").run(); assert!(p.root().join("target").is_dir()); assert!(p.bin("foo").is_file()); assert!(!p.bin("quux").exists()); p.cargo("build").cwd("bar/quux").run(); assert!(p.root().join("bar/quux/target").is_dir()); } #[cargo_test] fn excluded_default_members_not_crate_glob() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo", "bar/*"] default-members = ["bar/*"] exclude = ["bar/docs"] "#, ) .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/main.rs", "fn main() {}") .file("bar/baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("bar/baz/src/main.rs", "fn main() {}") .file("bar/docs/readme.txt", "This folder is not a crate!"); let p = p.build(); p.cargo("build").run(); assert!(!p.bin("foo").is_file()); assert!(p.bin("baz").is_file()); p.cargo("build --workspace").run(); assert!(p.bin("foo").is_file()); } #[cargo_test] fn glob_syntax() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["crates/*"] exclude = ["crates/qux"] "#, ) .file("src/main.rs", "fn main() {}") .file( "crates/bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = "../.." "#, ) .file("crates/bar/src/main.rs", "fn main() {}") .file( "crates/baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.0" edition = "2015" authors = [] workspace = "../.." "#, ) .file("crates/baz/src/main.rs", "fn main() {}") .file( "crates/qux/Cargo.toml", r#" [package] name = "qux" version = "0.1.0" edition = "2015" authors = [] "#, ) .file("crates/qux/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); assert!(!p.bin("bar").is_file()); assert!(!p.bin("baz").is_file()); p.cargo("build").cwd("crates/bar").run(); assert!(p.bin("foo").is_file()); assert!(p.bin("bar").is_file()); p.cargo("build").cwd("crates/baz").run(); assert!(p.bin("foo").is_file()); assert!(p.bin("baz").is_file()); p.cargo("build").cwd("crates/qux").run(); assert!(!p.bin("qux").is_file()); assert!(p.root().join("Cargo.lock").is_file()); assert!(!p.root().join("crates/bar/Cargo.lock").is_file()); assert!(!p.root().join("crates/baz/Cargo.lock").is_file()); assert!(p.root().join("crates/qux/Cargo.lock").is_file()); } /*FIXME: This fails because of how workspace.exclude and workspace.members are working. #[cargo_test] fn glob_syntax_2() { let p = project() .file("Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["crates/b*"] exclude = ["crates/q*"] "#) .file("src/main.rs", "fn main() {}") .file("crates/bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = "../.." "#) .file("crates/bar/src/main.rs", "fn main() {}") .file("crates/baz/Cargo.toml", r#" [package] name = "baz" version = "0.1.0" edition = "2015" authors = [] workspace = "../.." "#) .file("crates/baz/src/main.rs", "fn main() {}") .file("crates/qux/Cargo.toml", r#" [package] name = "qux" version = "0.1.0" edition = "2015" authors = [] "#) .file("crates/qux/src/main.rs", "fn main() {}"); p.build(); p.cargo("build").run(); assert!(p.bin("foo").is_file()); assert!(!p.bin("bar").is_file()); assert!(!p.bin("baz").is_file()); p.cargo("build").cwd("crates/bar").run(); assert!(p.bin("foo").is_file()); assert!(p.bin("bar").is_file()); p.cargo("build").cwd("crates/baz").run(); assert!(p.bin("foo").is_file()); assert!(p.bin("baz").is_file()); p.cargo("build").cwd("crates/qux").run(); assert!(!p.bin("qux").is_file()); assert!(p.root().join("Cargo.lock").is_file()); assert!(!p.root().join("crates/bar/Cargo.lock").is_file()); assert!(!p.root().join("crates/baz/Cargo.lock").is_file()); assert!(p.root().join("crates/qux/Cargo.lock").is_file()); } */ #[cargo_test] fn glob_syntax_invalid_members() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["crates/*"] "#, ) .file("src/main.rs", "fn main() {}") .file("crates/bar/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("check") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to load manifest for workspace member `[ROOT]/foo/crates/bar` referenced by workspace at `[ROOT]/foo/Cargo.toml` Caused by: failed to read `[ROOT]/foo/crates/bar/Cargo.toml` Caused by: [NOT_FOUND] "#]]) .run(); } /// This is a freshness test for feature use with workspaces. /// /// `feat_lib` is used by `caller1` and `caller2`, but with different features enabled. /// This test ensures that alternating building `caller1`, `caller2` doesn't force /// recompile of `feat_lib`. /// /// Ideally, once we solve rust-lang/cargo#3620, then a single Cargo build at the top level /// will be enough. #[cargo_test] fn dep_used_with_separate_features() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["feat_lib", "caller1", "caller2"] "#, ) .file( "feat_lib/Cargo.toml", r#" [package] name = "feat_lib" version = "0.1.0" edition = "2015" authors = [] [features] myfeature = [] "#, ) .file("feat_lib/src/lib.rs", "") .file( "caller1/Cargo.toml", r#" [package] name = "caller1" version = "0.1.0" edition = "2015" authors = [] [dependencies] feat_lib = { path = "../feat_lib" } "#, ) .file("caller1/src/main.rs", "fn main() {}") .file("caller1/src/lib.rs", "") .file( "caller2/Cargo.toml", r#" [package] name = "caller2" version = "0.1.0" edition = "2015" authors = [] [dependencies] feat_lib = { path = "../feat_lib", features = ["myfeature"] } caller1 = { path = "../caller1" } "#, ) .file("caller2/src/main.rs", "fn main() {}") .file("caller2/src/lib.rs", ""); let p = p.build(); // Build the entire workspace. p.cargo("build --workspace") .with_stderr_data(str![[r#" [COMPILING] feat_lib v0.1.0 ([ROOT]/foo/feat_lib) [COMPILING] caller1 v0.1.0 ([ROOT]/foo/caller1) [COMPILING] caller2 v0.1.0 ([ROOT]/foo/caller2) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); assert!(p.bin("caller1").is_file()); assert!(p.bin("caller2").is_file()); // Build `caller1`. Should build the dep library. Because the features // are different than the full workspace, it rebuilds. // Ideally once we solve rust-lang/cargo#3620, then a single Cargo build at the top level // will be enough. p.cargo("build") .cwd("caller1") .with_stderr_data(str![[r#" [COMPILING] feat_lib v0.1.0 ([ROOT]/foo/feat_lib) [COMPILING] caller1 v0.1.0 ([ROOT]/foo/caller1) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); // Alternate building `caller2`/`caller1` a few times, just to make sure // features are being built separately. Should not rebuild anything. p.cargo("build") .cwd("caller2") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build") .cwd("caller1") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); p.cargo("build") .cwd("caller2") .with_stderr_data(str![[r#" [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]) .run(); } #[cargo_test] fn dont_recurse_out_of_cargo_home() { let git_project = git::new("dep", |project| { project .file("Cargo.toml", &basic_manifest("dep", "0.1.0")) .file("src/lib.rs", "") .file( "build.rs", r#" use std::env; use std::path::Path; use std::process::{self, Command}; fn main() { let cargo = env::var_os("CARGO").unwrap(); let cargo_manifest_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap(); let output = Command::new(cargo) .args(&["metadata", "--format-version", "1", "--manifest-path"]) .arg(&Path::new(&cargo_manifest_dir).join("Cargo.toml")) .output() .unwrap(); if !output.status.success() { eprintln!("{}", String::from_utf8(output.stderr).unwrap()); process::exit(1); } } "#, ) }); let p = project() .file( "Cargo.toml", &format!( r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies.dep] git = "{}" [workspace] "#, git_project.url() ), ) .file("src/lib.rs", ""); let p = p.build(); p.cargo("check") .env("CARGO_HOME", p.root().join(".cargo")) .run(); } // FIXME: this fails because of how workspace.exclude and workspace.members are working. /* #[cargo_test] fn include_and_exclude() { let p = project() .file("Cargo.toml", r#" [workspace] members = ["foo"] exclude = ["foo/bar"] "#) .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/lib.rs", "") .file("foo/bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("foo/bar/src/lib.rs", ""); p.build(); p.cargo("build").cwd("foo").run(); assert!(p.root().join("target").is_dir()); assert!(!p.root().join("foo/target").is_dir()); p.cargo("build").cwd("foo/bar").run(); assert!(p.root().join("foo/bar/target").is_dir()); } */ #[cargo_test] fn cargo_home_at_root_works() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["a"] "#, ) .file("src/lib.rs", "") .file("a/Cargo.toml", &basic_manifest("a", "0.1.0")) .file("a/src/lib.rs", ""); let p = p.build(); p.cargo("check").run(); p.cargo("check --frozen").env("CARGO_HOME", p.root()).run(); } #[cargo_test] fn relative_rustc() { let p = project() .file( "src/main.rs", r#" use std::process::Command; use std::env; fn main() { let mut cmd = Command::new("rustc"); for arg in env::args_os().skip(1) { cmd.arg(arg); } std::process::exit(cmd.status().unwrap().code().unwrap()); } "#, ) .build(); p.cargo("build").run(); let src = p .root() .join("target/debug/foo") .with_extension(env::consts::EXE_EXTENSION); Package::new("a", "0.1.0").publish(); let p = project() .at("lib") .file( "Cargo.toml", r#" [package] name = "lib" version = "0.1.0" edition = "2015" [dependencies] a = "0.1" "#, ) .file("src/lib.rs", "") .build(); fs::copy(&src, p.root().join(src.file_name().unwrap())).unwrap(); let file = format!("./foo{}", env::consts::EXE_SUFFIX); p.cargo("build").env("RUSTC", &file).run(); } #[cargo_test] fn ws_rustc_err() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a"] "#, ) .file("a/Cargo.toml", &basic_lib_manifest("a")) .file("a/src/lib.rs", "") .build(); p.cargo("rustc") .with_status(101) .with_stderr_data(str![[r#" [ERROR] manifest path `[ROOT]/foo/Cargo.toml` is a virtual manifest, but this command requires running against an actual package in this workspace "#]]) .run(); p.cargo("rustdoc") .with_status(101) .with_stderr_data(str![[r#" [ERROR] manifest path `[ROOT]/foo/Cargo.toml` is a virtual manifest, but this command requires running against an actual package in this workspace "#]]) .run(); } #[cargo_test] fn ws_err_unused() { for table in &[ "[lib]", "[[bin]]", "[[example]]", "[[test]]", "[[bench]]", "[dependencies]", "[dev-dependencies]", "[build-dependencies]", "[features]", "[target]", "[badges]", "[lints]", ] { let key = table.trim_start_matches('[').trim_end_matches(']'); let p = project() .file( "Cargo.toml", &format!( r#" [workspace] members = ["a"] {table} "#, ), ) .file("a/Cargo.toml", &basic_lib_manifest("a")) .file("a/src/lib.rs", "") .build(); p.cargo("check") .with_status(101) .with_stderr_data(&format!( "\ [ERROR] failed to parse manifest at `[..]/foo/Cargo.toml` Caused by: this virtual manifest specifies a `{key}` section, which is not allowed ", )) .run(); } } #[cargo_test] fn ws_warn_unused() { for (key, name) in &[ ("[profile.dev]\nopt-level = 1", "profiles"), ("[replace]\n\"bar:0.1.0\" = { path = \"bar\" }", "replace"), ("[patch.crates-io]\nbar = { path = \"bar\" }", "patch"), ] { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a"] "#, ) .file( "a/Cargo.toml", &format!( r#" [package] name = "a" version = "0.1.0" edition = "2015" {} "#, key ), ) .file("a/src/lib.rs", "") .build(); p.cargo("check") .with_stderr_data(&format!( "\ [WARNING] {} for the non root package will be ignored, specify {} at the workspace root: package: [ROOT]/foo/a/Cargo.toml workspace: [ROOT]/foo/Cargo.toml [CHECKING] a v0.1.0 ([ROOT]/foo/a) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s ", name, name )) .run(); } } #[cargo_test] fn ws_warn_path() { // Warnings include path to manifest. let p = project() .file( "Cargo.toml", r#" [workspace] members = ["a"] "#, ) .file( "a/Cargo.toml", r#" cargo-features = ["edition"] [package] name = "foo" version = "0.1.0" edition = "2015" "#, ) .file("a/src/lib.rs", "") .build(); p.cargo("check").with_stderr_data(str![[r#" [WARNING] [ROOT]/foo/a/Cargo.toml: the cargo feature `edition` has been stabilized in the 1.31 release and is no longer necessary to be listed in the manifest See https://doc.rust-lang.org/cargo/reference/manifest.html#the-edition-field for more information about using this feature. [CHECKING] foo v0.1.0 ([ROOT]/foo/a) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]]).run(); } #[cargo_test] fn invalid_missing() { // Make sure errors are not suppressed with -q. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [dependencies] x = { path = 'x' } "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -q") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to get `x` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` Caused by: failed to load source for dependency `x` Caused by: Unable to update [ROOT]/foo/x Caused by: failed to read `[ROOT]/foo/x/Cargo.toml` Caused by: [NOT_FOUND] "#]]) .run(); } #[cargo_test] fn member_dep_missing() { // Make sure errors are not suppressed with -q. let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" [workspace] members = ["bar"] "#, ) .file("src/main.rs", "fn main() {}") .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" [dependencies] baz = { path = "baz" } "#, ) .file("bar/src/main.rs", "fn main() {}") .build(); p.cargo("check -q") .with_status(101) .with_stderr_data(str![[r#" [ERROR] failed to load manifest for workspace member `[ROOT]/foo/bar` referenced by workspace at `[ROOT]/foo/Cargo.toml` Caused by: failed to load manifest for dependency `baz` Caused by: failed to read `[ROOT]/foo/bar/baz/Cargo.toml` Caused by: [NOT_FOUND] "#]]) .run(); } #[cargo_test] fn simple_primary_package_env_var() { let is_primary_package = r#" #[test] fn verify_primary_package() {{ assert!(option_env!("CARGO_PRIMARY_PACKAGE").is_some()); }} "#; let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [workspace] members = ["bar"] "#, ) .file("src/lib.rs", is_primary_package) .file( "bar/Cargo.toml", r#" [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] workspace = ".." "#, ) .file("bar/src/lib.rs", is_primary_package); let p = p.build(); p.cargo("test").run(); // Again, this time selecting a specific crate p.cargo("clean").run(); p.cargo("test -p bar").run(); // Again, this time selecting all crates p.cargo("clean").run(); p.cargo("test --all").run(); } #[cargo_test] fn virtual_primary_package_env_var() { let is_primary_package = r#" #[test] fn verify_primary_package() {{ assert!(option_env!("CARGO_PRIMARY_PACKAGE").is_some()); }} "#; let p = project() .file( "Cargo.toml", r#" [workspace] members = ["foo", "bar"] "#, ) .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) .file("foo/src/lib.rs", is_primary_package) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", is_primary_package); let p = p.build(); p.cargo("test").run(); // Again, this time selecting a specific crate p.cargo("clean").run(); p.cargo("test -p foo").run(); } #[cargo_test] fn ensure_correct_workspace_when_nested() { let p = project() .file( "Cargo.toml", r#" [workspace] [package] name = "bar" version = "0.1.0" edition = "2015" authors = [] "#, ) .file("src/lib.rs", "") .file( "sub/Cargo.toml", r#" [workspace] members = ["foo"] "#, ) .file( "sub/foo/Cargo.toml", r#" [package] name = "foo" version = "0.1.0" edition = "2015" authors = [] [dependencies] bar = { path = "../.."} "#, ) .file("sub/foo/src/main.rs", "fn main() {}"); let p = p.build(); p.cargo("tree") .cwd("sub/foo") .with_stdout_data(str![[r#" foo v0.1.0 ([ROOT]/foo/sub/foo) └── bar v0.1.0 ([ROOT]/foo) "#]]) .run(); } cargo-0.86.0/tests/testsuite/yank.rs000064400000000000000000000120111046102023000155100ustar 00000000000000//! Tests for the `cargo yank` command. use std::fs; use cargo_test_support::prelude::*; use cargo_test_support::project; use cargo_test_support::registry; use cargo_test_support::str; fn setup(name: &str, version: &str) { let dir = registry::api_path().join(format!("api/v1/crates/{}/{}", name, version)); dir.mkdir_p(); fs::write(dir.join("yank"), r#"{"ok": true}"#).unwrap(); } #[cargo_test] fn explicit_version() { let registry = registry::init(); setup("foo", "0.0.1"); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("yank --version 0.0.1") .replace_crates_io(registry.index_url()) .run(); p.cargo("yank --undo --version 0.0.1") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index Unyank foo@0.0.1 [ERROR] failed to undo a yank from the registry at [ROOTURL]/api Caused by: EOF while parsing a value at line 1 column 0 "#]]) .run(); } #[cargo_test] fn explicit_version_with_asymmetric() { let registry = registry::RegistryBuilder::new() .http_api() .token(cargo_test_support::registry::Token::rfc_key()) .build(); setup("foo", "0.0.1"); let p = project() .file( "Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); // The http_api server will check that the authorization is correct. // If the authorization was not sent then we would get an unauthorized error. p.cargo("yank --version 0.0.1") .arg("-Zasymmetric-token") .masquerade_as_nightly_cargo(&["asymmetric-token"]) .replace_crates_io(registry.index_url()) .run(); p.cargo("yank --undo --version 0.0.1") .arg("-Zasymmetric-token") .masquerade_as_nightly_cargo(&["asymmetric-token"]) .replace_crates_io(registry.index_url()) .run(); } #[cargo_test] fn inline_version() { let registry = registry::init(); setup("foo", "0.0.1"); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("yank foo@0.0.1") .replace_crates_io(registry.index_url()) .run(); p.cargo("yank --undo foo@0.0.1") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr_data(str![[r#" [UPDATING] crates.io index Unyank foo@0.0.1 [ERROR] failed to undo a yank from the registry at [ROOTURL]/api Caused by: EOF while parsing a value at line 1 column 0 "#]]) .run(); } #[cargo_test] fn version_required() { setup("foo", "0.0.1"); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("yank foo") .with_status(101) .with_stderr_data(str![[r#" [ERROR] `--version` is required "#]]) .run(); } #[cargo_test] fn inline_version_without_name() { setup("foo", "0.0.1"); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("yank @0.0.1") .with_status(101) .with_stderr_data(str![[r#" [ERROR] missing crate name for `@0.0.1` "#]]) .run(); } #[cargo_test] fn inline_and_explicit_version() { setup("foo", "0.0.1"); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] license = "MIT" description = "foo" "#, ) .file("src/main.rs", "fn main() {}") .build(); p.cargo("yank foo@0.0.1 --version 0.0.1") .with_status(101) .with_stderr_data(str![[r#" [ERROR] cannot specify both `@0.0.1` and `--version` "#]]) .run(); } cargo-0.86.0/triagebot.toml000064400000000000000000000232021046102023000136660ustar 00000000000000[relabel] allow-unauthenticated = [ "A-*", "C-*", "Command-*", "E-*", "I-*", "O-*", "S-*", "Z-*", "beta-nominated", "regression-*", "relnotes", ] [ping.windows] message = """\ Hey Windows Group! This bug has been identified as a good "Windows candidate". In case it's useful, here are some [instructions] for tackling these sorts of bugs. Maybe take a look? Thanks! <3 [instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/windows.html """ label = "O-windows" [shortcut] [transfer] [merge-conflicts] remove = [] add = ["S-waiting-on-author"] unless = ["S-blocked", "S-waiting-on-review"] [autolabel."S-waiting-on-review"] new_pr = true [assign] contributing_url = "https://rust-lang.github.io/cargo/contrib/" warn_non_default_branch = true [assign.owners] "*" = ["@ehuss", "@epage", "@weihanglo"] [review-submitted] reviewed_label = "S-waiting-on-author" review_labels = ["S-waiting-on-review"] [review-requested] remove_labels = ["S-waiting-on-author"] add_labels = ["S-waiting-on-review"] [autolabel."A-build-execution"] trigger_files = [ "src/cargo/core/compiler/compilation.rs", "src/cargo/core/compiler/job_queue/", "src/cargo/core/compiler/mod.rs", ] [autolabel."A-build-scripts"] trigger_files = [ "crates/build-rs-test-lib/", "crates/build-rs/", "src/cargo/core/compiler/custom_build.rs", ] [autolabel."A-cache-messages"] trigger_files = ["src/cargo/util/rustc.rs"] [autolabel."A-cargo-targets"] trigger_files = [ "src/cargo/ops/cargo_compile/compile_filter.rs", "src/cargo/ops/cargo_compile/unit_generator.rs", ] [autolabel."A-cfg-expr"] trigger_files = [ "crates/cargo-platform/", "src/cargo/core/compiler/build_context/target_info.rs", ] [autolabel."A-cli"] trigger_files = ["src/bin/", "src/cargo/util/command_prelude.rs"] [autolabel."A-cli-help"] trigger_files = ["crates/mdman/", "src/etc/man/"] [autolabel."A-completions"] trigger_files = ["src/etc/_cargo", "src/etc/cargo.bashcomp.sh"] [autolabel."A-configuration"] trigger_files = ["src/cargo/util/context/mod.rs"] [autolabel."A-console-output"] trigger_files = [ "src/cargo/core/shell.rs", "src/cargo/util/machine_message.rs", "src/cargo/util/progress.rs", ] [autolabel."A-crate-dependencies"] trigger_files = ["src/cargo/core/dependency.rs"] [autolabel."A-crate-types"] trigger_files = ["src/cargo/core/compiler/crate_type.rs"] [autolabel."A-credential-provider"] trigger_files = ["credential/"] [autolabel."A-dep-info"] trigger_files = ["src/cargo/core/compiler/output_depinfo.rs"] [autolabel."A-dependency-resolution"] trigger_files = [ "benches/benchsuite/benches/resolve.rs", "crates/resolver-tests/", "src/cargo/core/resolver/", ] [autolabel."A-directory-source"] trigger_files = ["src/cargo/sources/directory.rs"] [autolabel."A-documenting-cargo-itself"] trigger_files = ["src/doc/"] [autolabel."A-environment-variables"] trigger_files = [ "crates/home/", "src/cargo/util/context/environment.rs", ] [autolabel."A-features2"] trigger_files = ["src/cargo/core/resolver/features.rs"] [autolabel."A-filesystem"] trigger_files = ["src/cargo/util/flock.rs", "src/cargo/util/important_paths.rs"] [autolabel."A-future-incompat"] trigger_files = ["src/cargo/core/compiler/future_incompat.rs"] [autolabel."A-git"] trigger_files = ["src/cargo/sources/git/", "src/cargo/ops/cargo_package/vcs.rs"] [autolabel."A-home"] trigger_files = ["crates/home/"] [autolabel."A-infrastructure"] trigger_files = [ ".cargo/", ".github/", "build.rs", "ci/", "clippy.toml", "crates/xtask-", "deny.toml", "publish.py", "triagebot.toml", ] [autolabel."A-interacts-with-crates.io"] trigger_files = ["crates/crates-io/", "src/cargo/ops/registry/"] [autolabel."A-layout"] trigger_files = [ "src/cargo/core/compiler/build_runner/compilation_files.rs", "src/cargo/core/compiler/layout.rs", ] [autolabel."A-links"] trigger_files = ["src/cargo/core/compiler/links.rs"] [autolabel."A-local-registry-source"] trigger_files = ["src/cargo/sources/registry/local.rs"] [autolabel."A-lockfile"] trigger_files = ["src/cargo/ops/lockfile.rs", "src/cargo/core/resolver/encode.rs"] [autolabel."A-lto"] trigger_files = ["src/cargo/core/compiler/lto.rs"] [autolabel."A-manifest"] trigger_files = [ "crates/cargo-util-schemas/src/manifest/", "src/cargo/core/manifest.rs", "src/cargo/util/toml/mod.rs", "src/cargo/util/toml_mut/", ] [autolabel."A-networking"] trigger_files = ["src/cargo/util/network/"] [autolabel."A-overrides"] trigger_files = ["src/cargo/sources/replaced.rs"] [autolabel."A-profiles"] trigger_files = ["src/cargo/core/profiles.rs"] [autolabel."A-rebuild-detection"] trigger_files = ["src/cargo/core/compiler/fingerprint/"] [autolabel."A-registries"] trigger_files = ["src/cargo/sources/registry/", "src/cargo/core/registry.rs"] [autolabel."A-registry-authentication"] trigger_files = ["src/cargo/util/auth/"] [autolabel."A-semver"] trigger_files = [ "crates/semver-check", "src/cargo/util/semver_ext.rs", ] [autolabel."A-source-replacement"] trigger_files = ["src/cargo/sources/replaced.rs"] [autolabel."A-sparse-registry"] trigger_files = ["src/cargo/sources/registry/http_remote.rs"] [autolabel."A-testing-cargo-itself"] trigger_files = [ "benches/", "crates/cargo-test-macro/", "crates/cargo-test-support/", ] [autolabel."A-timings"] trigger_files = [ "src/cargo/core/compiler/timings.js", "src/cargo/core/compiler/timings.rs", "src/cargo/util/cpu.rs", ] [autolabel."A-unstable"] trigger_files = ["src/cargo/core/features.rs"] [autolabel."A-vcs"] trigger_files = ["src/cargo/util/vcs.rs"] [autolabel."A-workspaces"] trigger_files = [ "benches/benchsuite/benches/workspace_initialization.rs", "src/cargo/core/workspace.rs", "src/cargo/util/workspace.rs" ] [autolabel."Command-add"] trigger_files = ["src/bin/cargo/commands/add.rs", "src/cargo/ops/cargo_add/"] [autolabel."Command-bench"] trigger_files = ["src/bin/cargo/commands/bench.rs"] [autolabel."Command-build"] trigger_files = ["src/bin/cargo/commands/build.rs"] [autolabel."Command-check"] trigger_files = ["src/bin/cargo/commands/check.rs"] [autolabel."Command-clean"] trigger_files = ["src/bin/cargo/commands/clean.rs", "src/cargo/ops/cargo_clean.rs"] [autolabel."Command-doc"] trigger_files = ["src/bin/cargo/commands/doc.rs", "src/cargo/ops/cargo_doc.rs"] [autolabel."Command-fetch"] trigger_files = ["src/bin/cargo/commands/fetch.rs", "src/cargo/ops/cargo_fetch.rs"] [autolabel."Command-fix"] trigger_files = [ "crates/rustfix/", "src/bin/cargo/commands/fix.rs", "src/cargo/ops/fix.rs", "src/cargo/util/diagnostic_server.rs", "src/cargo/util/lockserver.rs", ] [autolabel."Command-generate-lockfile"] trigger_files = ["src/bin/cargo/commands/generate_lockfile.rs"] [autolabel."Command-git-checkout"] trigger_files = ["src/bin/cargo/commands/git_checkout.rs"] [autolabel."Command-info"] trigger_files = ["src/bin/cargo/commands/info.rs", "src/cargo/ops/registry/info/"] [autolabel."Command-init"] trigger_files = ["src/bin/cargo/commands/init.rs"] [autolabel."Command-install"] trigger_files = ["src/bin/cargo/commands/install.rs", "src/cargo/ops/cargo_install.rs"] [autolabel."Command-locate-project"] trigger_files = ["src/bin/cargo/commands/locate_project.rs"] [autolabel."Command-login"] 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", "src/cargo/ops/registry/logout.rs"] [autolabel."Command-metadata"] trigger_files = ["src/bin/cargo/commands/metadata.rs", "src/cargo/ops/cargo_output_metadata.rs"] [autolabel."Command-new"] 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", "src/cargo/ops/registry/owner.rs"] [autolabel."Command-package"] trigger_files = ["src/bin/cargo/commands/package.rs", "src/cargo/ops/cargo_package/"] [autolabel."Command-pkgid"] 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", "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"] [autolabel."Command-remove"] trigger_files = ["src/bin/cargo/commands/remove.rs", "src/cargo/ops/cargo_remove.rs"] [autolabel."Command-report"] trigger_files = ["src/bin/cargo/commands/report.rs"] [autolabel."Command-run"] trigger_files = ["src/bin/cargo/commands/run.rs", "src/cargo/ops/cargo_run.rs"] [autolabel."Command-rustc"] trigger_files = ["src/bin/cargo/commands/rustc.rs"] [autolabel."Command-rustdoc"] trigger_files = ["src/bin/cargo/commands/rustdoc.rs"] [autolabel."Command-search"] 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"] [autolabel."Command-tree"] trigger_files = ["src/bin/cargo/commands/tree.rs", "src/cargo/ops/tree/"] [autolabel."Command-uninstall"] trigger_files = ["src/bin/cargo/commands/uninstall.rs", "src/cargo/ops/cargo_uninstall.rs"] [autolabel."Command-update"] trigger_files = ["src/bin/cargo/commands/update.rs", "src/cargo/ops/cargo_update.rs"] [autolabel."Command-vendor"] trigger_files = ["src/bin/cargo/commands/vendor.rs", "src/cargo/ops/vendor.rs"] [autolabel."Command-verify-project"] trigger_files = ["src/bin/cargo/commands/verify_project.rs"] [autolabel."Command-version"] trigger_files = ["src/bin/cargo/commands/version.rs"] [autolabel."Command-yank"] trigger_files = ["src/bin/cargo/commands/yank.rs", "src/cargo/ops/registry/yank.rs"] cargo-0.86.0/windows.manifest.xml000064400000000000000000000026111046102023000150330ustar 00000000000000 UTF-8 true